EDORAS FRAMEWORK

edoras framework Reference Documentation

1.3.0

Legal Notice


            Brunnhofweg 41
            CH-3007 Bern
            Phone: 
            Phone: 
            Fax: 
        

Copyright © 2009 by mimacom ag. This copyrighted material is made available to anyone wishing to use, modify, copy, or redistribute it subject to the terms and conditions of the Mozilla Public License Version 1.1.


Preface
1. Architecture
1.1. Core modules
1.2. Modules
1.3. Portlet modules
1.4. Configuration
1.4.1. Startup of the spring context
2. edoras framework - Core
2.1. Overview
2.2. Configuration
2.2.1. Spring beans in edsCore
2.3. Usage
2.3.1. Entity handling
2.3.1.1. Validation
2.3.1.2. Creation/Modification
2.3.1.3. Display Pattern
2.3.1.4. Sort order
2.4. Logging
2.4.1. Development logging
2.4.1.1. Log4j
2.4.1.2. Java logging
2.5. Dynamically adding beans to other beans
3. edoras framework - Descriptions
3.1. Overview
3.2. Descriptions
3.2.1. MutableDescription
3.2.2. Configuration
3.3. Description Provider
3.4. Decription Resolver
3.4.1. ListDescriptionResolver
3.4.2. EnumDescriptionResolver
3.4.3. EnumDescriptionResolver
3.4.4. PersistenceUnitDescriptionResolver
3.4.5. Adding resolver to the description provider
3.5. Persistent descriptions
3.6. Annotations
3.6.1. @Descriptions
3.6.2. @DescriptionType
3.7. GUI
3.7.1. Tags
3.7.1.1. Description provider admin view
3.7.2. Functions
4. edoras framework - Custom Scopes
4.1. Overview
4.2. Scopes
4.3. Configuration
5. edoras framework - ExtFaces
5.1. Overview
5.2. Dependencies
5.3. ExtFacesContext
5.4. Expression Language Additions
5.4.1. i18n
5.5. UIComponent Tags
5.5.1. The ext:inputFile tag
5.5.2. The ext:inputRichText tag
5.6. Facelet Composite Component Tags
5.6.1. The ext:iceInfoDataPaginator tag
5.6.2. The ext:iceNavDataPaginator tag
5.7. Converter Tags
5.7.1. The ext:convertPhoneNumber tag
5.7.2. The ext:convertYesNo tag
5.8. Validator Tags
5.8.1. The ext:validateEmailAddress tag
5.9. File Upload
6. edoras framework - PortletFaces
6.1. PortletFaces Overview
6.2. PortletFaces Dependencies
6.3. Overview of Portlet 1.0 and 2.0
6.3.1. Portlet Lifecycle
6.3.2. Portlet Modes
6.3.3. Portlet Window States
6.3.4. Portlet Preferences
6.3.5. Inter Portlet Communication
6.4. JSF Portlet Development
6.4.1. JSF Portlet Bridges
6.4.2. JSF Portlet View Handlers
6.4.2.1. Faclets 1.x FaceletPortletViewHandler
6.4.3. PortletPreferences and JSF
6.4.4. JSF ExternalContext and the Portlet API
6.4.5. JSF and Portlet Preferences
6.4.6. JSF and Inter-Portlet Communication
6.5. ICEfaces Portlet Development
6.5.1. ICEfaces Ajax with Partial Submit
6.5.2. ICEfaces Direct-To-DOM RenderKit
6.5.3. The ice:portlet Tag
6.5.4. ICEfaces 1.x Portlet Bridge
6.5.5. ICEfaces 1.x D2DFaceletViewHandler
6.5.6. ICEfaces 1.x and Portlet Window States
6.5.7. ICEfaces Portlets and Concurrent DOM Views
6.5.8. ICEfaces 1.x Extended Request Scope
6.5.9. ICEfaces Ajax Push and Inter-Portlet Communication
6.5.10. ICEfaces Themes and Portal Themes
6.5.11. ICEfaces Themes and Liferay Themes
6.5.12. ICEfaces Ajax Bridge and Liferay Portal
6.5.13. ICEfaces Portlets and Liferay Request Attributes
6.6. PortletFaces Example Portlets
6.7. PortletFacesContext
6.8. PortletFaces Expression Language Additions
6.8.1. i18n
6.8.2. liferay
6.8.3. liferay.companyId
6.8.4. liferay.documentLibraryURL
6.8.5. liferay.groupUser
6.8.6. liferay.imageGalleryURL
6.8.7. liferay.imageURL
6.8.8. liferay.layout
6.8.9. liferay.permissionChecker
6.8.10. liferay.portalURL
6.8.11. liferay.portlet
6.8.12. liferay.portraitURL
6.8.13. liferay.service
6.8.14. liferay.theme
6.8.15. liferay.themeDisplay
6.8.16. liferay.themeImageURL
6.8.17. liferay.themeImagesURL
6.8.18. liferay.user
6.8.19. liferay.userHasPortletPermission
6.9. PortletFaces UIComponent Tags
6.9.1. The pf:inputFile tag
6.9.2. The pf:inputRichText tag
6.9.3. The pf:permissionsLink tag
6.10. PortletFaces Composite Component Tags
6.10.1. The pf:iceInfoDataPaginator tag
6.10.2. The pf:iceNavDataPaginator tag
6.10.3. The pf:icon tag
6.10.4. The pf:messages tag
6.10.5. The pf:message tag
6.11. PortletFaces Converter Tags
6.11.1. The pf:convertDateTime tag
6.12. PorletFaces File Upload
6.13. PortletFaces and PortletPreferences
6.14. PortletFaces Liferay Theme Integration
6.14.1. ThemeDisplay
6.14.2. Theme Icons
6.14.3. Validation Messages (User Feedback)
6.15. PortletFaces Liferay Language Portlet Integration
6.16. PortletFaces Improved Integration Between Liferay and ICEfaces 1.x
7. edoras framework - XML Persister
7.1. Overview
7.2. Configuration
7.3. Annotations
7.4. Annotation options
7.5. Samples and code snippets
7.6. Hooking into the persistency mechanism
8. edoras framework - Test
8.1. Executor
8.1.1. StartupTestServlet
8.1.1.1. Configuration
8.1.1.2. Test results
8.1.1.3. Re-Executing tests
9. edoras framework - Event
9.1. Overview
9.2. Configuration
9.3. Usage
9.3.1. Raise events
9.3.1.1. Raise events by using the API
9.3.1.2. Raise events by Annotation
9.3.2. Observe events
9.3.2.1. Observe events by listener
9.3.2.2. Observe events by annotation
10. edoras framework - Web
10.1. Overview
10.2. Configuration
10.2.1. web.xml
10.2.2. faces-config.xml
10.2.3. Spring beans in edsWeb
10.3. Usage
10.3.1. Entity handling
10.3.1.1. Converters
10.3.2. Tag libraries
11. edoras framework - ViewManager
11.1. Overview
11.2. Configuration
11.2.1. Web Configuration
11.3. Defining views
11.4. View Actions
12. edoras framework - Filestore
12.1. Overview
12.2. Configuration
12.2.1. Web Configuration
12.3. FileStoreService
12.3.1. MimeTypeResolver
12.4. FilestoreDao
12.5. FileStoreController
12.5.1. ICEfaces
12.5.1.1. InputFileSessionCleaner
12.6. DownloadServlet
12.6.1. FilestoreDownloadHandler
12.6.2. Generating links for stored files
13. edoras framework - Archetypes
13.1. Overview
13.2. Archetypes
13.2.1. Web project
13.2.2. edoras module
A. Database scripts
A.1. How to generate database scripts
B. Icefaces patches
B.1.
C. Bean Configurations
C.1.

Preface

Working with object-oriented software and persitence...

  1. Read Chapter 1, Architecture for more information.

If you have questions, use the user forum.

Commercial development support, production support, and training is available through

Chapter 1. Architecture

1.1. Core modules

The core modules provide basic functionalities like spring configuration, localization and security. Other modules that provide more concrete services are based on these core modules.

The edorasframework core modules and their dependencies (simplified)

1.2. Modules

These modules provide concrete services for certain domains. Often, they are splitted into two or three parts:

  • Core: Contains the services itself but no GUI elements for it.

  • Web: Contains web GUI components and controllers (JSF/Facelets) for the services.

  • Icefaces: Contains web GUI components and controllers (Icefaces) for the services.

The edorasframework modules and their dependencies (simplified)

1.3. Portlet modules

The portlet modules provide functionalities that are related to portlets or portlet implementations. They are generally not dependent on the edorasframework core modules, so they can be used on their own.

1.4. Configuration

Components are basically configured as spring beans. The configuration file for a module is named like the artifact id with the string "-applicationContext.xml" added (e.g. org.edorasframework.web-applicationContext.xml) and is located in the META-INF folder. The beans are named with a short prefix depending on the component module (e.g. edsCore, edsWeb, etc.). This way, a component or application can overwrite a bean definition of another component.

1.4.1. Startup of the spring context

To use the defined spring beans, a context must be started. The context searches the classpath for all files named META-INF/*-applicationContext.xml and loads them. To ensure that the files are loaded in the right order, the @Id and @DependsOn annotations can be used:

<!---
    @Id("org.edorasframework.web")
    @DependsOn("org.edorasframework.core")
-->
<beans xmlns="http://www.springframework.org/schema/beans" ...
				

The code in the example ensures that the web component is loaded after the core component and therefore the web can overwrite bean definitions of the core.

In order for this dependency resolution to work, one has to use special spring context. See the javadoc for DependencyClassPathXmlApplicationContext , DependencyXmlWebApplicationContext and DependencyContextLoader .

Chapter 2. edoras framework - Core

2.1. Overview

The edoraframework ...

2.2. Configuration

necessary...

2.2.1. Spring beans in edsCore

Name edsAppCtrl
Class org.edorasframework.core.config.ApplicationContextController
Implements/Extends
Description bootstrap bean to access other beans by name or type
Name edsMsg
Class org.edorasframework.core.locale.impl.FallbackResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The global message handler, this must implement MessageHandler and extend ResourceBundle. All strings that must be translated are processed by this bean.
Name edsCoreMsg
Class org.edorasframework.core.locale.impl.PrefixResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The core message handler, delegates to the global message handler but prefixes all keys with 'org.edorasframework.core.'
Name edsLocale
Class org.edorasframework.core.locale.impl.ProviderLocalisationController
Implements/Extends org.edorasframework.core.locale.LocalisationController
Description The global localisation controller, delegates to a bean named 'edsLocaleProvider' which must implement LocalisatorProvider.
Name edsLocaleProvider
Class org.edorasframework.core.locale.impl.DirectLocalisatorProvider
Implements/Extends org.edorasframework.core.locale.LocalisatorProvider
Description The localisator provider used by the localisation controller.
Name edsUser
Class org.edorasframework.core.security.DummyUserInfo
Implements/Extends org.edorasframework.core.security.UserInfo
Description Informations about the current User.
Name edsMetaModel
Class org.edorasframework.core.metamodel.impl.DefaultMetaModel
Implements/Extends org.edorasframework.core.metamodel.MetaModel
Description The meta model implementation.
Name edsMetaDataFinder
Class org.edorasframework.core.metamodel.MetaDataFinder
Implements/Extends
Description This allows to provide additional meta informations about classes and their properties.
Name edsDialogHandler
Class org.edorasframework.core.locale.impl.LogDialogHandler
Implements/Extends org.edorasframework.core.locale.DialogHandler
Description The dialog handler implementation.
Name edsElEnvironment
Class org.edorasframework.core.el.impl.SimpleElEnvironment
Implements/Extends org.edorasframework.core.el.ElEnvironment
Description This provides that global access point for using EL expressions.
Name
Class org.edorasframework.core.description.impl.DescriptionScanner
Implements/Extends
Description Scans classes for Description typed fields and provides description resolvers to for them.
Name edsAddBeanPostProcessor
Class org.edorasframework.core.config.add.AddBeansPostProcessor
Implements/Extends org.edorasframework.core.config.add.AddBeansPostProcessor
Description Bean post processor for add beans that are dynamically added to their target beans.
Name edsAddBeanDescriptionResolver
Class org.edorasframework.core.description.impl.ListDescriptionResolver
Implements/Extends org.edorasframework.core.description.impl.ListDescriptionResolver
Description Default description resolver for descriptions added by the core namespace handler.
Name edsDescriptionProvider
Class org.edorasframework.core.description.impl.DefaultDescriptionProvider
Implements/Extends org.edorasframework.core.description.DescriptionProvider
Description The description provider bean.
Name edsDescriptionProviderDao
Class org.edorasframework.core.description.impl.NullDescriptionProviderDao
Implements/Extends org.edorasframework.core.description.DescriptionProviderDao
Description The description provider dao
Name edsValidator
Class org.edorasframework.core.metamodel.impl.NullValidator
Implements/Extends org.edorasframework.core.metamodel.BeanValidator
Description Validates the contents of beans.

2.3. Usage

2.3.1. Entity handling

2.3.1.1. Validation

Enities can be validated based on annotations. Currently, the validation annotations from hibernate and from JSR303 (javax.validation) are supported.

  • To use hibernate, add a bean to the spring context <bean class="org.edorasframework.core.metamodel.impl.hibernate.HibernateValidator" /> and add hibernate to the classpath.

  • To use JSR 303 validation, add a bean to the spring context <bean class="org.edorasframework.core.metamodel.impl.jsr303.Jsr303Validator" /> and add some implementation to the classpath, for example

    <dependency> 
        <groupId>com.agimatec</groupId>
            <artifactId>agimatec-validation</artifactId>
            <version>0.7.3-beta-1</version>
        </dependency>
    </programlisting>

To validate an entity, use one of these code snippets:

BeanValidator validator = ApplicationContextController.getRequiredBean(BeanValidator.class);

BeanValidator validator = metaModel.getValidator();

ExpressionFactory factory = elEnvironment.getExpressionFactory();
ELContext ctx = elEnvironment.getCurrentContext();
ELInfo info = new ELInfo(factory.createValueExpression(ctx, "#{person.name}", String.class));
Set<? extends ValidationMessage<?>> validationMessages = info.getValidationMessages(ctx, valueToValidate);

2.3.1.2. Creation/Modification

To automatically set the user and current timestamp on entity creation or modification, the @Creation and @Modification annotations can be used. Just add these annotations to a field or a getter. If the type of the annotated element is String, it will be set to the current user, if it is Date, it will be set to the current time stamp. For this to work, you have to apply the line @EntityListeners(MetaModelEntityListener.class) to the entity containing the creation/modification properties. The current user is get from the 'edsUser' bean which implements org.edorasframework.core.security.UserInfo.

2.3.1.3. Display Pattern

Display patterns define alternatives to convert an entity to a string. A display pattern consists of an EL expression that defines the conversion. Display patterns are applied to entities using the DisplayPattern and DisplayPatterns annotations. @DisplayPattern("Name: #{name}, Age: #{age}") To get the actual string from an entity using a display pattern, use this code:

metaModel.display(person, "patternName"));

2.3.1.4. Sort order

It can be defined sort orders to sort a collection of entities. A sort order is basically a list of property names and ascending flags. Sort orders are applied to entities using the PropertySortOrder, NamedSortOrder and SortOrder annotations. To do the actual sort, a comparator can be retrieved using this code:

ClassMetaData<Person> cmd = metaModel.getClassMetaData(Person.class);
Comparator<Person> comp = cmd.getSortOrderComparator(MetaModel.DEFAULT_CONTEXT);
                    

2.4. Logging

2.4.1. Development logging

To allow to use the same logging configuration during development and during maven builds on continuous integration servers edoras framework provides special log appenders / handlers.

The components listed below support the supported configuration possibilities to enable/ disable the logging.

  • Define the flag by system environment property using the property key defined in the field org.edorasframework.core.logging.DevelopmentLoggerHelper.ENABLE_SYSTEM_PROPERTY.

  • Define the flag by java system property using the property key defined in the field org.edorasframework.core.logging.DevelopmentLoggerHelper.ENABLE_SYSTEM_PROPERTY. (Overwrites if the property is already defined by environmet variable)

  • Define the flag by configuration property using the configuration key org.edorasframework.core.logging.DevelopmentLoggerHelper.ENABLE_CONF_PROPERTY. (Overwrites if the property is already defined by environmet or system variable) For logger implementation specific configuration see listing below.

2.4.1.1. Log4j

# Root logger configuration
log4j.rootLogger=INFO, devel

# The development console appender
log4j.appender.devel=org.edorasframework.core.logging.DevelopmentConsoleAppender

# define whether logging is enabled or not
log4j.appender.devel.enableLogging=true

2.4.1.2. Java logging

# the development console handler
handlers = org.edorasframework.core.logging.DevelopmentConsoleHandler

# Set the default logging level for the root logger
.level = ALL
    
# define whether logging is enabled or not
org.edorasframework.core.logging.DevelopmentConsoleHandler.enableLogging=true

2.5. Dynamically adding beans to other beans

Edorasframework provides the possibility to add beans to other beans within the application context configuration. The beans are added before the @javax.annotation.PostConstruct annotatied methods are invoked. Using the add bean solution there is no need to completly redefine a bean wit a list property just to add on single property bean more. To add a bean to another the add tag of the edorasframework core module tag add can be used.

<!--needs namespace: xmlns:core="http://schema.edorasframework.org/org.edorasframework.core"-->

<core:add beanRef="toBeAdded" targetBeanRef="toRecieve" addMethod="addBean"/>

This configuration adds the bean toBeAdded to the bean toReceive by using the method addBean on the target bean. The addMethod attribute is not mandatory, since the component searches the method within the target bean and invokes it. This method must suite the following requirements:

  • Has to be public.

  • The name of the method has to start with 'add'.

  • May have only one attribute.

  • The attribute type needs to be assignable for the bean to be added.

Chapter 3. edoras framework - Descriptions

3.1. Overview

The description provider is part of the edoras framework core component. Descriptions are used to centralize the information and reduce redundancy within the application. Using a description on a bean allows link a simple link property with a more specific string description.

3.2. Descriptions

A description is always assigned to a description type, which is for type safety reasons a class object. The type orders the descriptions into categories to which bean custom properties can be assigned to. The key of the description has to be unique within each type. Type and key are used to identify each description uniquely. The value is the String representation of the description.

3.2.1. MutableDescription

If the description object implements the org.edorasframework.core.description.MutableDescription interface, some of the description's values may be changed at runtime. Using a persistent DAO, these changes will be available also after a restart of the application.

3.2.2. Configuration

The application context of the edorasframework core module defines the following bewn names for the description provider beans.

  • edsDescriptionProvider - The description provider bean

  • edsDescriptionProviderDao - The description provider dao bean

  • edsAddBeanDescriptionResolver - A description resolver where the dynamically added descriptions are registered (using the core:addDescription tag.)

If single descriptions are needed by configuration, the can be defined as follows:

<!--needs namespace: xmlns:core="http://schema.edorasframework.org/org.edorasframework.core"-->

<core:addDescription type="your.description.type.Class" key="1" value="Value" />

By using this tag, the description is automatically added to the description provider.

3.3. Description Provider

The description Provider is the main service component which provides all descriptions that are available for the application. By default this bean is already defined by the edorasframework core component and is not needed to be defined within the current implementation.

<bean id="edsDescriptionProvider"
   class="org.edorasframework.core.description.impl.DefaultDescriptionProvider">
   <property name="dao" ref="edsDescriptionProviderDao" />
   <property name="descriptionResolvers">
      <set>
         <!-- description resolvers go here -->
      </set>
   </property>
</bean>

3.4. Decription Resolver

The description resolver is used to resolve descriptions and provide them to the description provider dunring its initialisation. By default the following description resolver exist.

3.4.1. ListDescriptionResolver

The org.edorasframework.core.description.impl.ListDescriptionResolver allows to define descriptions within the application context. The constructor argument of this resolver takes a list of description beans.

<bean class="org.edorasframework.core.description.impl.ListDescriptionResolver">
   <constructor-arg>
      <set>
         <!-- Description beans here -->
      </set>
   </constructor-arg>
</bean>

3.4.2. EnumDescriptionResolver

If descriptions are implemented as enumeration, the org.edorasframework.core.description.impl.EnumDescriptionResolver may be used to provide these descriptions to the description provider. As constructor argument the class name of the enumeration description implementation has to be defined.

<bean class="org.edorasframework.core.description.impl.EnumDescriptionResolver">
   <constructor-arg>
      <set>
         <!-- Enum Description class names here -->
      </set>
   </constructor-arg>
</bean>

3.4.3. EnumDescriptionResolver

If descriptions are defined as constants, the org.edorasframework.core.description.impl.ConstantDescriptionResolver may be used to provide these descriptions to the description provider. As constructor argument the class name of the enumeration description implementation has to be defined.

<bean class="org.edorasframework.core.description.impl.ConstantDescriptionResolver">
   <constructor-arg>
      <set>
         <!-- Enum Description class names here -->
      </set>
   </constructor-arg>
</bean>

3.4.4. PersistenceUnitDescriptionResolver

The persistence unit post processor parses all classes handled by the entity manager factory and searches for the @Descriptions annotation. If such annotations are fount the resolver processes all defined description type classes and adds all descriptions automatically that are eighter defined as member variables or as enumeration of the description type class.

<bean id="entityManagerFactory" ...>
   <property name="persistenceUnitPostProcessors">
      <list>
         <ref bean="jpaDescriptionResolver" />
      </list>
   </property>
</bean>

<bean id="jpaDescriptionResolver" 
    class="org.edorasframework.core.description.impl.jpa.PersistenceUnitDescriptionResolver" />

3.4.5. Adding resolver to the description provider

To add description resolvers dynamically to the description provider the following tag can be used.

<!--needs namespace: xmlns:core="http://schema.edorasframework.org/org.edorasframework.core"-->

<core:addDescriptionResolver beanRef="resolverBeanId" />

3.5. Persistent descriptions

To use persistent descriptions the org.edorasframework.core.description.impl.jpa.JpaDescriptionProviderDao provides the needed functionality to persist the descriptions by using JPA. This dao uses the description implementation org.edorasframework.core.description.impl.jpa.JpaDescription to store the description data within a database. To define this dao add the following bean definition to your spring context:

<bean id="edsDescriptionProviderDao" 
    class="org.edorasframework.core.description.impl.jpa.JpaDescriptionProviderDao" />

3.6. Annotations

3.6.1. @Descriptions

The org.edorasframework.core.description.Descriptions annotation is used by the persistence unit description resolver. This annotation can be defined on the class or member field, to define which description types may be used by this specific class.

3.6.2. @DescriptionType

Description type classes can be annotated with the org.edorasframework.core.description.DescriptionType annotation to define a custom and user readable name for this description type.

3.7. GUI

The org.edorasframework.web module provides the following jsf tags an functions which can be used for jsf applications.

xmlns:eds="http://www.edorasframework.org/taglib/org.edorasframework.web"

3.7.1. Tags

3.7.1.1. Description provider admin view

Use the following tag to insert the view: The parameter to be used is the bean name of the descriptionController which needs to implement the interface org.edorasframework.web.description.DescriptionController.

<eds:descriptionView descriptionController="#{descriptionController}"/>

3.7.2. Functions

<!-- Returns the description for the given type and key. If no description is found <code>null</code> is returned. -->
    <function>
        <function-name>description</function-name>
        <function-class>
            org.edorasframework.web.util.ELFunctions
        </function-class>
        <function-signature>
            org.edorasframework.core.description.Description getDescription(java.lang.String, java.lang.Integer)
        </function-signature>
    </function>

    <function>
        <function-name>descriptionTypeSelectItems</function-name>
        <function-class>
            org.edorasframework.web.util.ELFunctions
        </function-class>
        <function-signature>
            java.util.List getDescriptionSelectItems(java.lang.String,java.util.ResourceBundle,boolean)
        </function-signature>
    </function>

Chapter 4. edoras framework - Custom Scopes

4.1. Overview

Anyone ever wanted to have more than just three scopes in JSF, here is a possible solution. On top of Spring custom scopes, edoras provides some implementation of additional scopes, however, to use them, Spring has to be used as the managed bean container rather than the JSF bean facility. But this is a good decision anyway.

Currently the custom scopes can only be used with ICEfaces as they are based on the ICEfaces specific extended request scope extensively. Here is an overview of the different scopes offered by this component:

4.2. Scopes

(listed from narrower to wider scopes)

  • prototype (every time such a bean is requested, it is created as a new object and is never shared)

  • request (standard request scope, lives as long as the underlying request)

  • extRequest (the same as the extended request scope in ICEfaces, lives between two GET requests, meaning, it does not persist across a refresh (like hitting F5), however it persists across multiple postbacks like Ajax requests)

  • view (the same as extRequest, but the scope is attached to the view-id, hence it persists across a refresh or even a redirect, as long as the same view is being rendered, even if the component tree was created from scratch, it is created on top of the window scope, so every tab or window running on the same session has its own state, if view scoped)

  • conversation (in development currently, the conversation scope spans across multiple views and is typically used to map a single use case)

  • window (basically the same as session, but this scope is attached to the browsers window or tab, hence multiple tabs or windows are supported, having there own state actually since this scope persists as long as the same window or tab is used)

  • session (standard session scope, persisting its state in the http-session and is shared over multiple tabs or windows in the same browser)

  • process (attached to a process instance, persists over the lifetime of a process instance, even a persisted one, this scope is provided in the org.edorasframework.process component)

  • persistentUser (in development currently, this scope is attached to the user-id and is persisted in the database, so it persists over different sessions and even server restart, can be used as an easy way to scope user-related profile beans)

  • persistent (the same as persistentUser although its state is attached to the application rather than the user in the database)

  • singleton (like application scope in the JSF bean facility)

4.3. Configuration

Assuming you already set up Spring as being the main bean managed container.

in web.xml:

<!--If you want to have multiple tabs and windows being supported,
    turn on the concurrent DOM view in ICEfaces. Otherwise the window-scope
    would be the same as the session scope.-->
<context-param>
    <param-name>com.icesoft.faces.concurrentDOMViews</param-name>
    <param-value>true</param-value>
</context-param>

<!-- The extended request scope has to be turned on by disabling
     the standard request scope in ICEfaces (this is default) -->
<context-param>
    <param-name>com.icesoft.faces.standardRequestScope</param-name>
    <param-value>false</param-value>
</context-param>

in applicationContext.xml (only needed, if you have sub views):

<!-- Registers a list of sub view ids to the view scope. -->
<bean scope="singleton" parent="edsSubViewRegisterer">
    <property name="subViewIds">
        <list>
            <value>/pages/scope/subScopes.jspx</value>
        </list>
    </property>
</bean>

Chapter 5. edoras framework - ExtFaces

5.1. Overview

The ongoing goal of the ExtFaces project is to make it easier to develop JSF web applications. The project home page can be found at http://www.edorasframework.org/web/fw/extfaces. The following is a list of high-level features:

ExtFaces was founded by Joel Kozikowski and Neil Griffin and was originally sponsored by Liferay, Inc. under incubation. Since then, ExtFaces has been adopted by Mimacom AG and is a sub-project of the edoras framework, which is a suite of JARs that compliment the following stack: JSF/ICEfaces, Spring, JPA, and Liferay Portal. The edoras framework also includes a workflow engine and graphical workflow designer for Eclipse. The project home page can be found at http://www.edorasframework.org.

5.2. Dependencies

You can obtain the ExtFaces JAR by downloading it from the project website, or if using Maven, include the following dependency in your pom.xml file.

Example 5.1. Maven pom.xml entries to include ExtFaces JAR

<dependencies>
	<dependency>
		<groupId>org.edorasframework</groupId>
		<artifactId>org.edorasframework.extfaces</artifactId>
		<version>1.3.0-SNAPSHOT</version>
	</dependency>
</dependencies>
<repositories>
	<repository>
		<id>edorasframework-releases</id>
		<name>edorasframework.org releases</name>
		<releases>
			<enabled>true</enabled>
		</releases>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
		<url>http://repo.edorasframework.org/mvn/maven2/</url>
	</repository>
	<repository>
		<id>edorasframework-snapshots</id>
		<name>edorasframework.org snapshots</name>
		<releases>
			<enabled>false</enabled>
		</releases>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
		<url>http://repo.edorasframework.org/mvn/maven2-snapshots/</url>
	</repository>
</repositories>
			

The following diagram illustrates the dependencies for the ExtFaces JAR.

ExtFaces Dependencies

Figure 5.1. ExtFaces Dependencies


5.3. ExtFacesContext

JSF web application developers typically call FacesContext.getCurrentInstance() in order to obtain the ThreadLocal singleton instance associated with the current request. While JSF portlet developers can certainly do the same, it's easier to call ExtFacesContext.getInstance() which returns an application-scoped singleton instance.

Example 5.2. Obtaining the ExtFacesContext Singleton Instance

public class SessionScopedManagedBean {
					
	private ExtFacesContext extFacesContext = ExtFacesContext.getInstance();
					
	public List<File> getDocuments() {
		List<File> documents;
		try {
			documents = DocumentService.getFiles();
		}
		catch (Exception e) {
			LOG.error(e.getMessage(), e);
			// Don't have to call ExtFacesContext.getInstance() first since
			// a reference to it was obtained when the bean was created.
			extFacesContext.addGlobalErrorMessage("An unexpected error occurred");
		}
		return documents;
	}
}


ExtFacesContext is an abstract class that extends FacesContext which means it supplies all the same method signatures and can therefore do anything that FacesContext can do. ExtFacesContext implements the delegation design pattern for methods defined by FacesContext by first calling FacesContext.getCurrentInstance() and then delegating to corresponding methods. The benefit of using this technique is that JSF web application developers only have to call ExtFacesContext.getInstance() once, and can save the singleton object reference for future use.

UML Class Diagram Showing FacesContext Class Inheritance

Figure 5.2. UML Class Diagram Showing FacesContext Class Inheritance


UML Class Diagram for org.edorasframework.extfaces.context.ExtFacesContext

Figure 5.3. UML Class Diagram for org.edorasframework.extfaces.context.ExtFacesContext


5.4. Expression Language Additions

ExtFaces introduces several variables into the Expression Language (EL).

Table 5.1. PortletFaces EL Variables

EL Variable Description
i18n As an abbreviation for the word "internationalization" the i18n EL variable enables page authors to declaratively specify message keys.

Type: String


5.4.1. i18n

As an abbreviation for the word "internationalization" the i18n EL variable enables page authors to declaratively specify message keys. Currently the MessageContextImpl class will only get values that are provided the JSF standard message keys. Developers can use Spring to inject an alternate MessageContextImpl in order to leverage additional values.

Example 5.3. Usage of the i18n EL Variable

<h:outputLabel value="#{The JSF required message is: i18n['javax.faces.component.UIInput.REQUIRED']}" />
				

5.5. UIComponent Tags

ExtFaces provides the following UIComponent tags as part of its component suite.

Table 5.2. UIComponent Tags

Tag Description
ext:inputFile Renders an HTML <input type="file" /> tag which provides file upload capability.
ext:inputRichText Renders a text area that provides the ability to enter rich text such as bold, italic, and underline.

5.5.1. The ext:inputFile tag

The ext:inputFile tag renders an HTML <input type="file" /> tag which enables file upload capability.

Note

Usage of this tag requires a faces-context-factory element to be placed in the WEB-INF/faces-config.xml file. See the File Upload section for more details.

Table 5.3. Attributes

Attribute Type Description Required
id String The identifier of the component false
rendered Boolean Boolean flag indicating whether or not this component is to be rendered during the RENDER_RESPONSE phase of the JSF lifecycle. The default value is “true”. false
value java.io.File The value of the component, which will be a file on the server. true

Example 5.4. Example usage of ext:inputFile tag

<h:form enctype="multipart/form-data">
	<ext:inputFile value="#{modelManagedBean.file}" />
</h:form>
				

5.5.2. The ext:inputRichText tag

The ext:inputRichText tag renders a text area that provides the ability to enter rich text such as bold, italic, and underline. The renderer relies on the CKEditorTM to provide the rich text editing area.

Note

At this time it is the responsibility of the web application developer to include a copy of the CKEditorTM JavaScript and related images in the web application.

Table 5.4. Attributes

Attribute Type Description Required
autoIncludeJavascript Boolean Boolean flag indicating whether or not the Javascript required by the rich text editor will be automatically included in the rendered HTML. The default value is "true". false
id String The identifier of the component false
javascriptPath String The path to the Javascript resources in the web application. The default value is "/js". false
rendered Boolean Boolean flag indicating whether or not this component is to be rendered during the RENDER_RESPONSE phase of the JSF lifecycle. The default value is “true”. false
value String The value of the component, the HTML fragment generated by the end-user. true

Example 5.5. Example usage of ext:inputRichText tag

<ext:inputRichText id="comments" value="#{modelManagedBean.comments}" />
				

5.6. Facelet Composite Component Tags

ExtFaces provides the following Facelet Composite Component tags as part of its component suite.

Table 5.5. Facelet Composite Component Tags

Tag Description
ext:iceInfoDataPaginator Encapsulates an ICEfaces ice:dataPaginator tag that renders pagination information for an associated ice:dataTable.
ext:iceNavDataPaginator Encapsulates an ICEfaces ice:dataPaginator tag that renders navigation controls for an associated ice:dataTable. The icons will match the current ICEfaces theme.

5.6.1. The ext:iceInfoDataPaginator tag

The ext:iceInfoDataPaginator encapsulates an ICEfaces ice:dataPaginator tag that renders pagination information for an associated ice:dataTable.

Table 5.6. Attributes

Attribute Type Description Required
for String Corresponds to the value of an id attribute for an ice:dataTable tag. true
value String Specifies a string that contains replacement tokens for each piece of pagination information. The default value is "Results {0}-{1} of {2} (Page {3} of {4})". The best practice would be to specify an EL expression that returns an internationalized value that contains the replacement tokens. true

Example 5.6. Example usage of ext:iceInfoDataPaginator tag

<f:view xmlns:ext="http://edorasframework.org/extfaces/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component">

	<ext:iceInfoDataPaginator for="dataTable1" />
	<ice:dataTable id="dataTable1" value="#{modelManagedBean.rows}" var="row">
		...
	</ice:dataTable>

</f:view>
				

5.6.2. The ext:iceNavDataPaginator tag

The ext:iceInfoDataPaginator encapsulates an ICEfaces ice:dataPaginator tag that renders navigation controls for an associated ice:dataTable.

Table 5.7. Attributes

Attribute Type Description Required
fastForwardIconRendered Boolean Boolean flag indicating whether or not the "Fast Forward" button/icon is rendered. The default value is "false". false
fastRewindIconRendered Boolean Boolean flag indicating whether or not the "Fast Rewind" button/icon is rendered. The default value is "false". false
firstIconRendered Boolean Boolean flag indicating whether or not the "First" button/icon is rendered. The default value is "true". false
for String Corresponds to the value of an id attribute for an ice:dataTable tag. true
lastIconRendered Boolean Boolean flag indicating whether or not the "Last" button/icon is rendered. The default value is "true". false
nextIconRendered Boolean Boolean flag indicating whether or not the "Next" button/icon is rendered. The default value is "true". false
paginator Boolean Boolean flag indicating whether or not the page number links will be rendered. This is a pass-through attribute for the encapsulated ice:dataPaginator. The default value is "true". false
paginatorMaxPages Integer The maximum amount of pages to be displayed in the paginator. This is a pass-through attribute for the encapsulated ice:dataPaginator. The default value is 7. false
previousIconRendered Boolean Boolean flag indicating whether or not the "Previous" button/icon is rendered. The default value is "true". false

Example 5.7. Example usage of ext:iceNavDataPaginator tag

<f:view xmlns:ext="http://edorasframework.org/extfaces/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component">

	<ext:iceNavDataPaginator for="dataTable1" />
	<ice:dataTable id="dataTable1" value="#{modelManagedBean.rows}" var="row">
		...
	</ice:dataTable>

</f:view>
				

5.7. Converter Tags

ExtFaces provides the following converter tags.

Table 5.8. Converter Tags

Tag Description
ext:convertPhoneNumber Converts a string of digits into a formatted phone number.
ext:convertYesNo Converts input such as "Yes" and "No" to Boolean.TRUE and Boolean.FALSE respectively.

5.7.1. The ext:convertPhoneNumber tag

The ext:convertPhoneNumber tag converts a string of digits into a formatted phone number.

Table 5.9. Attributes

Attribute Type Description Required
unitedStatesPhoneFormat String The format of the 10-digit US phone number, i.e.: ###-###-#### or (###)-###-#### or ###.###.#### false

Example 5.8. Example usage of ext:convertPhoneNumber tag

<h:inputText value="#{modelManagedBean.phoneNumber}">
	<ext:convertPhoneNumber unitedStatesPhoneFormat="###-###-####" />
</h:inputText>
				

5.7.2. The ext:convertYesNo tag

The ext:convertYesNo tag converts input such as "Yes" and "No" to Boolean.TRUE and Boolean.FALSE respectively.

Example 5.9. Example usage of ext:convertYesNo tag

<h:inputText value="#{modelManagedBean.active}">
	<ext:convertYesNo />
</h:inputText>

5.8. Validator Tags

ExtFaces provides the following validator tags.

Table 5.10. Validator Tags

Tag Description
ext:validateEmailAddress Validates an email address.

5.8.1. The ext:validateEmailAddress tag

The ext:validateEmailAddress tag validates an email address against the following regular expression: .+[@].+[.].+

Example 5.10. Example usage of ext:validateEmailAddress tag

<h:inputText value="#{modelManagedBean.emailAddress}">
	<ext:validateEmailAddress />
</h:inputText>
				

5.9. File Upload

The JSF 1.x and 2.x specifications have not implemented support for HTML forms with enctype="multipart/form-data" and are therefore do not support file uploads. Various workarounds exist for use with the JSP view-handler, such as introducing a servlet filter or phase listener to intercept the request. With the advent of the Facelets view-handler, these techniques have become largely ineffectual. The problem has to do with the FaceletViewHandler restoreView(FacesContext context, String viewId) method which is unable to retrieve the javax.faces.ViewState request parameter for HTML forms with enctype="multipart/form-data". The underlying reason why it can't retrieve the parameter is because the ExternalContextImpl.getRequestParameterMap() method in the JSF Reference Implementation is not equipped to handle these types of postback requests.

The ExtFaces project solves this problem by providing wrapper implementations of FacesContext, FacesContextFactory, and ExternalContext. These can be activated by placing the following <faces-context-factory> element inside of your portlet WAR's WEB-INF/faces-config.xml descriptor:

Example 5.11. Example usage of faces-context-factory element

<factory>
	<faces-context-factory>org.edorasframework.extfaces.mojarra.FacesContextFactoryImpl</faces-context-factory>
</factory>
					


This will ultimately cause the FacesContext.getExternalContext() method to return an instance of the org.edorasframework.portletfaces.mojarra.ExternalContextImpl class. This class overrides the ExternalContext.getRequestParameterMap() method, which uses Apache Commons FileUpload project to parse the request parameters. When used in conjunction with the ext:inputFile tag, JSF web application developers can provide file upload capability in their Facelet views.

Chapter 6. edoras framework - PortletFaces

6.1. PortletFaces Overview

The ongoing goal of the PortletFaces project is to make it easier to develop JSF portlets that run within Liferay Portal. The project home page can be found at http://www.portletfaces.org. PortletFaces contains a wealth of features that expose the standard features of the Portlet 2.0 API and vendor-specific features of Liferay in a way that is natural to JSF development. The following is a list of high level features:

PortletFaces was founded by Joel Kozikowski and Neil Griffin and was originally sponsored by Liferay, Inc. under incubation. Since then, PortletFaces has been adopted by Mimacom AG and is a sub-project of the edoras framework, which is a suite of JARs that compliment the following stack: JSF/ICEfaces, Spring, JPA, and Liferay Portal. The edoras framework also includes a workflow engine and graphical workflow designer for Eclipse. The project home page can be found at http://www.edorasframework.org.

6.2. PortletFaces Dependencies

You can obtain the PortletFaces JAR (and runtime dependencies) by downloading it from the project website, or if using Maven, include the following dependency in your pom.xml file.

Example 6.1. Maven pom.xml entries to include PortletFaces JAR

<dependencies>
	<dependency>
		<groupId>org.edorasframework</groupId>
		<artifactId>org.edorasframework.portletfaces</artifactId>
		<version>1.3.0-SNAPSHOT</version>
	</dependency>
</dependencies>
<repositories>
	<repository>
		<id>edorasframework-releases</id>
		<name>edorasframework.org releases</name>
		<releases>
			<enabled>true</enabled>
		</releases>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
		<url>http://repo.edorasframework.org/mvn/maven2/</url>
	</repository>
	<repository>
		<id>edorasframework-snapshots</id>
		<name>edorasframework.org snapshots</name>
		<releases>
			<enabled>false</enabled>
		</releases>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
		<url>http://repo.edorasframework.org/mvn/maven2-snapshots/</url>
	</repository>
</repositories>
			

The following diagram illustrates the dependencies for the PortletFaces JAR.

Note

The dependency on the MyFaces portlet-bridge-api and the Sun jsf-portlet bridge are scoped as "provided" because the only time they will truly be runtime dependencies is when the pf:inputFile tag is used. The commons-fileupload is scoped as "compile", although it too is not truly a runtime dependency unless the pf:inputFile tag is used. The commons-io dependency is a transitive runtime dependency for commons-fileupload that is not mentioned in its pom.xml file. See the File Upload section for more information.

PortletFaces Dependencies

Figure 6.1. PortletFaces Dependencies


6.3. Overview of Portlet 1.0 and 2.0

Portlets are web applications that are designed to run inside a portlet container that implements either the Portlet 1.0 or Portlet 2.0 standard. Portlet containers provide a layer of abstraction over the Java EE Servlet API, and consequently require a servlet container like Apache Tomcat to function. The reference implementation for Portlet 1.0 and 2.0 is the Apache Pluto project: http://portals.apache.org/pluto

Portals are standalone systems that use a portlet container as the runtime engine for executing portlets. When a portal is asked to deliver a portal page to the end-user’s web browser, each portlet is asked to render itself as a fragment of HTML. It is the job of the portal to aggregate these HTML fragments into a complete HTML document.

6.3.1. Portlet Lifecycle

The Portlet 1.0 standard defines two lifecycle phases for the execution of a portlet that a compliant portlet container must support: The first is the javax.portlet.PortletRequest.RENDER_PHASE, in which the portlet container asks each portlet to render itself as a fragment of HTML. The second is the javax.portlet.PortletRequest.ACTION_PHASE, in which the portlet container invokes actions related to HTML form submission. When the portal receives an HTTP GET request for a portal page, the portlet container executes the portlet lifecycle and each of the portlets on the page undergoes the RENDER_PHASE. When the portal receives an HTTP POST request, the portlet container executes the portlet lifecycle and the portlet associated with the HTML form submission will first undergo the ACTION_PHASE before the RENDER_PHASE is invoked for all of the portlets on the page.

The Portlet 2.0 standard adds two more lifecycle phases that define the execution of a portlet. The first is the javax.portlet.PortletRequest.EVENT_PHASE, in which the portlet container broadcasts events that are the result of an HTML form submission. During this phase, the portlet container asks each portlet to process events that they are interested in. The typical use case for the EVENT_PHASE is to achieve Inter-Portlet Communication (IPC), whereby two or more portlets on a portal page share data in some way. The other new phase added by the Portlet 2.0 standard is the javax.portlet.PortletRequest.RESOURCE_PHASE, in which the portlet container asks a specific portlet to perform resource-related processing. One typical use case for the RESOURCE_PHASE is for an individual portlet to process Ajax requests. Another typical use case for the RESOURCE_PHASE is for an individual portlet to generate non-HTML content (for download purposes) such as a PDF or spreadsheet document.

6.3.2. Portlet Modes

The Portlet 1.0 and 2.0 standards define three portlet modes that a compliant portlet container must support: javax.portlet.PortletMode.VIEW, javax.portlet.PortletMode.EDIT, and javax.portlet.PortletMode.HELP. Portal vendors and portlet developers may supply custom modes as well. VIEW mode refers to the rendered portlet markup that is encountered by the user under normal circumstances. Perhaps a clearer name would be normal mode or typical mode, because the word view is also used by developers to review to the view concern of the MVC design pattern. EDIT mode refers to the rendered portlet markup that is encountered by the user when selecting custom values for portlet preferences. Perhaps a clearer name would be preferences mode. Finally, HELP mode refers to the rendered portlet markup that is encountered by the user when seeking help regarding the usage and/or functionality of the portlet.

Portlet VIEW Mode

Figure 6.2. Portlet VIEW Mode


Portlet EDIT Mode

Figure 6.3. Portlet EDIT Mode


Portlet HELP Mode

Figure 6.4. Portlet HELP Mode


6.3.3. Portlet Window States

Portals typically manifest the rendered markup of a portlet in a rectangular section of the browser known as a portlet window. The Portlet 1.0 and 2.0 standards define three window states that a compliant portlet container must support: javax.portlet.WindowState.NORMAL, javax.portlet.WindowState.MAXIMIZED, and javax.portlet.WindowState.MINIMIZED. The NORMAL window state refers to the way in which the portlet container displays the rendered markup of a portlet when it can appear on the same portal page as other portlets. The MAXIMIZED window state refers to the way in which the portlet container displays the rendered markup of a portlet when it is the only portlet on a page, or when the portlet is to be rendered more prominently than other portlets on a page. Finally, the MINIMIZED window state refers to the way in which the portlet container displays a portlet when the markup is not to be rendered.

6.3.4. Portlet Preferences

Developers often have the requirement to provide the end-user with the ability to personalize the portlet behavior in some way. To meet this requirement, the Portlet 1.0 and 2.0 standards provide the ability to define preferences for each portlet. Preference names and default values can be defined in the WEB-INF/portlet.xml configuration file. Portal end-users start out interacting with the portlet user interface in portlet VIEW mode but can switch to portlet EDIT mode in order to select custom preference values.

Example 6.2. Specifying preference names and associated default values in the WEB-INF/portlet.xml configuration file

<portlet-app>
	<portlet>
		...
		<portlet-preferences>
			<preference>
				<name>datePattern</name>
				<value>MM/dd/yyyy</value>
			</preference>
			<preference>
				<name>unitedStatesPhoneFormat</name>
				<value>###-###-####</value>
			</preference>
		</portlet-preferences>
				...
	</portlet>
</portlet-app>

6.3.5. Inter Portlet Communication

Inter-portlet communication (IPC) is a technique whereby two or more portlets on a portal page share data in some way. In a typical IPC use case, user interactions with one portlet affect the rendered markup of another portlet. The Portlet 2.0 standard provides two techniques to achieve IPC: Public Render Parameters and Server-Side Events.

The Public Render Parameters technique provides a way for portlets to share data by setting public/shared parameter names in a URL controlled by the portal. While the benefit of this approach is that it is relatively easy to implement, the drawback is that only small amounts of data can be shared. Typically the kind of data that is shared is simply the value of a database primary key.

The Server-Side Events technique provides a way for portlets to share data using an event-listener design. When using this form of IPC, the portlet container acts as broker and distributes events and payload (data) to portlets. One requirement of this approach is that the payload must implement the java.io.Serializable interface since it might be sent to a portlet in another WAR running in a different classloader.

It could be argued that the Portlet 2.0 approaches for IPC have a common drawback in that they can lead to a potentially disruptive end-user experience. This is because they cause either an HTTP GET or HTTP POST which results in a full page refresh. Technologies such as ICEfaces Ajax Push can be used to solve this problem.

Illustration of IPC

Figure 6.5. Illustration of IPC


6.4. JSF Portlet Development

Strictly speaking, Portlet 1.0 and 2.0 only provide the ability for developers to write a Java class that writes HTML markup to the response that is delivered to the web browser. Although it is possible to introduce a markup-based view technology like JSP, portlet developers often choose the JSF framework in order to leverage the MVC design pattern and robust UI component features.

6.4.1. JSF Portlet Bridges

The Portlet 1.0 and JSF 1.0 specifications were formulated during roughly the same timeframe. Consequently, the JSF expert group was able to design a framework with portlet compatibility in mind. This is evidenced by methods like ExternalContext.getRequest() which returns a value of type Object, rather than a value of type javax.servlet.http.HttpServletRequest. When running inside a portlet container, the same method would return a value of type javax.portlet.PortletRequest. Although the JSF API provides a degree of portlet compatibility, it is necessary to introduce a bridge between the JSF lifecycle and the Portlet lifecycle in order to run JSF applications as portlets.

In order to use JSF in a portlet, developers must specify a JSF portlet bridge in the <portlet-class> element of the WEB-INF/portlet.xml descriptor. JSF portlet bridge implementations are either based on the JSR 301 standard, the JSR 329 standard, or were developed as innovative open source projects prior to the formulation of the standards. The JSR 301 standard defines a bridge API for Portlet 1.0 + JSF 1.2, whereas the JSR 329 standard defines a bridge API for Portlet 2.0 + JSF 1.2. The reference implementation for JSR 301 and 329 is the Apache MyFaces Portlet Bridge project.

Note

At the time of this writing, the Subversion repository for the MyFaces Portlet Bridge provides a branch with prototype support for Portlet 2.0 + JSF 2.0.

JSF portlet bridges are responsible for providing a “bridge” between the portlet lifecycle and the JSF lifecycle. For example, when a portal page that contains a JSF portlet is requested via HTTP GET, then the RENDER_PHASE of the portlet lifecycle should in turn execute the RESTORE_VIEW and RENDER_RESPONSE phases of the JSF lifecycle. Similarly, when the user submits a form contained within a JSF portlet via HTTP POST, then the ACTION_PHASE of the portlet lifecycle should execute the complete JSF lifecycle of RESTORE_VIEW, APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES, INVOKE_APPLICATION, and RENDER_RESPONSE.

Since the portal is in full control of managing URLs, JSF portlet bridges are also responsible for asking the portal to generate URLs that are compatible with actions that invoke JSF navigation rules. Consequently, JSF portlets may not perform a redirect. If a different JSF view is to be rendered as a result of a JSF navigation-rule, then the JSF portlet bridge simply displays the new JSF view in the same portlet window.

Table 6.1. JSF Portlet Bridges

Bridge Name Description
MyFaces Portlet Bridge (JSR 301 Reference Implementation)

Project Website: http://myfaces.apache.org/portlet-bridge/1.0
Portlet API: Portlet 1.0
Portlet Class:
  javax.portlet.faces.GenericFaces
Portlet JSF Compatibility: Mojarra 1.2, MyFaces 1.2
View Handler: JSP, Unofficially works with FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:)

MyFaces Portlet Bridge (JSR 329 Reference Implementation)

Project Website: http://myfaces.apache.org/portlet-bridge/2.0
Portlet API: Portlet 2.0
Portlet Class:
  javax.portlet.faces.GenericFacesPortlet
JSF Compatibility: Mojarra 1.2, MyFaces 1.2
View Handler: JSP, Unofficially works with FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:)

Sun OpenPortal JSF Portlet Bridge

Project Website: https://jsfportletbridge.dev.java.net
Portlet API: Portlet 1.0 and 2.0
Portlet Class:
  com.sun.faces.portlet.FacesPortlet
JSF Compatibility: Mojarra 1.1, 1.2
View Handler: JSP, FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:), Woodstock (retired)

ICEfaces 1.x Portlet Bridge

Project Website: http://www.icefaces.org
Portlet API: Portlet 1.0
Portlet Class:
  com.icesoft.faces.webapp.http.portlet.MainPortlet
JSF Compatibility: Mojarra 1.1, 1.2
View Handler: JSP, D2DFaceletViewHandler
Component Compatibility: Standard (f:, h:), ICEfaces (ice:)

Apache Portals-Bridges JSF Portlet Bridge

Project Website: http://portals.apache.org/bridges/multiproject/portals-bridges-jsf
Portlet API: Portlet 1.0
Portlet Class:
  org.apache.portals.bridges.jsf.FacesPortlet
JSF Compatibility: MyFaces 1.1
View Handler: JSP Only
Component Compatibility: Standard (f:, h:)

MyFacesGenericPortlet

Project Website: http://myfaces.apache.org/core11
Portlet API: Portlet 1.0
Portlet Class:
  org.apache.myfaces.portlet.MyFacesGenericPortlet
JSF Compatibility: MyFaces 1.1, 1.2
View Handler: JSP, FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:), Tomahawk (t:)

JBoss Portlet Bridge

Project Website: http://www.jboss.org/portletbridge
Portlet API: Portlet 1.0
Portlet Class:
  javax.portlet.faces.GenericFacesPortlet
JSF Compatibility: Mojarra 1.2, MyFaces 1.2
View Handler: JSP, JBoss FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:), RichFaces (rich:), Seam (s:)

JBoss Portlet Bridge

Project Website: http://www.jboss.org/portletbridge/
Portlet API: Portlet 2.0
Portlet Class:
  javax.portlet.faces.GenericFacesPortlet
JSF Compatibility: Mojarra 1.2, MyFaces 1.2
View Handler: JSP, JBoss FaceletPortletViewHandler
Component Compatibility: Standard (f:, h:), RichFaces (rich:), Seam (s:)


Example 6.3. Specifying the JSR 301 or JSR 329 JSF Portlet Bridge in the WEB-INF/portlet.xml configuration file, as well as default Facelet views that are to be rendered for VIEW mode, EDIT mode, and HELP mode

<portlet-app>
	<portlet>
		<portlet-name>my_portlet</portlet-name>
		<display-name>My Portlet</display-name>
		<portlet-class>
			javax.portlet.faces.GenericFacesPortlet
		</portlet-class>
		<init-param>
			<name>javax.portlet.faces.defaultViewId.view</name>
			<value>/xhtml/applicantForm.xhtml</value>
		</init-param>
		<init-param>
			<name>javax.portlet.faces.defaultViewId.edit</name>
			<value>/xhtml/edit.xhtml</value>
		</init-param>
		<init-param>
			<name>javax.portlet.faces.defaultViewId.help</name>
			<value>/xhtml/help.xhtml</value>
		</init-param>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>view</portlet-mode>
			<portlet-mode>edit</portlet-mode>
			<portlet-mode>help</portlet-mode>
		</supports>
		
		...
		
	</portlet>
</portlet-app>
			

Example 6.4. Specifying the Sun OpenPortal JSF Portlet Bridge in the WEB-INF/portlet.xml configuration file, as well as default JSF views that are to be rendered for VIEW mode, EDIT mode, and HELP mode

<portlet-app>
	<portlet>
		<portlet-name>my_portlet</portlet-name>
		<display-name>My Portlet</display-name>
		<portlet-class>
			com.sun.faces.portlet.FacesPortlet
		</portlet-class>
		<init-param>
			<name>com.sun.faces.portlet.INIT_VIEW</name>
			<value>/xhtml/applicantForm.xhtml</value>
		</init-param>
		<init-param>
			<name>com.sun.faces.portlet.INIT_EDIT</name>
			<value>/xhtml/edit.xhtml</value>
		</init-param>
		<init-param>
			<name>com.sun.faces.portlet.INIT_HELP</name>
			<value>/xhtml/help.xhtml</value>
		</init-param>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>view</portlet-mode>
			<portlet-mode>edit</portlet-mode>
			<portlet-mode>help</portlet-mode>
		</supports>
		
		...
		
	</portlet>
</portlet-app>
			

6.4.2. JSF Portlet View Handlers

The default view-handler for JSF 1.x is designed for JSP technology. With the advent of the Facelets view-handler, JSF developers were able to migrate away from JSP-based views to XHTML-based views and take advantage innovative features such as Composite Components and Page Templates. The Facelets project can be found at: https://facelets.dev.java.net

6.4.2.1. Faclets 1.x FaceletPortletViewHandler

Although the com.sun.facelets.FaceletViewHandler class is not compatible with JSF portlets, the Facelets project supplies the com.sun.facelets.FaceletPortletViewHandler class in the “demo/portlet” folder of its source code distribution. Although this class is not contained in the jsf-facelets.jar binary distribution, the FaceletPortletViewHandler.java file can be coped into the Java source code folder of the portlet so that the Facelets view-handler can be used instead of JSP.

Example 6.5. Specifying the portlet-compatible version of the Facelets view-handler in the WEB-INF/faces-config.xml configuration file

<faces-config>
	<application>
		<view-handler>
			com.sun.facelets.FaceletPortletViewHandler
		</view-handler>
	</application>
</faces-config>

The JSR 301 and JSR 329 standards only officially support JSP-based views with the default JSP view-handler provided by the JSF implementation. However, it is possible to use the FaceletPortletViewHandler in an unofficial manner.

Note

Facelets is the premiere view technology for JSF 2.0 and the Mojarra MultiViewHandler automatically detects if JSF views are designed for Facelets or JSP. When portlet bridges officially support JSF 2.0, there will be no more need to include the FaceletPortletViewHandler source in the Java source code folder of the portlet when using Mojarra.

6.4.3. PortletPreferences and JSF

JSF portlet developers often have the requirement to provide the end-user with the ability to personalize the portlet in some way. To meet this requirement, the Portlet 2.0 specification provides the ability to define portlet preferences for each portlet. Preference names and default values can be defined in the WEB-INF/portlet.xml descriptor. Portal end-users start out interacting with the portlet user interface in portlet VIEW mode but switch to portlet EDIT mode in order to select custom preference values.

Example 6.6. Portlet Preferences in WEB-INF/portlet.xml

<portlet-preferences>
	<preference>
		<name>unitedStatesPhoneFormat</name>
		<value>###-###-####</value>
	</preference>
	<preference>
		<name>datePattern</name>
		<value>MM/dd/yyyy</value>
	</preference>
	<preference>
		<name>recipientEmailAddress</name>
		<value>humanresources@some-company-domain.com</value>
	</preference>
</portlet-preferences>

Additionally, Portlet 2.0 provides the ability to specify support for EDIT mode in the WEB-INF/portlet.xml descriptor.

Example 6.7. Enabling Support for Portlet EDIT Mode in WEB-INF/portlet.xml

<supports>
	<mime-type>text/html</mime-type>
	<portlet-mode>view</portlet-mode>
	<portlet-mode>edit</portlet-mode>
</supports>

However, just because support portlet EDIT mode has been specified, it doesn't mean that the portlet container knows which JSF view should be rendered when the user enters portlet portlet EDIT mode. JSF portlet developers must specify the Facelet view that is to be displayed for each supported portlet mode. While JSR 301/329 defines a standard way of specifying views, non-standard bridges each have their own way.

Example 6.8. Specifying a Facelet View for EDIT mode with a JSR 301/329 JSF Portlet Bridge

<init-param>
	<name>javax.portlet.faces.defaultViewId.edit</name>
	<value>/edit.xhtml</value>
</init-param>

Example 6.9. Specifying a Facelet View for EDIT mode with the Sun OpenPortal JSF Portlet Bridge

<init-param>
	<name>com.sun.faces.portlet.INIT_EDIT</name>
	<value>/edit.xhtml</value>
</init-param>

Example 6.10. Specifying a Facelet View for EDIT mode with the ICEfaces 1.x Portlet Bridge

<init-param>
	<name>com.icesoft.faces.EDIT</name>
	<value>/edit.iface</value>
</init-param>

Facelet views that are designed to be used in portlet EDIT mode are typically forms that contain JSF component tags that enable the portlet end-user to select custom preference values that override the default values specified in the WEB-INF/portlet.xml descriptor. JSR 301/329 bridge implementations are required to provide an EL resolver that introduces the portletPreferences variable into the EL, which is a mutable java.util.Map that provides read/write access to each portlet preference. By utilizing the JSR 301/329 portletPreferences variable within an EL ValueExpression, portlet developers can declaratively bind the Facelet view to the portlet preference model data. In order to save the preferences, a backing bean must call the PortletPreferences.store() method.

Example 6.11. EDIT Mode with a JSR 301/329 Portlet Bridge

<!--
This is a file named edit.xhtml that can be used for portlet EDIT mode.
It utilizes the JSR 301/329 portletPreferences EL variable for gaining
read/write access to javax.portlet.PortletPreferences.
-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">

	<h:form>
		<h:messages globalOnly="true" />
		<h:outputLabel for="datePattern" />
		<h:inputText id="datePattern" required="true" value="#{portletPreferences['datePattern'].value}" />
		<h:message for="datePattern" />
		<h:commandButton actionListener="#{backingManagedBean.savePreferences}" value="Save Preferences" />
	</h:form>

</f:view>

/**
* This is a JSF backing managed-bean that has a savePreferences action-listener.
*/
public class BackingManagedBean {

	public void savePreferences(ActionEvent actionEvent) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.getExternalContext();
		PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
		PortletPreferences portletPreferences = portletRequest.getPreferences();
		portletPreferences.store();
	}
}

6.4.4. JSF ExternalContext and the Portlet API

Just as JSF web application developers rely on ExternalContext in order to get access to the Servlet API, JSF portlet developers also rely on ExternalContext in order to get access to the Portlet API. The two most common tasks that JSF portlet developers need to perform is to obtain an instance of the javax.portlet.PortletRequest or javax.portlet.PortletResponse objects.

Example 6.12. Getting the PortletRequest and PortletResponse objects from within a JSF backing managed-bean action method

public class BackingBean {

	public String submit() {
		FacesContext facesContext =
			FacesContext.getCurrentInstance();

		ExternalContext externalContext =
			facesContext.getExternalContext();

		PortletRequest portletRequest =
			(PortletRequest) externalContext.getRequest();

		PortletResponse portletResponse =
			(PortletResponse) externalContext.getResponse();

		return “success”;
	}
}
			

6.4.5. JSF and Portlet Preferences

Facelet views that are designed to be used in portlet EDIT mode are typically forms that enable the portlet end-user to select custom preference values that override the default values specified in the WEB-INF/portlet.xml configuration file. JSR 301/329 bridge implementations are required to provide an EL resolver that introduces the portletPreferences variable into the EL, which is a mutable java.util.Map that provides read/write access to each portlet preference. By utilizing the JSR 301/329 portletPreferences variable within an EL ValueExpression, portlet developers can declaratively bind the Facelet view to the portlet preference model data. In order to save the preferences, a backing bean must call the javax.portlet.PortletPreferences.store() method.

Example 6.13. Developing a Facelet view and associated backing managed-bean to support portlet EDIT mode with a JSR 301/329 Portlet Bridge

<!--
	This is a file named edit.xhtml that can be used
	for portlet EDIT mode. It utilizes the JSR 301/329
	portletPreferences EL variable for gaining read/write
	access to javax.portlet.PortletPreferences.
-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">
	<h:form>
		<h:messages globalOnly="true" />
		<h:outputLabel for="datePattern" />
		<h:inputText id="datePattern"
			required="true"
			value="#{portletPreferences['datePattern'].value}" />
		<h:message for="datePattern" />
		<h:commandButton
			actionListener="#{backingBean.savePreferences}"
			value="Save Preferences" />
	</h:form>
</f:view>

/**
 * This is a JSF backing managed-bean that has a
 * savePreferences action-listener.
 */
public class BackingBean {

	public void savePreferences(ActionEvent actionEvent) {

		FacesContext facesContext =
			FacesContext.getCurrentInstance();

		ExternalContext externalContext =
			facesContext.getExternalContext();

		PortletRequest portletRequest =
			(PortletRequest) externalContext.getRequest();

		PortletPreferences portletPreferences =
			portletRequest.getPreferences();

		portletPreferences.store();
	}
}

6.4.6. JSF and Inter-Portlet Communication

The only JSF portlet bridges that can technically support Portlet 2.0 style IPC are those that subclass the Portlet 2.0 version of javax.portlet.GenericPortlet class. At the time of this writing, version 1.2.3 of the Sun OpenPortal JSF Portlet Bridge supports Public Render Parameters, and Server-Side Events will be supported in a subsequent version. Also at the time of this writing, the JSR 329 standard supports both Public Render Parameters and Server-Side Events. As the JSR 329 specification is currently only at Early Draft Review 2 (EDR2) status, please refer to the following sections of the specification for the latest details on how to leverage Portlet 2.0 IPC with JSF:

  • Section 2.6.1, titled "Events"
  • Section 2.6.3, titled "Public Render Parameters"
  • Section 3.2, titled "Initializing the Bridge"
  • Section 5.2.5, titled "Executing a Portlet Event Request"
  • Section 5.3, titled "Processing Public Render Parameters"

Perhaps the most natural approach for a JSF developer to try for IPC is to specify session scope on a JSF managed-bean. Surprisingly, this approach doesn’t work. To understand the reason why, it is necessary to discuss the fact that the Portlet 1.0 and 2.0 standards make a distinction between two kinds of session scopes: javax.portlet.PortletSession.APPLICATION_SCOPE and javax.portlet.PortletSession.PORTLET_SCOPE. The former can be used for sharing data between portlets packaged in the same WAR, but the latter cannot. The reason why JSF session scope can’t be used to share data between portlets is because all JSF portlet bridges use PortletSession.PORTLET_SCOPE.

In order to share data with PortletSession.APPLICATION_SCOPE, the JSF portlet developer can place a JSF model managed-bean in request scope and use the getter/setter as a layer of abstraction.

Example 6.14. Developing a request-scoped JSF managed-bean that has a getter and setter that serves as a layer of abstraction over PortletSession.APPLICATION_SCOPE

public class ModelManagedBean {

	public static final String
		SHARED_STRING_KEY = “sharedStringKey”;

	public String getSharedString() {
		return PortletSessionUtil.getSharedSessionAttribute(
			SHARED_STRING_KEY);
	}

	public void setSharedString(String value) {
		PortletSessionUtil.setSharedSessionAttribute(
			SHARED_STRING_KEY, value);
	}
}

public class PortletSessionUtil {

	public static Object getSharedSessionAttribute(
		String key) {

		FacesContext facesContext =
			FacesContext.getCurrentInstance();

		ExternalContext externalContext =
			facesContext.getExternalContext();

		PortletSession portletSession =
			(PortletSession) externalContext().getSession(false);

		return portletSession.getAttribute(
			key, PortletSession.APPLICATION_SCOPE);
	}

	public static void setSharedSessionAttribute(
		String key, Object value) {

		FacesContext facesContext =
			FacesContext.getCurrentInstance();

		ExternalContext externalContext =
			facesContext.getExternalContext();

		PortletSession portletSession =
			(PortletSession)externalContext().getSession(false);

		portletSession.setAttribute(
			key, value, PortletSession.APPLICATION_SCOPE);
	}
}

Alternatively, if using the Spring Framework to replace or augment the JSF Managed Bean Facility, then developers can store data in PortletSession.APPLICATION_SCOPE using the globalSession scope keyword

Example 6.15. Specifying a Spring bean that is to be stored in PortletSession.APPLICATION_SCOPE by registering it in the WEB-INF/applicationContext.xml configuration file

<bean
	id="sharedManagedBean"
	class="com.sample.jsf.SharedManagedBean"
	scope="globalSession"/>
			

6.5. ICEfaces Portlet Development

ICEfaces is an open source extension to JSF that enables developers with Java EE application skills to build Ajax-powered Rich Internet Applications (RIA) without writing any JavaScript code. The product contains a robust suite of Ajax-enabled JSF UI components, and also supports a broad array of Java application servers, IDEs, third party components, and JavaScript effect libraries. The project home page can be found at http://www.icefaces.org

Because of its integrated Ajax framework, ICEfaces is a particularly good choice for developing RIA portlets. Consider a portal page that contains two portlets: Portlet A and Portlet B. When submitting a form in Portlet A, an HTTP POST takes place and the entire portal page is refreshed. This can result in a disruptive end-user experience if the user had entered data in Portlet B prior to submitting Portlet A. ICEfaces allows you to combat this disruptive experience with RIA features in your portlets.

ICEfaces can be used in a variety of portal products including Liferay Portal. Since July of 2007, Liferay, Inc. and ICEsoft Technologies, Inc. have had a technology partnership in place to support customers that want to develop and deploy ICEfaces portlets within Liferay Portal.

6.5.1. ICEfaces Ajax with Partial Submit

When a portal page is requested for the first time via HTTP GET, portlets built with ICEfaces undergo the RENDER_PHASE of the portlet lifecycle just like any other portlet. From that point on, ICEfaces circumvents normal interaction through the portlet container. When doing a form submission from an ICEfaces portlet, an HTTP POST will not be performed; instead, form submission takes place via Ajax

There are two techniques that developers can use in order to enable Ajax in a JSF view built with ICEfaces component tags:

  • Specify paritalSubmit=”true” on the ice:form tag
  • Specify partialSubmit=”true” on each ICEfaces component tag

Note that if the first technique is used, then ICEfaces component tags that are used to perform full form submissions (such as ice:commandButton) must specify partialSubmit=”false”.

Example 6.16. Enabling Ajax in a Facelet view built with ICEfaces component tags

<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.w3.org/1999/xhtml
	http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
	<ice:portlet>
		<ice:form partialSubmit="true">
			<ice:panelGrid columns=”2”>
<ice:outputLabel
for=”firstName” value=”First Name” />
<ice:inputText
	value=”#{modelManagedBean.firstName}” />
	<ice:message for=”firstName” />
	<ice:outputLabel
		for=”lastName” value=”Last Name” />
		<ice:inputText
		value=”#{modelManagedBean.lastName}” />
		<ice:message for=”lastName” />
			<ice:commandButton
			action=”#{backingManagedBean.submit}”
			partialSubmit=”false” />
			</ice:panelGrid>
		</ice:form>
	</ice:portlet>
</f:view>
			

6.5.2. ICEfaces Direct-To-DOM RenderKit

Rather than writing markup directly to the response, ICEfaces components render themselves into a server-side Document Object Model (DOM) via the ICEfaces Direct-to-DOM (D2D) RenderKit. When a JSF view is requested for the first time, the markup inside the server-side DOM is delivered to the browser as part of the response. As the user interacts with the UI of the portlet, ICEfaces transparently submits user actions via Ajax and executes the JSF lifecycle. When the RENDER_RESPONSE phase of the JSF lifecycle completes, ICEfaces will compare the previous server-side DOM with the latest server-side DOM and send the incremental page updates back to the browser via the ICEfaces Ajax Bridge. In order to improve the application experience of the end-user, ICEfaces will only permit fields that have been visited by the user to undergo validation during the PROCESS_VALIDATIONS phase of the JSF lifecycle.

This approach is sometimes referred to as “dom-diffing” and provides the following benefits for portlets:

  • The end user is immediately presented with form validation failures for visited fields when pressing the tab key
  • When a navigation-rule fires and a new JSF view is to be rendered, ICEfaces will render the new JSF view by performing a complete update of the markup contained in the affected portlet, rather than causing the entire browser page to reload
  • ICEfaces portlets will not disturb other portlets on the same portal page

6.5.3. The ice:portlet Tag

ICEfaces provides the ice:portlet component tag that developers should use to wrap the entire content of each portlet. It implements the javax.faces.component.NamingContainer interface so that it can apply the portlet namespace as the top level of the JSF ID hierarchy. Doing this makes the ID hierarchy more efficient and helps the ICEfaces framework uniquely identify components on the page, which is important when more than one ICEfaces portlet is placed on the same portal page.

6.5.4. ICEfaces 1.x Portlet Bridge

ICEfaces 1.x ships with a Portlet 1.0 compliant portlet bridge for deployment of ICEfaces portlets. Note that ICEfaces 2.x will use a Portlet 2.0 compliant bridge that will include the ability to channel the ICEfaces Ajax requests through the Portlet 2.0 RESOURCE_PHASE of the portlet lifecycle.

Example 6.17. Specifying the ICEfaces 1.x Portlet Bridge in the WEB-INF/portlet.xml configuration file, as well as default JSF views that are to be rendered for VIEW mode, EDIT mode, and HELP mode

<portlet-app>
	<portlet>
		<portlet-name>my_portlet</portlet-name>
		<display-name>My Portlet</display-name>
		<portlet-class>
			com.icesoft.faces.webapp.http.portlet.MainPortlet
		</portlet-class>
		<init-param>
			<name>com.icesoft.faces.portlet.viewPageURL</name>
			<value>/xhtml/applicantForm.xhtml</value>
		</init-param>
		<init-param>
			<name>com.icesoft.faces.portlet.editPageURL</name>
			<value>/xhtml/edit.xhtml</value>
		</init-param>
		<init-param>
			<name>com.icesoft.faces.portlet.helpPageURL</name>
			<value>/xhtml/help.xhtml</value>
		</init-param>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>view</portlet-mode>
			<portlet-mode>edit</portlet-mode>
			<portlet-mode>help</portlet-mode>
		</supports>
		
		...
		
	</portlet>
</portlet-app>
			

6.5.5. ICEfaces 1.x D2DFaceletViewHandler

In order to use Facelets with the ICEfaces 1.x Portlet Bridge, it is necessary to use the ICEfaces com.icesoft.faces.facelets.D2DFaceletViewHandler class which is designed to provide support for Facelet views and the D2D RenderKit

Example 6.18. Specifying the ICEfaces D2D view-handler in the WEB-INF/faces-config.xml configuration file

<faces-config>
	<application>
		<view-handler>
			com.icesoft.faces.facelets.D2DFaceletViewHandler
		</view-handler>
	</application>
</faces-config>
			

6.5.6. ICEfaces 1.x and Portlet Window States

Since ICEfaces 1.x portlets never perform an HTTP post, they do not participate in the ACTION_PHASE of the portlet lifecycle. It is therefore not possible for ICEfaces 1.x portlets to programmatically change the portlet window state. However, ICEfaces portlets can respond accordingly when the user clicks on links provided by the portal that control portlet window states.

6.5.7. ICEfaces Portlets and Concurrent DOM Views

ICEfaces provides a feature called Concurrent DOM Views that controls whether or not the ICEfaces framework supports multiple views of a single application from the same browser. When running in a portlet container, ICEfaces needs to treat the separate portlets on a single portal page as distinct views so it is almost always necessary (and therefore safest) to have this parameter set to true.

Example 6.19. Enabling the ICEfaces Concurrent DOM Views feature in the WEB-INF/web.xml configuration file so that separate portlets on the same portal page are treated as distinct views

<context-param>
	<param-name>
		com.icesoft.faces.concurrentDOMViews
	</param-name>
	<param-value>true</param-value>
</context-param>
			

6.5.8. ICEfaces 1.x Extended Request Scope

When developers specify a value of request for the scope a JSF managed-bean, the scope is understood to be very short-lived as it lasts for the duration of a request. When a developer specifies a value of request when using ICEfaces, then the ICEfaces Extended Request scope is applied by default. As an added benefit, the ICEfaces Extended Request scope lends itself quite well to portlets.

Note

ICEfaces 1.x Extended Request scope was one of the inspirations for a new feature in JSF 2.0 called View scope. ICEfaces 2.x applications will use the new JSF 2.0 View scope in place of ICEfaces Extended Request scope.

The ICEfaces Ajax Bridge is responsible for dispatching Ajax requests as a result of user-initiated actions and monitoring the status of each Ajax request. Developers can specify the com.icesoft.faces.connectionTimeout context parameter in the WEB-INF/web.xml configuration file to change the length of time (in milliseconds), that the ICEfaces Ajax Bridge will wait before declaring the connection lost. The default value is 60000 (60 seconds).

Example 6.20. Specifying the length of time in the WEB-INF/web.xml configuration file that the ICEfaces Ajax Bridge will wait before declaring the connection lost

<context-param>
	<param-name>
		com.icesoft.faces.connectionTimeout
	</param-name>
	<param-value>80000</param-value>
</context-param>
			

The duration of the ICEfaces Extended Request scope begins when the view is first requested, and stays active until one of the following conditions occurs:

  • The user navigates to a different JSF view
  • The user navigates to a different portal page
  • The ICEfaces connection timeout occurs
  • The PortletSession expires
  • The user terminates the web browser

To disable the ICEfaces Extended Request scope, developers can specify the com.icesoft.faces.standardRequestScope context parameter in the WEB-INF/web.xml configuration file and set it to false.

Example 6.21. Disabling ICEfaces Extended Request scope and restore standard request scope in the WEB-INF/web.xml configuration file

<context-param>
	<param-name>
		com.icesoft.faces.standardRequestScope
	</param-name>
	<param-value>true</param-value>
</context-param>
			

6.5.9. ICEfaces Ajax Push and Inter-Portlet Communication

While the Portlet 2.0 standard defines techniques for performing inter-portlet communication (IPC), they cause either an HTTP GET or HTTP POST which results in a full page reload and a disruptive end-user experience. ICEfaces provides a natural way for portlets to perform IPC via ICEfaces Ajax Push.

ICEfaces pioneered Ajax Push, which is sometimes referred to as Reverse Ajax or Comet. The technology provides the ability for server-initiated events to cause incremental page updates to be sent to the browser. With ICEfaces Ajax Push, developers can create collaborative and dynamic enterprise applications like never before.

Because the mechanism facilitates asynchronous updates from the server to the client, interaction with one ICEfaces portlet can trigger communication with other ICEfaces portlets by changing values in JSF backing and model managed-beans. This mechanism is not restricted to IPC among portlets on the same portal page in a single browser, but can include updating other browsers that are interacting with the same portal page. The result is not just inter-portlet communication, but inter-portlet, inter-browser communication. Additionally, ICEfaces Ajax Push solves the potentially disruptive end-user experience associated with the Portlet 2.0 standard IPC techniques.

Illustration of IPC with ICEfaces Ajax Push

Figure 6.6. Illustration of IPC with ICEfaces Ajax Push


The following is a list of guidelines for achieving IPC with ICEfaces Ajax Push

  • Package the portlets that need to communicate in the same WAR.
  • In order to share data between portlets, use application-scoped beans or request-scoped beans that store data in PortletSession.APPLICATION_SCOPE.
  • Use the ICEfaces Ajax Push SessionRenderer to trigger client updates when the shared data changes.

Example 6.22. Developing a JSF managed-bean in application scope that maintains a chat log that participates in ICEfaces Ajax Push using the SessionRenderer

/*
* This is a file named ChatRoomManagedBean.java
* that is registered as a JSF managed-bean in
* application scope.
*/
import com.icesoft.faces.async.render.SessionRenderer;
import java.util.ArrayList;
import java.util.List;
import javax.faces.event.ActionEvent;

public class ChatRoomManagedBean {

	private String messageText;

	private List<String> messages = new ArrayList<String>();
	
	private static final String
		AJAX_PUSH_GROUP_NAME = "chatRoom";
	
	public ChatRoomsModel() {
		SessionRenderer.addCurrentSession(
			AJAX_PUSH_GROUP_NAME);
	}
	
	public void addMessage(ActionEvent actionEvent) {
		messages.add(messageText);
		SessionRenderer.render(AJAX_PUSH_GROUP_NAME);
	}
	
	public List<String> getMessages() {
		return messages;
	}
		
	public String getMessageText() {
		return messageText;
	}
		
	public void setMessageText(String messageText) {
		this.messageText = messageText;
	}
}
		
<!-- This is a Facelet view named chatRoom.xhtml -->
<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.w3.org/1999/xhtml
	http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
	<ice:portlet>
		<ice:form>
			<ice:dataTable
				value=”#{chatRoomManagedBean.messages}”
				var=”message”>
				<ice:column>
					<ice:outputText value=”#{message}” />
				</ice:column>
			</ice:dataTable>
			<ice:inputText
				value=”#{chatRoomManagedBean.messageText}” />
			<ice:commandButton
				actionListener=”#{chatRoomManagedBean.addMessage}” />
		</ice:form>
	</ice:portlet>
</f:view>

Note

The TritonSource project contains open source demonstration portlets that focus on ICEfaces portlets for Liferay Portal. Specifically, TritonSource has a demonstration portlet featuring an ICEfaces chat room that integrates with Liferay Portal’s “Friends” Social Networking services. When friends sign-in to Liferay Portal, a server-initiated event triggers ICEfaces Ajax Push so that other friends that are online become aware of their friend’s online presence. Additionally, when the user clicks on a “Chat” icon, ICEfaces Ajax Push is used for IPC to begin a new chat room in a Chat Portlet. The TritonSource project website can be found at: http://www.tritonsource.org

6.5.10. ICEfaces Themes and Portal Themes

The ICEfaces Component Suite fully supports consistent component styling via a set of predefined CSS style classes and associated images. Changing the component styles for a web application developed with the ICEfaces Component Suite is as simple as changing the style sheet used. ICEfaces ships with a set of predefined style sheets are available to be used as-is, or customized to meet the specific requirements of the application. There are five predefined ICEfaces style sheets included, two of which are designed to be used inside a portlet container:

  • rime.css
  • rime-portlet.css
  • xp.css
  • xp-portlet.css
  • royale.css

Example 6.23. Specifying the portlet-compatible version of the ICEfaces "XP" theme

<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.w3.org/1999/xhtml
	http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
	<ice:portlet>
		<ice:outputStyle
			href="/xmlhttp/css/xp/xp-portlet.css" />
		<ice:form>
			...
		</ice:form>
	</ice:portlet>
</f:view>
			

The Portlet 1.0 and 2.0 standards document a set of common CSS class names that should be applied to specific page elements in order to integrate with the portlet container’s theme mechanism. When running in a portlet container, ICEfaces components will automatically render the following subset of Portlet 1.0 CSS class names where appropriate

  • portlet-form-button
  • portlet-form-field
  • portlet-form-input-field
  • portlet-form-label
  • portlet-menu
  • portlet-menu-cascade-item
  • portlet-menu-item
  • portlet-menu-item-hover
  • portlet-section-alternate
  • portlet-section-body
  • portlet-section-footer
  • portlet-section-header
  • portlet-msg-alert
  • portlet-msg-error
  • portlet-msg-info

To disable this feature, developers can specify the com.icesoft.faces.portlet.renderStyles context parameter in the WEB-INF/web.xml configuration file and set its value to false.

Example 6.24. Disabling automatic rendering of Portlet 1.0 / 2.0 standard CSS class names in the WEB-INF/web.xml configuration file

<context-param>
	<param-name>
		com.icesoft.faces.portlet.renderStyles
	</param-name>
	<param-value>false</param-value>
</context-param>
			

6.5.11. ICEfaces Themes and Liferay Themes

Liferay Portal supports styling for Portlet 1.0 and 2.0 standard CSS class names as well as a set of vendor-specific CSS class names within the context of a Liferay theme. However, since Liferay themes do not contain styling for the ICEfaces Component Suite, it is necessary to select an ICEfaces style sheet that is visually compatible with the Liferay theme.

On some occasions, it becomes necessary to override some of the styling in a Liferay theme in order to make it more visually compatible with an ICEfaces portlet. For example, Liferay themes typically render spans of class portlet-msg-error with a margin that has too much space to be placed alongside a rendered ice:inputText component tag.

Example 6.25. Overriding styling in a Liferay theme from within a Facelet view so that rendered output from ice:messages and ice:message have a more narrow margin

<!--
	This is a file named my-portlet-view.xhtml
-->
<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.w3.org/1999/xhtml
	http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd">
	<ice:portlet>
		<ice:outputStyle
			href="/xmlhttp/css/xp/xp-portlet.css" />
		<ice:outputStyle
			href="liferay-theme-override.css" />
		<ice:form styleClass=”my-portlet-view”>
			<ice:messages globalOnly=”true” />
			...
		</ice:form>
	</ice:portlet>
</f:view>

/*
 * This is a separate file named liferay-theme-override.css
 */
.my-portlet-view .portlet-msg-error {
	margin: 1px 0px 0px 0px;
	padding: 1px 5px 1px 24px;
}
			

6.5.12. ICEfaces Ajax Bridge and Liferay Portal

When an ICEfaces portlet is added to a portal page at runtime by the end-user, the ICEfaces Ajax Bridge’s window.onload() logic will not be executed unless there is a full page refresh.

As a workaround, Liferay Portal provides configuration parameters that allow the developer to specify that a full page refresh is required. Doing this ensures that the ICEfaces bridge is properly initiated. The required parameters, render-weight and ajaxable, are specified in the WEB-INF/liferay-portlet.xml configuration file

Example 6.26. Specifying that a full page refresh should take place after the ICEfaces portlet is first added to the portal page

<liferay-portlet-app>
	<portlet>
		<portlet-name>my_portlet</portlet-name>
		<instanceable>false</instanceable>
		<render-weight>1</render-weight>
		<ajaxable>false</ajaxable>
	</portlet>
</liferay-portlet-app>
			

6.5.13. ICEfaces Portlets and Liferay Request Attributes

In order to ensure compatibility with the Portlet 2.0 Technology Compatibility Kit (TCK), Liferay’s implementation of the javax.portlet.PortletRequest.getAttributeNames() method does not return a complete list of attribute names that are truly present in the PortletRequest object. Although certain attribute names are hidden, if they are known by the portlet developer, their respective values can be retrieved by calling Liferay’s implementation of the javax.portlet.PortletRequest.getAttribute(String name) method.

In order for the ICEfaces 1.x portlet bridge to maintain compatibility with the ICEfaces Extended Request scope, it needs to make a copy of all of the request attributes. In order to ensure that ICEfaces copies the necessary hidden attributes, developers must specify the com.icesoft.faces.portlet.hiddenAttributes context parameter in the WEB-INF/web.xml configuration file.

Example 6.27. Specifying a space-delimited list of hidden request attributes in the WEB-INF/web.xml configuration file

<context-param>
	<param-name>
		com.icesoft.faces.portlet.hiddenAttributes
	</param-name>
	<param-value>COMPANY_ID LAYOUT RENDER_PORTLET THEME_DISPLAY</param-value>
</context-param>
			

6.6. PortletFaces Example Portlets

In order to demonstrate usage of PortletFaces in a portlet, Mimacom AG has developed the following example portlets.

Table 6.2. Example Portlets

Name Description

Example Liferay Portlet using JSF 1.2 and the Sun OpenPortal JSF Portlet Bridge

This example shows how to use features of PortletFaces with standard JSF 1.2 component tags. It utilizes the Sun OpenPortal JSF Portlet Bridge in order to run as a portlet within Liferay.

Subversion repository URL: http://repo.edorasframework.org/svn/examples/trunk/org.edorasframework.example.portlet.liferay.jsf.1.2/

Example Liferay Portlet using ICEfaces 1.x and the ICEfaces 1.x Portlet Bridge

This example shows how to use features of PortletFaces with ICEfaces 1.x component tags. It utilizes the ICEfaces 1.x Portlet Bridge in order to run as a portlet within Liferay. ICEfaces partialSubmit is enabled so that form validation failures are reported back to the user without having to submit the form. Additionally, the ICEfaces ice:inputFile tag is used in conjunction with an ice:outputProgress tag to support file uploads with a progress indicator.

Subversion repository URL: http://repo.edorasframework.org/svn/examples/trunk/org.edorasframework.example.portlet.liferay.icefaces.1.x/


6.7. PortletFacesContext

JSF web application developers typically call FacesContext.getCurrentInstance() in order to obtain the ThreadLocal singleton instance associated with the current request. While JSF portlet developers can certainly do the same, it's easier to call PortletFacesContext.getInstance() which returns an application-scoped singleton instance.

Example 6.28. Obtaining the PortletFacesContext Singleton Instance

public class SessionScopedManagedBean {

	private PortletFacesContext portletFacesContext = PortletFacesContext.getInstance();
	
	public List<DlFileEntry> getDocuments() {
		List<DLFileEntry> documents;
		try {
			documents = DLFileEntryLocalServiceUtil.getFileEntries(folderId);
		}
		catch (Exception e) {
			LOG.error(e.getMessage(), e);
			// Don't have to call PortletFacesContext.getInstance() first since
			// a reference to it was obtained when the bean was created.
			portletFacesContext.addGlobalUnexpectedErrorMessage();
		}
		return documents;
	}
}


PortletFacesContext is an abstract class that extends the edoras framework's ExtFacesContext abstract class, which in turn extends the JSF FacesContext abstract class. Since PortletFacesContext ultimately extends FacesContext, it supplies all the same method signatures and can therefore do anything that FacesContext can do. Both PortletFacesContext and ExtFacesContext implement the delegation design pattern for methods defined by FacesContext by first calling FacesContext.getCurrentInstance() and then delegating to corresponding methods. The benefit of using this technique is that JSF portlet developers only have to call PortletFacesContext.getInstance() once, and can save the singleton object reference for future use.

UML Class Diagram Showing FacesContext Class Inheritance

Figure 6.7. UML Class Diagram Showing FacesContext Class Inheritance


UML Class Diagram for org.edorasframework.extfaces.context.ExtFacesContext

Figure 6.8. UML Class Diagram for org.edorasframework.extfaces.context.ExtFacesContext


UML Class Diagram for org.edorasframework.portletfaces.context.PortletFacesFacesContext

Figure 6.9. UML Class Diagram for org.edorasframework.portletfaces.context.PortletFacesFacesContext


6.8. PortletFaces Expression Language Additions

PortletFaces introduces several variables into the Expression Language (EL).

Table 6.3. PortletFaces EL Variables

EL Variable Description
i18n As an abbreviation for the word "internationalization", the i18n EL variable enables page authors to declaratively specify message keys that hook into Liferay's Language Utility.

Type: String

liferay Utility managed-bean that is designed to be kept in JSF request scope. Its purpose is to introduce some Liferay-specific variables into the JSF EL.

Type: org.edorasframework.portletfaces.bean.util.Liferay

liferay.companyId The Liferay companyId primary key value associated with the community/organization portal page that the current portlet is placed upon.

Type: Long

liferay.documentLibraryURL The absolute URL for the Liferay Document Library Struts action path.

Type: String

liferay.imageGalleryURL The absolute URL for the Liferay Image Gallery Struts action path.

Type: String

liferay.imageURL The absolute URL for the Liferay Image Servlet.

Type: String

liferay.groupUser The Liferay User that owns the Liferay community/organization portal page that the current portlet is placed upon.

Type: com.liferay.portal.model.User

liferay.layout The Liferay Layout associated with the community/organization portal page that the current portlet is placed upon.

Type: com.liferay.portal.model.Layout

liferay.permissionChecker The Liferay PermissionChecker associated with the current request and Liferay User.

Type: com.liferay.portal.security.permission.PermissionChecker

liferay.portalURL The absolute URL for the portal.

Type: String

liferay.portlet the containing Liferay Portlet associated with the PortletRequest.

Type: com.liferay.portal.model.Portlet

liferay.portraitURL Designed to be called from the EL by passing a Liferay User or userId as an array index, returns the absolute URL to the user's portrait.

Type: String

liferay.service Designed to be called from the EL by passing a Liferay service name String (bean id) as an array index, returns the instance of the service class.

Type: Object

liferay.theme The Liferay Theme associated with the Liferay Layout.

Type: com.liferay.portal.model.Theme

liferay.themeDisplay The Liferay ThemeDisplay associated with the PortletRequest.

Type: com.liferay.portal.theme.ThemeDisplay

liferay.themeImageURL Designed to be called from the EL by passing a relative path to a theme image as an array index, returns the absolute URL to the theme image.

Type: String

liferay.themeImagesURL The absolute URL for the image path associated with the current Liferay Theme.

Type: String

liferay.user The Liferay User associated with the PortletRequest.

Type: com.liferay.portal.model.User

liferay.userHasPortletPermission Designed to be called from the EL by passing an action-key as an array index, returns a Boolean indicating whether or not the Liferay User associated with the PortletRequest has permission to execute the specified action-key on the current portlet.

Type: Boolean


6.8.1. i18n

As an abbreviation for the word "internationalization", the i18n EL variable enables page authors to declaratively specify message keys that are provided by one of the following:

  • Liferay's Language Utility
  • Portlet WAR additions to Liferay's Language Utility
  • The JSF standard message keys

The Liferay Language Utility is typically accessed by portlet developers by calling static Java methods found in the LanguageUtil class. The utility operates by reading the locale-specific version of the portal's Language.properties file, which contains thousands of keys and internationalized messages.

Portlet developers can extend the Liferay Language Utility by creating a file within the portlet WAR named WEB-INF/liferay-hook.xml that points to locale-specific resource bundles that are in the runtime classpath of the portlet.

Example 6.29. WEB-INF/liferay-hook.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 5.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_5_2_0.dtd">
<hook>
	<language-properties>Language_en_US.properties</language-properties>
</hook>

Example 6.30. Contents of Language_en_US.properties

add-new-entry=Add New Entry
save-entry=Save Entry 

Example 6.31. Usage of the i18n EL Variable

<h:outputLabel value="#{i18n['first-name']}" />

When using JBoss EL, page authors can take advantage of the i18n.replace() method in order to substitute values into the text of the message.

Example 6.32. Usage of the i18n EL Variable with JBoss EL

<!--
Note: The US English translation of the x-has-x-friends key would look like the following:
x-has-x-friends={0} has {1} friends.
-->
<h:outputText value="#{i18n.replace('x-has-x-friends', liferay.groupUser.fullName, friendsModel.dataModel.rowCount)}" />

6.8.2. liferay

This is a utility managed-bean that is designed to be kept in request scope. Its purpose is to introduce some Liferay-specific variables into the JSF EL. The reason why this is implemented as a managed-bean (and not as an ELResolver) is because of the way ICEfaces 1.x handles Ajax requests. When an ICEfaces portlet is first rendered to the portal page, the ICEfaces portlet bridge participates in a normal manner with the portlet lifecycle. However, all user interactions that trigger an Ajax XMLHttpRequest (like partialSubmit) bypass the portlet lifecycle and go directly to the ICEfaces PersistentFacesServlet. While this has great benefits for speed, it introduces problems when ICEfaces portlets need to interact with Liferay resources that are scoped to the portlet lifecycle. For example, the Liferay ThemeDisplay object is available as a request attribute in the portlet lifecycle, but when the lifecycle is complete, Liferay's ServicePostAction will call the ThemeDisplay.recycle() method which invalidates all of the properties. If the portlet utilizing this managed bean is an ICEfaces portlet, then ICEfaces will place the instance of this class in its "extended" request scope, which will keep the Liferay-specific values in existence long after the portlet lifecycle has completed. If the portlet is a standard JSF portlet, then the JSF managed-bean facility will place the instance of this class in standard request scope. This introduces a small amount of overhead for standard JSF portlets, but is necessary in order to have PortetFaces supply a standard API for both ICEfaces portlets and JSF portlets.

6.8.3. liferay.companyId

The Liferay companyId primary key value associated with the community/organization portal page that the current portlet is placed upon.

Example 6.33. EL Usage of liferay.companyId

<h:outputText value="#{liferay.companyId} is the companyId associated with this set of Liferay Portal pages." />

6.8.4. liferay.documentLibraryURL

The absolute URL for the Liferay Document Library Struts action path prefix. The most common use case is to append the /get_file suffix and some additional request parameters in order to provide a hyperlink to a document in the Liferay Document Library. See the Liferay struts-config.xml file for a complete list of available suffixes.

Example 6.34. EL Usage of liferay.documentLibraryURL

<h:dataTable id="documents" value="#{documentModelBean.dataModel}" var="dlFileEntry">
	<h:column>
		<f:facet name="head">
			<h:outputText value="#{i18n['file-name']}" />
		</f:facet>
		<h:outputLink
			target="_blank"
			value="#{liferay.documentLibraryURL}/get_file?p_l_id=#{liferay.themeDisplay.plid}&folderId=#{dlFileEntry.folderId}&name=#{dlFileEntry.name}">
			<h:outputText value="#{dlFileEntry.title}" />
		</h:outputLink>
	</h:column>
</h:dataTable>

6.8.5. liferay.groupUser

The Liferay User that owns the Liferay community/organization portal page that the current portlet is placed upon.

Example 6.35. EL Usage of liferay.groupUser

<h:outputText
	value="The user named #{liferay.groupUser.fullName} owns this set of Liferay Portal pages." />

6.8.6. liferay.imageGalleryURL

The absolute URL for the Liferay Image Gallery Struts action path prefix. See the Liferay struts-config.xml file for a complete list of available suffixes.

6.8.7. liferay.imageURL

The absolute URL for the Liferay Image Servlet. Although this can be used to construct a URL that points a Liferay user's portrait/photo, for performance reasons, it is better to use the portraitURL EL variable instead.

6.8.8. liferay.layout

The Liferay Layout associated with the community/organization portal page that the current portlet is placed upon.

Example 6.36. EL Usage of liferay.layout

<h:outputText
	value="The name of this portal page is #{liferay.layout.name}" />

6.8.9. liferay.permissionChecker

The Liferay PermissionChecker associated with the current request and Liferay User.

Example 6.37. EL Usage of liferay.permissionChecker

<h:commandButton actionListener="#{backingBean.save}" rendered="#{liferay.permissionChecker.companyAdmin}" value="#{i18n['save']}" />

6.8.10. liferay.portalURL

The absolute URL for the portal. For example: http://localhost:8080

6.8.11. liferay.portlet

The containing Liferay Portlet associated with the PortletRequest.

Example 6.38. EL Usage of liferay.portlet

<h:outputText
	value="The name of this portlet is #{liferay.portlet.displayName}" />

6.8.12. liferay.portraitURL

Designed to be called from the EL by passing a Liferay User or userId as an array index, returns the absolute URL to the user's portrait.

Example 6.39. EL Usage of liferay.portraitURL

<h:graphicImage value="#{liferay.portraitURL[liferay.group.user]}" />

6.8.13. liferay.service

Designed to be called from the EL by passing a Liferay service name String (bean id) as an array index, returns the instance of the service class. Liferay manages instances of services using Liferay-extended versions of the Spring XmlWebApplicationContext BeanFactory class named PortalApplicationContext and PortletApplicationContext. The liferay.service extension to the EL is meant to be used to resolve Liferay services so that they can be injected into JSF managed beans via the managed-property feature inside of the portlet's WEB-INF/faces-config.xml file.

Example 6.40. EL Usage of liferay.service (WEB-INF/faces-config.xml)

<managed-bean>
	<managed-bean-name>modelManagedBean</managed-bean-name>
	<managed-bean-class>mypackage.ModelManagedBean</managed-bean-class>
	<managed-bean-scope>request</managed-bean-scope>
	<!-- Inject the service into the model managed bean. -->
	<managed-property>
		<property-name>myService</property-name>
		<value>#{liferay.service['myservice.bean.id']}</value>
	</managed-property>
</managed-bean>

6.8.14. liferay.theme

The Liferay Theme associated with the Liferay Layout.

Example 6.41. EL Usage of liferay.theme

<h:outputText value="The name of the Liferay theme applied to this portal page is #{liferay.theme.name}" />

6.8.15. liferay.themeDisplay

The Liferay ThemeDisplay associated with the PortletRequest. Perhaps it is easier to think of the Liferay ThemeDisplay as a "display context" which provides access to a wealth of information including the current Company, User, Layout, Theme, PermissionChecker, and more.

Example 6.42. EL Usage of liferay.themeDisplay

<link href="#{liferay.themeDisplay.uRLSignIn}">#{i18n['sign-in']}</link>

6.8.16. liferay.themeImageURL

Designed to be called from the EL by passing a relative path to a theme image as an array index, returns the absolute URL to the theme image.

Example 6.43. EL Usage of liferay.themeImageURL

<h:graphicImage value="#{liferay.themeImageURL['/common/delete.png']}" />

6.8.17. liferay.themeImagesURL

Returns the absolute URL for the image path associated with the current Liferay Theme. For example: http://localhost:8080/image/image_gallery.

Example 6.44. EL Usage of liferay.themeImagesURL

<h:graphicImage value="#{liferay.themeImagesURL}/common/delete.png" />

6.8.18. liferay.user

the Liferay User associated with the PortletRequest.

Example 6.45. EL Usage of liferay.user

<h:outputText value="#{i18n['welcome']}, #{liferay.user.firstName}" />

6.8.19. liferay.userHasPortletPermission

Designed to be called from the EL by passing an action-key as an array index, returns a Boolean indicating whether or not the Liferay User associated with the PortletRequest has permission to execute the specified action-key on the current portlet. The action-key is typically defined in a Liferay resource-action-mapping XML file that defines the <portlet-resource/> and <model-resource/> permissions associated with a Liferay portlet. Please refer to the portal-impl/classes/resource-actions/messageboards.xml file in the Liferay Portal source code distribution for an example of how to write a Liferay resource-action-mapping XML file.

Example 6.46. EL Usage of liferay.userHasPortletPermission

<h:dataTable
	rendered="#{liferay.userHasPortletPermission['VIEW']}"
	value="#{modelManagedBean.users}"
	var="user">
</h:dataTable>

6.9. PortletFaces UIComponent Tags

PortletFaces provides the following UIComponent tags as part of its component suite.

Table 6.4. UIComponent Tags

Tag Description
pf:inputFile Renders an HTML <input type="file" /> tag which provides file upload capability.
pf:inputRichText Renders a text area that provides the ability to enter rich text such as bold, italic, and underline.
pf:permissionsLink Renders an HTML anchor tag (hyperlink) that the user can click on in order to see the Liferay Permissions screen for the associated resource.

6.9.1. The pf:inputFile tag

The pf:inputFile tag renders an HTML <input type="file" /> tag which enables file upload capability.

Note

Usage of this tag requires a faces-context-factory element to be placed in the WEB-INF/faces-config.xml file. See the File Upload section for more details.

Table 6.5. Attributes

Attribute Type Description Required
id String The identifier of the component false
rendered Boolean Boolean flag indicating whether or not this component is to be rendered during the RENDER_RESPONSE phase of the JSF lifecycle. The default value is “true”. false
value java.io.File The value of the component, which will be a file on the server. true

Example 6.47. Example usage of pf:inputFile tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:pf="http://portletfaces.org/facelets">

	<h:form enctype="multipart/form-data">
		<pf:inputFile value="#{managedBean.file}" />
		<h:commandButton action="#{fileUploadManagedBean.submit}" value="Upload File" />
	</h:form>

</f:view>

public class FileUploadManagedBean {

	private File file;

	public File getFile() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}

	public String submit( {
		System.out.println("Uploaded file: " + file);
		return "filesUploaded";
	}
}

6.9.2. The pf:inputRichText tag

The pf:inputRichText tag renders a text area that provides the ability to enter rich text such as bold, italic, and underline. The renderer relies on the CKEditorTM to provide the rich text editing area.

Note

Since Liferay bundles the CKEditorTM JavaScript and related images with the portal, the portlet developer does not need to include it with the portlet.

Table 6.6. Attributes

Attribute Type Description Required
id String The identifier of the component false
rendered Boolean Boolean flag indicating whether or not this component is to be rendered during the RENDER_RESPONSE phase of the JSF lifecycle. The default value is “true”. false
value String The value of the component, the HTML fragment generated by the end-user. true

Example 6.48. Example usage of pf:inputRichText tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:pf="http://portletfaces.org/facelets">

	<h:form>
		<pf:inputRichText id="comments" value="#{modelManagedBean.comments}" />
	</h:form>

</f:view>

6.9.3. The pf:permissionsLink tag

The pf:permissionsLink tag renders an HTML anchor tag (hyperlink) that the user can click on in order to see the Liferay Permissions screen for the associated resource.

Table 6.7. Attributes

Attribute Type Description Required
id String The identifier of the component false
modelResource String The fully qualified Java class of the model resource. For example: MyModelResource.class.getName() true
modelResourceDescription String The description of the model resource. false
redirect Boolean The redirect URL. false
rendered Boolean Boolean flag indicating whether or not this component is to be rendered during the RENDER_RESPONSE phase of the JSF lifecycle. The default value is “true”. false
resourcePrimKey String The primary key value of the model resource. false
value String The text of the hyperlink that the user will see and click on. false

Example 6.49. Example usage of pf:permissionsLink tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:pf="http://portletfaces.org/facelets">

	<h:form>
		<pf:permissionsLink
			modelResource="org.portletfaces.myproject.model.Book"
			modelResourceDescription="Book"
			resourcePrimKey="#{modelManagedBean.book.bookId} />
	</h:form>

</f:view>

6.10. PortletFaces Composite Component Tags

PortletFaces provides the following Facelet Composite Component tags as part of its component suite.

Table 6.8. Facelet Composite Component Tags

Tag Description
pf:iceInfoDataPaginator Encapsulates an ICEfaces ice:dataPaginator tag that renders pagination information for an associated ice:dataTable. The navigation information will match the internationalized Liferay "showing-x-x-of-x-results" message.
pf:iceNavDataPaginator Encapsulates an ICEfaces ice:dataPaginator tag that renders navigation controls for an associated ice:dataTable. The icons will match the current Liferay theme.
pf:icon Encapsulates an HTML img tag whose src attribute contains a fully qualified URL to an icon in the Liferay theme.
pf:messages Encapsulates the h:messages tag and automatically applies the JSR 286 standard class names.
pf:message Encapsulates the h:message tag and automatically applies the JSR 286 standard class names.

6.10.1. The pf:iceInfoDataPaginator tag

The pf:iceInfoDataPaginator encapsulates an ICEfaces ice:dataPaginator tag that renders pagination information for an associated ice:dataTable. The navigation information will match the internationalized Liferay "showing-x-x-of-x-results" message.

Table 6.9. Attributes

Attribute Type Description Required
for String Corresponds to the value of an id attribute for an ice:dataTable tag. true
value String Specifies a string that contains replacement tokens for each piece of pagination information. The default value is the internationalized Liferay "showing-x-x-of-x-results" message. true

Example 6.50. Example usage of pf:iceInfoDataPaginator tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:pf="http://portletfaces.org/facelets">

	<pf:iceInfoDataPaginator for="dataTable1" />
	<ice:dataTable id="dataTable1" value="#{modelManagedBean.rows}" var="row">
		...
	</ice:dataTable>

</f:view>

6.10.2. The pf:iceNavDataPaginator tag

The pf:iceInfoDataPaginator encapsulates an ICEfaces ice:dataPaginator tag that renders navigation controls for an associated ice:dataTable. The icons will match the current Liferay theme.

Table 6.10. Attributes

Attribute Type Description Required
fastForwardIconRendered Boolean Boolean flag indicating whether or not the "Fast Forward" button/icon is rendered. The default value is "false". false
fastRewindIconRendered Boolean Boolean flag indicating whether or not the "Fast Rewind" button/icon is rendered. The default value is "false". false
firstIconRendered Boolean Boolean flag indicating whether or not the "First" button/icon is rendered. The default value is "true". false
for String Corresponds to the value of an id attribute for an ice:dataTable tag. true
lastIconRendered Boolean Boolean flag indicating whether or not the "Last" button/icon is rendered. The default value is "true". false
nextIconRendered Boolean Boolean flag indicating whether or not the "Next" button/icon is rendered. The default value is "true". false
paginator Boolean Boolean flag indicating whether or not the page number links will be rendered. This is a pass-through attribute for the encapsulated ice:dataPaginator. The default value is "true". false
paginatorMaxPages Integer The maximum amount of pages to be displayed in the paginator. This is a pass-through attribute for the encapsulated ice:dataPaginator. The default value is 7. false
previousIconRendered Boolean Boolean flag indicating whether or not the "Previous" button/icon is rendered. The default value is "true". false

Example 6.51. Example usage of pf:iceNavDataPaginator tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:pf="http://portletfaces.org/facelets">

	<pf:iceNavDataPaginator for="dataTable1" />
	<ice:dataTable id="dataTable1" value="#{modelManagedBean.rows}" var="row">
		...
	</ice:dataTable>

</f:view>

6.10.3. The pf:icon tag

The pf:icon tag encapsulates an HTML img tag whose src attribute contains a fully qualified URL to an icon image in the current Liferay theme.

Table 6.11. Attributes

Attribute Type Description Required
alt String Corresponds to the value of the alt attribute for the embedded img tag. The default value is Liferay's internationalized message for the key named view. false
image String The name of the theme image icon, which can be the prefix of any image filename in the Liferay theme's "common" image folder. The default value is view. false

Example 6.52. Example usage of pf:icon tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:pf="http://portletfaces.org/facelets">

	<pf:icon alt="#{i18n['delete']}" image="delete" />

</f:view>

6.10.4. The pf:messages tag

The pf:messages tag encapsualtes the h:messages tag and automatically applies the JSR 286 standard class names. See Liferay Theme Integration for more information.

Table 6.12. Attributes

Attribute Type Description Required
globalOnly Boolean Boolean flag indicating whether or not only global messages should be rendered. false.

Example 6.53. Example usage of pf:messages tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:pf="http://portletfaces.org/facelets">

	<h:form>
		<pf:messages globalOnly="true" />
		<h:panelGrid columns="3">
			<h:outputLabel for="dateOfBirth" />
			<h:inputText id="dateOfBirth" value="#{modelManagedBean.dateOfBirth}" />
			<pf:messages for="dateOfBirth" />
		</h:panelGrid>
		<h:commandButton action="#{backingManagedBean.submit}" />
	</h:form>
	
</f:view>

6.10.5. The pf:message tag

The pf:message tag encapsualtes the h:message tag and automatically applies the JSR 286 standard class names. See Liferay Theme Integration for more information.

Table 6.13. Attributes

Attribute Type Description Required
for String Corresponds to the value of the id attribute of an associated JSF component tag such as h:inputText or h:selectOneMenu. true

Example 6.54. Example usage of pf:message tag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component"
	xmlns:pf="http://portletfaces.org/facelets">

	<h:form>
		<pf:messages globalOnly="true" />
		<h:panelGrid columns="3">
			<h:outputLabel for="dateOfBirth" />
			<h:inputText id="dateOfBirth" value="#{modelManagedBean.dateOfBirth}" />
			<pf:messages for="dateOfBirth" />
		</h:panelGrid>
		<h:commandButton action="#{backingManagedBean.submit}" />
	</h:form>

</f:view>

6.11. PortletFaces Converter Tags

PortletFaces provides the following converter tags.

Table 6.14. Converter Tags

Tag Description
pf:convertDateTime Extends the default JSF date/time converter to support the output of Calendar, and takes the TimeZone and Locale of the current Liferay user into account.

6.11.1. The pf:convertDateTime tag

The pf:convertDateTime tag extends the default JSF date/time converter to support the output of Calendar, and takes the TimeZone and Locale of the current Liferay user into account.

Example 6.55. Example usage of pf:convertDateTime tag

<h:inputText value="#{modelManagedBean.calendar}">
	<pf:convertDateTime />
</h:inputText>

6.12. PorletFaces File Upload

The JSF 1.x and 2.x specifications have not implemented support for HTML forms with enctype="multipart/form-data" and are therefore do not support file uploads. Various workarounds exist for use with the JSP view-handler, such as introducing a servlet filter or phase listener to intercept the request. With the advent of the Facelets view-handler, these techniques have become largely ineffectual. The problem has to do with the FaceletViewHandler restoreView(FacesContext context, String viewId) method which is unable to retrieve the javax.faces.ViewState request parameter for HTML forms with enctype="multipart/form-data". The underlying reason why it can't retrieve the parameter is because the ExternalContextImpl.getRequestParameterMap() method in the JSF Reference Implementation is not equipped to handle these types of postback requests.

The PortletFaces project solves this problem by providing wrapper implementations of FacesContext, FacesContextFactory, and ExternalContext. These can be activated by placing the following <faces-context-factory> element inside of your portlet WAR's WEB-INF/faces-config.xml descriptor:

Example 6.56. Example usage of faces-context-factory element

<factory>
	<faces-context-factory>org.edorasframework.portletfaces.bridge.sun.FacesContextFactoryImpl</faces-context-factory>
</factory>


This will ultimately cause the FacesContext.getExternalContext() method to return an instance of the org.edorasframework.portletfaces.bridge.sun.ExternalContextImpl class. This class overrides the ExternalContext.getRequestParameterMap() method, which uses Apache Commons FileUpload project to parse the request parameters. When used in conjunction with the pf:inputFile tag, JSF portlet developers can provide file upload capability in their Facelet views.

6.13. PortletFaces and PortletPreferences

Simiar to the JSR 301/329 portletPreferences EL variable, PortletFaces introduces an EL variable named portletPreference (singlular, not plural). Although the EL usage is similar in syntax, the implementation is different so that it is compatible with ICEfaces paritalSubmit (Ajax). One drawback of JSR 301/329 portletPreferences EL variable is that when used with ICEfaces partialSubmit, user preference selections from the EDIT mode view will be directly set inside the underlying PortletPreferences object. Even though the user might not click a "Save Preferences" button to store the preferences permanently, the preference values might be active for the remainder of the PortletSession. The PortletFaces portletPreference EL variable does not store submitted values directly inside of the underlying PortletPreferences object. Instead, the submitted values are stored in a temporary copy, which solves the problem related to ICEfaces partialSubmit. Additionally, PortletFaces provides a convenience backing managed-bean named PortletPreferencesForm that has an action-listener named PortletPreferencesForm.submit() that will permanently store the portlet preferences.

Example 6.57. EDIT Mode with PortletFaces and ICEfaces Partial Submit

<!--
This is a file named edit.xhtml that can be used for portlet EDIT mode.
It utilizes the PortletFaces portletPreference EL variable for gaining
read/write access to javax.portlet.PortletPreferences. Unlike the
JSR 301/329 approach, there is no need to write a backing managed-bean
because PortletFaces already provides one named portletPreferencesForm.
-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ice="http://www.icesoft.com/icefaces/component">

	<ice:messages globalOnly="true" />
	<ice:form partialSubmit="true">
		<ice:outputLabel for="datePattern" />
		<ice:inputText id="datePattern" required="true" value="#{portletPreference['datePattern']}" />
		<ice:message for="datePattern" />
		<ice:commandButton actionListener="#{portletPreferencesForm.submit}" partialSubmit="false" value="Save Preferences" />
	</ice:form>
</f:view>

6.14. PortletFaces Liferay Theme Integration

PortletFaces offers several features that help integrate JSF portlets with the current Liferay theme.

6.14.1. ThemeDisplay

PortletFaces provides the PortletFacesContext.getThemeDisplay() method at the Java level and also the liferay.themeDisplay EL variable for getting access to the Liferay ThemeDisplay object.

6.14.2. Theme Icons

PortletFaces provides the pf:icon Facelet composite component tag that encapsulates an HTML img tag whose src attribute contains a fully qualified URL to an icon image in the current Liferay theme. Additionally, PortletFaces provides the liferay.themeImagesURL and liferay.themeImageURL Facelet composite component tags for gaining access to theme image icons.

6.14.3. Validation Messages (User Feedback)

Most of the standard JSF HTML component tags render themselves as HTML markup such as <label />, <input />, <span />, etc. and assume the current Liferay theme thanks to the power of CSS. However, the h:messages and h:message tag will not assume the current Liferay theme unless the following JSR 286 standard CSS class names are applied:

  • portlet-msg-error
  • portlet-msg-info
  • portlet-msg-warn

Example 6.58. JSR 286 standard CSS class names applied to the h:messages tag

<h:messages errorClass="portlet-msg-error" fatalClass="portlet-msg-error"
	infoClass="portlet-msg-info" warnClass="portlet-msg-warn" />
			

As a convenience, PortletFaces provides the pf:messages and pf:message Facelet composite component tags that encapsulate the h:messages and h:message tags respectively, and automatically apply the JSR 286 standard class names as shown above.

Note

When running as a portlet, the ICEfaces ice:messages and ice:message component tags automatically apply the JSR 286 standard class names as shown above. Additionally the ice:dataTable component tag will apply the following JSR 286 standard class names for alternating table rows:

  • portlet-section-alternate
  • portlet-section-body

6.15. PortletFaces Liferay Language Portlet Integration

In a normal JSF web application, the Locale that is used to display internationalized values is dictated by the locale specified in the end-user's web-browser. However, Liferay Portal permits the user to select a different locale (language) using the Language Portlet. The user's choice is ultimately saved as a languageId in the Liferay User object and is persisted to the database.

Liferay Portal Language Portlet

Figure 6.10. Liferay Portal Language Portlet


In order to provide seamless integration between JSF portlets and the language selected by the user, PortletFaces provides the LiferayLocalePhaseListener. The listener monitors the RESTORE_VIEW phase of the JSF lifecycle and will automatically set the locale inside the UIViewRoot according to the value specified by Liferay's User.getLocale() method, which is aware of the selected languageId. This in turn causes internationalization techniques such as the f:loadBundle tag and the i18n EL keyword to automatically translate message keys into the language selected by the user with the Liferay Language Portlet.

6.16. PortletFaces Improved Integration Between Liferay and ICEfaces 1.x

The ICEfaces 1.x extended-request scope is very similar to what JSF 2.0 now calls "view" scope. While normal JSF request scope keeps a managed-bean in memory for the duration of a request, the ICEfaces extended-request scope typically keeps a managed-bean in memory for a longer duration. The scope begins when a JSF view is first requested, and terminates under one of the following conditions:

  • The user naviates to a different JSF view
  • The user signs-out of the Portal
  • The PortletSession expires
  • The ICEfaces connection-timeout expires
  • The user dismisses the browser window

When an ICEfaces portlet is rendered on a portal page, the ICEfaces 1.x portlet bridge will participate in the Portlet RenderRequest phase just like any other portlet. However, from that time on the ICEfaces 1.x bridge will bypass the portlet lifecycle and perform all subsequent interactions with the server via Ajax by hitting the ICEfaces PersistentFacesServlet. The ICEfaces 1.x portlet bridge is based on the JSR 168 (Portlet 1.0) API and therefore cannot take advantage of the new ResourceRequest phase of the JSR 286 (Portlet 2.0) API. The benefit of hitting the PersistentFacesServlet directly is that ICEfaces partial submits will execute faster than if they went through the the Portlet 2.0 ResourceRequest phase. The drawback is that certain Liferay objects are unusable after the initial RenderRequest phase. Specifically, the Liferay PermissionChecker and ThemeDisplay objects get "recycled" at then end of the RenderRequest phase by Liferay's ServicePostAction.

PortletFaces works around this problem by making copies of Liferay's PermissionChecker and ThemeDisplay objects and keeping them in "request" scope, which will default to the ICEfaces extended-request scope when ICEfaces is used in a portlet. These objects are available to JSF portlet developers by calling the PortletFacesContext.getPermissionChecker() and PortletFacesContext.getThemeDisplay() methods respectively.

Example 6.59. Getting the Liferay PermissionChecker and ThemeDisplay objects from the PortletFacesContext

import com.liferay.portal.security.permission.PermissionChecker;
import com.liferay.portal.theme.ThemeDisplay;

public class BackingManagedBean {

	PortletFacesContext portletFacesContext =
		PortletFacesContext.getInstance();

	public String submit() {
		PermissionChecker permissionChecker =
			PortletFacesContext.getPermissionChecker();

		ThemeDisplay themeDisplay =
			PortletFacesContext.getThemeDisplay();
	}
}

Chapter 7. edoras framework - XML Persister

7.1. Overview

Sometimes it is very usefull to serialize simple java objects to an XML stream and to deserialize them later back from the stream. XStream offers very powerfull functionality for serializing objects to XML and back again, however, if the attributes and types of such a serialized class change, existing XML strings might not be parsed back to objects again.

The xmlpersister within the edoras framework offers a simple, annotation driven way of using XStream in any java class with no such limitations. As you add a new attribute to your class or remove an existing one, it does not matter, even handling of existing streams based on the old class is possible without failure.

Basically, where a simple XML serialization of java objects is needed where the XML stream stays longer as the lifetime of the appropriate virtual machine creating them (e.g. the XML stream is persisted somehow), the xmlpersister is a good way to deal with.

7.2. Configuration

It all starts with an XmlPersister whose default implementation is the DefaultXmlPersister. There is no need of any configuration for this component being used, except that every Java class used with the xmlpersister for serializing must be registered in order to let the persister scan its annotations.

There are two ways to do that, either register all classes statically within the DefaultXmlPersister somewhere:

static {
    // register all classes to be serialized using the xmlpersister
    DefaultXmlPersister.registerPersistableClass(PersistableClass1.class);
    DefaultXmlPersister.registerPersistableClass(PersistableClass2.class);
}

or subclass the DefaultXmlPersister with your own class, registering the classes as a static initialization:

public class YourXmlPersister extends DefaultXmlPersister {
    static {
        // all your static registrations go in here
        DefaultXmlPersister.registerPersistableClass(PersistableClass.class);
    }

    public ProcessXmlPersister() {
        // do some more initialization, if needed
    }
}

7.3. Annotations

In order to tell the xml persister which fields to persist, there are a couple of annotations available. Unlike the basic XStream framework, the xmlpersister does not persist fields automatically unless they have an annotation on it.

The first annotation to be placed on the class itself is the @XmlPersistable annotation to tell the persister that objects of that class are persistable and how their alias should be in the XML stream.

@XmlPersistable
public class SamplePersistableClass {

}

Optionally, the alias to be used by the xml persister can be provided, otherwise, the convention is used instead where the persister is taking the simple class name as the alias.

@XmlPersistable("Alias")
public class SamplePersistableClass {

}

Any field needed to be streamed into an attribute of the xml node being created for the object needs to be annotated with the @XmlPersistedAttribute annotation:

@XmlPersistable
public class SamplePersistableClass {

    /** This field is serialized as an attribute using name "description". */
    @XmlPersistedAttribute
    private String description;

    /** This field is not serialized as it does not have the @XMLPersitedAttribute annotation. */
    private int number;
}

A field which itself is an annotated class can be written to the stream as a sub-node using the @XmlPersistedObject annotation:

@XmlPersistable
public class SamplePersistableClass {

    /** This object is recursively serialized to XML using a sub-node. */
    @XmlPersistedObject
    private SamplePersistableClass parent;
}

7.4. Annotation options

@XmlPersistable

Parameter Description optional?
value The name of the alias used for persisting the object as a node in the XML stream. yes

@XmlPersistedAttribute

Parameter Description optional?
value The name of the attribute in the XML node. If not provided, the name of the field is taken as the convention. yes
defaultValue Optionally used to define the default value for the annotated attribute. This will be used if either the attribute was not found or if parsing the value found was leading into an exception. This will avoid the deserialization to fail, even if attribute values are not parsable. yes
delimiter The optional delimiter to be used, if the attribute type is a java.util.List containing String elements. Defaults to DefaultXmlPersistingHandler.STRING_LIST_DELIMITER. yes
converter If the attribute value is a list of elements T, the converter must be provided, implementing the interface org.edorasframework.xmlpersister.ListElementConverter for the same type T. yes

@XmlPersistedObject

Parameter Description optional?
value The name of the attribute in the XML node for this object. If not provided, the name of the field is taken as the convention. yes
implementation If this annotation is placed on a collection field, this parameter must be provided as the implementation to be created while deserializing, if the interface type is used as the field type. For instance, if the field type is java.util.List, the implementation might be java.util.ArrayList. no for a Collection based field type
accessor If this annotation is placed on a field having an implementation with a collection of elements, this parameter must be provided, if the collection does not implement the java.util.Collection interface. The class provided with this parameter must implement the org.edorasframework.xmlpersister.CollectionAccessor interface. yes

7.5. Samples and code snippets

Assume the following simple Java class:

@XmlPersistable
public class SamplePersistableClass {

    /** This field is serialized as an attribute using name "description". */
    @XmlPersistedAttribute
    private String description;

    /** This field is not serialized as it does not have the @XMLPersitedAttribute annotation. */
    private int number;

    /** This object is recursively serialized to XML using a sub-node. */
    @XmlPersistedObject
    private SamplePersistableClass parent;

    /** A list of strings persisted as a single attribute having delimiter ';'. */
    @XmlPersistedAttribute(delimiter = ";")
    private List<String> messages;

    // ... followed by getters and setters ...

The following code would produce an XML:

SamplePersistableClass parent = new SamplePersistableClass();
parent.setDescription("Parent Object");
parent.setNumber(10);
    
SamplePersistableClass child = new SamplePersistableClass();
child.setDescription("Child Object");
child.setParent(parent);
parent.addMessage("message 1");
parent.addMessage("message 2");
parent.addMessage("message 3");
  
DefaultXmlPersister persister = new DefaultXmlPersister();
String xml = persister.persistObject(child);
System.out.println(xml);

The output of this code snippet would be:

<SamplePersistableClass description="Child Object">
  <SamplePersistableClass objectName="parent" description="Parent Object" messages="message 1;message 2;message 3"/>
</SamplePersistableClass>

Here are some more examples on how to use the annotations:

@XmlPersistable
public class SamplePersistableClass {

    // this will convert the list of objects to a single, delimited string
    // using the converter, stored in a single attribute of the XML node
    @XmlPersistedAttribute(converter = PersistetObjectConverter.class)
    private List<PersistetObject> objects;

The converter could be as simple as the following:

public class PersistetObjectConverter implements ListElementConverter<PersistetObject> {

    public String convertToString(PersistetObject element) {
        StringBuilder buf = new StringBuilder();
        buf.append(element.getTest());
        buf.append(";");
        buf.append(element.getNumber());
        return buf.toString();
    }

    public String getElementDelimiter() {
        return "|";
    }

    public PersistetObject parseFromString(String element) {
        String[] splits = element.split(";");
        return new PersistetObject(splits[0], Integer.parseInt(splits[1]));
    }
}

Using default values allows you to add a new field to a class, annotate it with a default value to be able to read in existing XML streams without that specific field. If there is no such default value specified, the field is left untouched (null) while deserializing. So setting a default value prevents the field from being left to null.

@XmlPersistable
public class SamplePersistableClass {

    @XmlPersistedAttribute(defaultValue="default description")
    private String description;

7.6. Hooking into the persistency mechanism

Sometimes it is not enough to have a set of annotations to be placed on fields of an object to persist it into an XML stream. The component itself is easy to be extended (see the javadoc for more information about that), however, there is also a simple hook interface available to be implemented by persistable classes to hook into the persistence mechanism.

@XmlPersistable()
public class SamplePersistableClass implements XmlPersistableHooks {
    // ... implementation of the hooks goes in here ...
}

See the javadoc of that interface for a detailed description about the hook methods provided and how to extend the persistence of the object being serialized / deserialized to / from XML. Basically, there are hooks provided for pre and post loading, writing dynamic attribute values as well as writing object and object lists to the stream.

Chapter 8. edoras framework - Test

8.1. Executor

The org.edorasframework.test.common.executor.TestExecutor is a can execute JUnit tests by returning the results as org.edorasframework.test.common.executor.report.TestCaseReport objects which can be used to present test results at runtime.

8.1.1. StartupTestServlet

The org.edorasframework.test.common.executor.web.StartupTestServlet uses a test case executor to execute unit tests in an application server environment. This allows to run automated integration tests against productive databases using all layers of the application.

8.1.1.1. Configuration

The classes the test servlet needs to execute need to be defined colon separated within the init-param with name test.classes.

<!-- The servlet configuration -->
<servlet>
  <servlet-name>StartupTestServlet</servlet-name>
    <servlet-class>org.edorasframework.test.common.executor.web.StartupTestServlet</servlet-class>
    <init-param>
      <param-name>test.classes</param-name>
      <param-value>org.xyz.Test1;org.xyz.Test2;org.xyz.Test3</param-value>
    </init-param>
  <load-on-startup>10</load-on-startup>
</servlet>

<!-- The mapping for the test servlet -->
<servlet-mapping>
  <servlet-name>StartupTestServlet</servlet-name>
  <url-pattern>*.test</url-pattern>
</servlet-mapping>

8.1.1.2. Test results

By calling the servlet on the pammed URL, the test results are presented on a simple web page.

8.1.1.3. Re-Executing tests

By adding the request parameter retest to the test servlet url, the tests are reexecuted.

Chapter 9. edoras framework - Event

9.1. Overview

The edoras framework event module can be used to raise events from beans which will be observed by other beans. The events can be raised either by using the API of by adding an annotation on the method that should raise an event. To observe events one possibility is to add an ObserveEvent annotation on the method that should be called if the event is raised. Another way is to add an EventListener to the EventBus.

9.2. Configuration

To use edoras framework the following maven artifact has to be used:

<groupId>org.edorasframework.event</groupId>
<artifactId>org.edorasframework.event</artifactId>

This artifact contains the application context file org.edorasframework.event-applicationContext.xml which needs to be loaded in addition to the custom context. This context file contains the following sections:

  • Spring aop configuration; initializes Spring aop which will load the raise event pointcut advisor.

    <!-- configure spring aop -->
    <aop:config />
  • EventBus implementation; Singleton scoped bean to handle the events. The event bus has to be defined with the name "edsEventBus".

    <!-- The default event bus implementation -->
    <bean id="edsEventBus" 
        class="org.edorasframework.event.impl.DefaultEventBus"
        lazy-init="true" />
  • RaiseEventAdvisor implementation; defines the pointcut for the raise event annotated methods.

    <!-- The raise event advice which will be automatically found and applied by Spring aop -->
    <bean id="edsRaiseEventPointcutAdvisor" lazy-init="true" 
        class="org.edorasframework.event.
           annotation.impl.RaiseEventPointcutAdvisor" />
  • EventBusBeanPostProcessor; bean factory post processor and bean post processor that handles observe event beans.

    <!-- The event bus  bean post processor -->
    <bean id="edsEventBusBeanPostProcessor" lazy-init="true"
        class="org.edorasframework.event.
            impl.EventBusBeanPostProcessor" />

9.3. Usage

9.3.1. Raise events

An event can be raised by two different ways.

9.3.1.1. Raise events by using the API

The event bus interface defines several methods to raise an event from your java code.

void raiseEvent(Event event) throws EventException;

void raiseEvent(String eventId, EventType type, Object bean, Object[] parameters) throws EventException;

void raiseEvent(String eventId, EventType type, Object bean, Object[] parameters, Object returnValue) throws EventException;

To access the event bus bean the module provides a convenience method:

org.edorasframework.event.config.EventBeans.getEventBus();

9.3.1.2. Raise events by Annotation

An event can be raised from any public method of any configured bean class by just adding the annotation org.edorasframework.event.annotation.RaiseEvent to it. This annotation defines two parameters where both are optional:

  • value: Defines the string id of the event that will be risen from this method. If no Id is defined, a default id is generated. This default id consists of the simple class name and the name of the method that will raise the event. SimpleClassName.methodName

  • type: Defines when the event will be raised. The following possibilities are defined within the enum org.edorasframework.event.EventType.

    • SUCCESS: the event is raised only if the method is successful. Default value.

    • FAILURE: the event is only raised if an exception occurred.

    • ALWAYS: the event is raised if the method is successful or if an exception occurred.

@RaiseEvent(value = "demoEventId", type = EventType.ALWAYS)
public void demoMethod() {
    // your implementation here ...
}

To enable event raising by anntotation the only thing that has to be done is that the bean with the annotated methods is configured within the application context.

9.3.2. Observe events

To observe events this module provides two possibilities.

9.3.2.1. Observe events by listener

To listen for events you can always register an event listener within the event bus by using the following method. The listener is registered for one single event id on which it is listening to. If no longer needed the event listener can also be removed from the event bus component using one of its remove methods.

a void addEventlistener(String eventId, org.edorasframework.event.EventListener listener);

The org.edorasframework.event.EventListener interface defines one method, which will be called if an event for this listener was raised.

void onEvent(org.edorasframework.event.Event event);

9.3.2.2. Observe events by annotation

Observing events by annotation can be used on all public methods of any singleton bean. The annotation org.edorasframework.event.annotation.ObserveEvent defines two parameters of which the value is mandatory.

  • value: Defines the string id of the events that will be provided to this observer method. The value is mandatory.

  • create: Defines whether the bean has to be created if an event for the defined is raised or not. By default the create flag is set to true.

The observe event annotation supports three different method signatures:

  • no arguments: The method is called with no additional information.

    @ObserveEvent("anEventId") 
    public void observeMethodA() {
        // observer code here ...
    }

  • event as argument: The event object contains all information about the event and its source.

    @ObserveEvent("anEventId")
    public void observeMethodB(org.edorasframework.event.Event event) {
        // observer code here ...
    }

  • same signature as raise event method: The method gets the same parameters as the raise method got.

    @ObserveEvent(EVENT_ID_D)
    public void observeMethodD(String string, Integer integer, Date date) {
        // observer code here ...
    }

To enable event observe event by anntotation the bean with the annotated methods has to be configured as singleton within the application context.

Chapter 10. edoras framework - Web

10.1. Overview

The web part of the edoras framework is based on JSF and facelets as the main web technologies. It provides some useful functions that extend these base frameworks and other components that allow to access the edoras core functions from within the web part.

10.2. Configuration

To configure an application to use the edoras framework, it is mainly necessary to add some parameters to the main configuration files of any JSF application. With the following configuration files, a web application with the edoras framework is set up and ready to develop.

10.2.1. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.edorasframework.web.config.DependencyXmlWebApplicationContext
        </param-value>
    </context-param>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:/META-INF/*-applicationContext.xml,
            /WEB-INF/applicationContext.xml
        </param-value>
    </context-param>
  
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>
            javax.faces.webapp.FacesServlet
         </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- bootstrap spring framework -->
    <servlet>
        <servlet-name>context</servlet-name>
        <servlet-class>
            org.springframework.web.context.ContextLoaderServlet
         </servlet-class>
        <!-- load the context servlet after the faces servlet -->
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    
    <!-- spring support for request and session scope -->
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
</web-app>
				

It basically defines the spring context, where to search the spring bean definitions and the servlets for JSF and spring.

10.2.2. faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
    version="1.2">
    
    <factory>
        <application-factory>
            org.edorasframework.web.util.JBossELApplicationFactory
        </application-factory>
    </factory>

    <application>
        <view-handler>
            com.icesoft.faces.facelets.D2DFaceletViewHandler
        </view-handler>
        <el-resolver>
            org.springframework.web.jsf.el.SpringBeanFacesELResolver
        </el-resolver>
    </application>
</faces-config>
				

It defines a special application factory that causes the JBoss EL implementation to be used, the facelets view handler and the spring bean EL resolver so that all spring beans can be accessed through EL expressions.

10.2.3. Spring beans in edsWeb

Definitions of the spring beans in the web part of the edoras framework.

Name edsAppCtrl
Class org.edorasframework.core.config.ApplicationContextController
Overrides definition from edsCore
Implements/Extends
Description Set the application context control into web mode.
Name edsWebMsg
Class org.edorasframework.core.locale.impl.PrefixResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The web message handler, delegates to the global message handler but prefixes all keys with 'org.edorasframework.web.'
Name edsLocale
Class org.edorasframework.web.locale.JsfLocalisationController
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.locale.LocalisationController
Description Set the global localisation controller to use JSF and to delegate to a bean named 'edsLocaleProvider'.
Name edsPhaseListenerBeanPostProcessor
Class org.edorasframework.web.util.PhaseListenerBeanPostProcessor
Implements/Extends
Description Register a phase listener post processor, this causes spring beans which implement PhaseListener to be automatically registered in JSF to be a phase listener.
Name edsWebHtmlSec
Class org.edorasframework.websecurity.impl.NullHtmlSecurisator
Implements/Extends org.edorasframework.websecurity.HtmlSecurisator
Description Set the HTML securisator which removes any potentially dangerous tags and attributes from user provided HTML code.
Name edsWebLayoutManager
Class org.edorasframework.web.entity.LayoutManager
Implements/Extends org.edorasframework.web.entity.LayoutManager
Description The web layout manager that saved the available layouts.
Name edsWebCurrentLayout
Class org.edorasframework.web.entity.CurrentLayout
Implements/Extends org.edorasframework.web.entity.CurrentLayout
Description The web layout controller that saves the current layout during page creation.
Name edsDialogHandler
Class org.edorasframework.web.locale.JsfMessageDialogHandler
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.locale.DialogHandler
Description A dialog handler that shows dialogs using the JSF message functionality.
Name edsElEnvironment
Class org.edorasframework.web.util.JsfFactories
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.el.ElEnvironment
Description An EL environment that bases on the EL implementation provided by JSF.
Name edsWebSecurity
Class org.edorasframework.web.security.impl.DefaultAccessSecurisator
Implements/Extends
Description

10.3. Usage

10.3.1. Entity handling

One main goal of the web part of edoras framework is to facilitate the handling of entities. Default use cases should be as easy as possible. It provides some functions to use the entity handling of the core (see Section 2.3.1, “Entity handling” ).

After we have created an entity with @Label and validation annotations we can go on and create a view for it:

<html xmlns:web="http://www.edorasframework.org/taglib/org.edorasframework.web"
...
    <web:panel layout="simple">
        <web:textProperty value="#{person.firstName}" />
        <web:textProperty value="#{person.lastName}" />
        <web:property value="#{person.gender}">
            <h:selectOneRadio>
                <f:selectItem itemValue="MALE" itemLabel="male" />
                <f:selectItem itemValue="FEMALE" itemLabel="female" />
            </h:selectOneRadio>
        </web:property>
        <web:property value="#{person.birthday}">
            <h:inputText style="#{property.valid ? 'border: 1px solid green' : 'border: 1px solid red'}">
                <f:convertDateTime type="date"/>
            </h:inputText>
        </web:property>
    </web:panel>
...

Several things are going on here:

  • The namespace 'web' is defined.

  • A panel with layout 'simple' is opened. This defines how the three parts of a property (label, input field, message) are layed out on the screen. There are two predefined layouts: 'table' and 'simple'. You can define your own layouts, see org.edorasframework.web.entity.LayoutManager and the sources of the predefined layouts in META-INF/org/edorasframework/web/tag of the org.edorasframework.web.jar

  • Two text properties for the first and last name are defined. These are rendered as input fields with the correct label (defined with @Label). User input is automatically validated (based on the validation annotations of the entity) and if validation fails, appropriate messages are shown.

  • A property tag for the gender is opened. This adds a org.edorasframework.web.entity.PropertyInfo with the name 'property' to the context inside the property tag. This provides informations about the property like the label, the HTML id, and the validation state of the property.

  • A selectOneRadio tag is added to display two checkboxes for the gender. Notice that there is no 'value' attribute on the tag. This is done automagically by the property tag. It adds 'value', 'id' and 'required' attributes to all its child tags that are EditableValueHolders and that do not provide these attributes by themselves.

  • As last thing, a property for the birthday is added. The input field is displayed with a green or red border depending whether the date is valid or not.

10.3.1.1. Converters

Displaying a list of entities in a combobox is a painful thing in JSF. You have to provide a list of SelectItems which have a value and a label. The value is used a key to find out which item the user has selected and must be a string. So if you set the value to be the entity itself, you get back the result of the toString method instead of your entity. If you set the value to be the ID of the entity, you get it back, but have to convert the ID back to the corresponding entity.

To make this task easier, you can use the propertyConverter and the entityConverter . With these, the SelectItem's values may be the entities itself. The converter takes a given property or the ID from the entity as key and automatically converts the key back to the corresponding entity.

10.3.2. Tag libraries

In the preceding sections, several tags provided by the edorasframework where shown. For a complete list of the available tags, see the taglibdoc section of the maven site of the web project.

Chapter 11. edoras framework - ViewManager

11.1. Overview

The viewManager is used to manager the views of an application. It can handle the view hierarchy and create generic view menus.

11.2. Configuration

The viewManager module the following two beans automatically to the application context. If a custom implementation is needed the beans can be overwritten by defining an own bean with the same name in the application's application context configuration.

<!-- The default view manager bean -->
<bean id="edsViewManager" class="org.edorasframework.viewmanager.core.impl.DefaultViewManager" /> 

<!-- The default view manager controller bean -->
<bean id="edsViewManagerController" class="org.edorasframework.viewmanager.core.impl.DefaultViewManagerController" />

11.2.1. Web Configuration

Within the web module the view manager controller is by default session scoped.

<!-- Register the default view manager controller session scoped. -->
<bean id="edsViewManagerController" scope="session" 
   class="org.edorasframework.viewmanager.core.impl.DefaultViewManagerController"/>

<!-- Register the view manager phase listener -->
<bean id="edsViewManagerPhaseListener" class="org.edorasframework.viewmanager.web.impl.ViewManagerPhaseListener" />

This module registers also the viewManager phase listener automatically. The viewManager phase lsitener activates an deactivates the views as they are loaded within the session. To work properly the phase listener needs an the org.edorasframework.web.faces.listener.PhaseListenerBeanPostProcessor bean within the application context. This bean is by default initialized by the org.edorasframework.web module and needs only to be defined if the org.edorasframework.web is not used within the application.

11.3. Defining views

The views can be defined as property within the view manager configuration. A view is defined throught its interface org.edorasframework.viewmanager.core.View.

<bean id="edsViewManager" class="org.edorasframework.viewmanager.core.impl.DefaultViewManager">
   <property name="views"
      <list>
         <bean class="org.edorasframework.viewmanager.core.impl.DefaultView">
            <property name="viewId" value="viewA" />
            <property name="label" value="View A" />
         </bean>
         <bean class="org.edorasframework.viewmanager.core.impl.DefaultView">
            <property name="viewId" value="viewB" />
            <property name="label" value="View B" />
            <property name="parentViewId" value="viewA" />
         </bean>
      </list>
   </property>
</bean>

11.4. View Actions

The viewmanager allows to define actions that are invoked of a view is initialized or disposed. These actions have to implement the interface org.edorasframework.viewmanager.core.InitializingAction for initializing actions or for org.edorasframework.viewmanager.core.DisposingAction disposing actions.

The actions are defined within the view manager controller bean.

<bean id="edsViewManagerController" class="org.edorasframework.viewmanager.core.impl.DefaultViewManagerController">
   <property name="initializingActions">
      <list>
         <!-- initializing actions here -->
      </list>
   </property>
   <property name="disposingActions">
      <list>
         <!-- disposing actions here -->
      </list>
   </property>
</bean>

Chapter 12. edoras framework - Filestore

12.1. Overview

Filestore is a simple component to store files on the database and read them again. The content is not stored in a byte array but directly streamed into / out of the database.

12.2. Configuration

application context

<!-- Service configuration -->
<bean class="org.edorasframework.filestore.core.impl.DefaultFilestoreService">
   <property name="mimeTypeResolver">
      <bean class="org.edorasframework.filestore.core.mime.impl.MagicMimeTypeResolver" />
   </property>
   <property name="dao" ref="edsFileStoreDao" />
</bean>

<!-- The dao configuration -->
<bean id="edsFileStoreDao" class="org.edorasframework.filestore.core.impl.hibernate.HibernateFilestoreDao">
   <!-- define the lob handler to be uesd -->
   <property name="lobHandler" ref="${filestore.lob.handler}" />
</bean>

<!-- LobHandler for well-behaved JDBC drivers -->
<bean id="edsFileStoreDefaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true" />
<bean id="edsFileStoreOracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
   <!-- 
     define a nativeJdbcExtractor that matches to the connection pool you are using. 
     Below the dbcp connection pool implementation is used.
   -->
   <property name="nativeJdbcExtractor">
      <bean class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" />
   </property>
</bean>

<!-- The filestore controller -->
<bean id="edsFileStoreController" scope="session"
   class="org.edorasframework.filestore.icefaces.impl.IcefacesFilestoreController" >
   <property name="filestoreService" value="edsFileStoreService" />
</bean>

<!-- The filestore download handler is used within the download servlet. See web configuration -->
<bean id="edsFileStoreDownloadHandler"
   class="org.edorasframework.filestore.web.impl.FilestoreDownloadHandler" />

12.2.1. Web Configuration

web.xml

<servlet>
   <servlet-name>downloadServlet</servlet-name>
   <servlet-class>org.edorasframework.web.download.DownloadServlet</servlet-class>
   <load-on-startup>5</load-on-startup>
</servlet>

!-- cleans the uploaded files when the session is closed -->
<listener>
   <listener-class>org.edorasframework.filestore.icefaces.impl.InputFileSessionCleaner</listener-class>
</listener>

12.3. FileStoreService

The default implementation of the org.edorasframework.filestore.core.FilestoreService is org.edorasframework.filestore.core.impl.DefaultFilestoreService.

12.3.1. MimeTypeResolver

The org.edorasframework.filestore.core.mime.MimeTypeResolver is a component to resolve the mime type of a given file which is used by the file store. The mime type resolver can be injected into the default filestore service implementation, but is not needed. If no resolver is set the, mime type used will always be application/x-unknown.

12.4. FilestoreDao

Since the filestore dao is streaming the file content directly into and out of the database a lob handler has to be defined within the dao. The lob handler is responsible for the correct handling of the data streams. By default the org.springframework.jdbc.support.lob.DefaultLobHandler can be used. If you are using an oracle database you have to use the org.springframework.jdbc.support.lob.OracleLobHandler and don't forget to set the nativeJdbcExtractor according to your chosen connection pool implementation.

12.5. FileStoreController

The default file store controller implementation is org.edorasframework.filestore.web.impl.DefaultFilestoreController. This controller defines methods to access the file store service.

12.5.1. ICEfaces

The org.edorasframework.filestore.icefaces.impl.IcefacesFilestoreController uses the ICEfaces ICEfaces ice:inputFile component to enable the file upload to the server. Check the ICEfaces documentation to include and configure this component.

12.5.1.1. InputFileSessionCleaner

Since the ICEfaces inputfFile component creates temp files on the server, the org.edorasframework.filestore.icefaces.impl.InputFileSessionCleaner may be used to clean the files of a session when the session gets disposed.

12.6. DownloadServlet

Enable file download, the org.edorasframework.web.download.DownloadServlet has to be configured within the web.xml of your application. This servlet needs the spring application context to be available during initialization. Be sure to set the load-on-startup priority accordingly.

12.6.1. FilestoreDownloadHandler

The org.edorasframework.filestore.web.impl.FilestoreDownloadHandler needs to be configured as spring bean. It is responsible that the requests of the downloadservlet are delegated to the filestoer service.

12.6.2. Generating links for stored files

The filestore web module provides el functions to generate links for stored files. The links can be generated by using the hash id of the document. To use this functions, the namespace http://www.edorasframework.org/taglib/org.edorasframework.filestore.web has to be difined within your web template. The generated links include alreay the context name of the current application.

The function filestoreHashDownloadLink takes the String hash id of a document and retuns the the sownload link for the given document.

Chapter 13. edoras framework - Archetypes

13.1. Overview

Archetypes are maven project templates that can be used to create a new projects very fast. The archetypes of edorasframework create maven projects having the eclipse project configuration.

13.2. Archetypes

The archetype catalog is located within the edorasframework maven2 repository of http://repo.edorasframework.org/mvn/maven2/archetype-catalog.xml.

To create a new project by using an archetype, use the following command from your console. (Currently the m2 eclipse plugin does not support archetypes built with maven archetype plugin 2.0-alpha-4)

mvn archetype:generate -DarchetypeGroupId=archetype.groupId.here -DarchetypeArtifactId=archetype.artifactId.here -DarchetypeCatalog=http://repo.edorasframework.org/mvn/maven2/archetype-catalog.xml

Replace the placeholders archetype.groupId.here and archetype.artifactId.here with one of group and artifact ids of one of the following archetypes.

13.2.1. Web project

groupId: org.edorasframework.archetype

artifactId: org.edorasframework.archetype.edoras.module

This archetype creates a simple eclipse web project with three modules:

  • common: The common components of the project. Such as entities, utilities, ...

  • service: The service layer module. All service implementations for the project are here.

  • web: The presentation layer, where the gui templates, controller- /backing-beans, are located.

13.2.2. edoras module

groupId: org.edorasframework.archetype

artifactId: org.edorasframework.archetype.edoras.module

This archetype creates a default edoras module containing the following three sub projects:

  • core: The common components of the project. Such as entities, utilities, ...

  • web: The service layer module. All service implementations for the project are here.

  • icefaces: The presentation layer, where the gui templates, controller- /backing-beans, are located.

Appendix A. Database scripts

A.1. How to generate database scripts

edorasframework provides no database scripts by default. Nevertheless they can be created by using Hibernate Tools hbm2ddl which exists as ant and as maven2 plugin hibernate3-maven-plugin The properties to be used is documented within the Hibernate tools Reference Guide.

Appendix B. Icefaces patches

The edorasframework provides its own version of the icefaces libraries. They are based on the original icefaces sources and include some patches that fix known issues or add some (rather small) new features. The intension of these patch projects is to provide a fast solution to inconveniences using icefaces. All patches are also submitted to icesoft to include them in future versions of icefaces. So the number of patches should always be relatively small and not grow from release to release.

There are two icefaces patches atrifacts:

  • org.edorasframework.icefaces.<icefaces-version>.core.jar which patches the icefaces.jar of the corresponding version.
  • org.edorasframework.icefaces.<icefaces-version>.comps.jar which patches the icefaces-comps.jar of the corresponding version.

Appendix C. Bean Configurations

C.1.1. Spring beans in edsCore

Name edsAppCtrl
Class org.edorasframework.core.config.ApplicationContextController
Implements/Extends
Description bootstrap bean to access other beans by name or type
Name edsMsg
Class org.edorasframework.core.locale.impl.FallbackResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The global message handler, this must implement MessageHandler and extend ResourceBundle. All strings that must be translated are processed by this bean.
Name edsCoreMsg
Class org.edorasframework.core.locale.impl.PrefixResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The core message handler, delegates to the global message handler but prefixes all keys with 'org.edorasframework.core.'
Name edsLocale
Class org.edorasframework.core.locale.impl.ProviderLocalisationController
Implements/Extends org.edorasframework.core.locale.LocalisationController
Description The global localisation controller, delegates to a bean named 'edsLocaleProvider' which must implement LocalisatorProvider.
Name edsLocaleProvider
Class org.edorasframework.core.locale.impl.DirectLocalisatorProvider
Implements/Extends org.edorasframework.core.locale.LocalisatorProvider
Description The localisator provider used by the localisation controller.
Name edsUser
Class org.edorasframework.core.security.DummyUserInfo
Implements/Extends org.edorasframework.core.security.UserInfo
Description Informations about the current User.
Name edsMetaModel
Class org.edorasframework.core.metamodel.impl.DefaultMetaModel
Implements/Extends org.edorasframework.core.metamodel.MetaModel
Description The meta model implementation.
Name edsMetaDataFinder
Class org.edorasframework.core.metamodel.MetaDataFinder
Implements/Extends
Description This allows to provide additional meta informations about classes and their properties.
Name edsDialogHandler
Class org.edorasframework.core.locale.impl.LogDialogHandler
Implements/Extends org.edorasframework.core.locale.DialogHandler
Description The dialog handler implementation.
Name edsElEnvironment
Class org.edorasframework.core.el.impl.SimpleElEnvironment
Implements/Extends org.edorasframework.core.el.ElEnvironment
Description This provides that global access point for using EL expressions.
Name
Class org.edorasframework.core.description.impl.DescriptionScanner
Implements/Extends
Description Scans classes for Description typed fields and provides description resolvers to for them.
Name edsAddBeanPostProcessor
Class org.edorasframework.core.config.add.AddBeansPostProcessor
Implements/Extends org.edorasframework.core.config.add.AddBeansPostProcessor
Description Bean post processor for add beans that are dynamically added to their target beans.
Name edsAddBeanDescriptionResolver
Class org.edorasframework.core.description.impl.ListDescriptionResolver
Implements/Extends org.edorasframework.core.description.impl.ListDescriptionResolver
Description Default description resolver for descriptions added by the core namespace handler.
Name edsDescriptionProvider
Class org.edorasframework.core.description.impl.DefaultDescriptionProvider
Implements/Extends org.edorasframework.core.description.DescriptionProvider
Description The description provider bean.
Name edsDescriptionProviderDao
Class org.edorasframework.core.description.impl.NullDescriptionProviderDao
Implements/Extends org.edorasframework.core.description.DescriptionProviderDao
Description The description provider dao
Name edsValidator
Class org.edorasframework.core.metamodel.impl.NullValidator
Implements/Extends org.edorasframework.core.metamodel.BeanValidator
Description Validates the contents of beans.

C.1.2. Spring beans in edsWeb

Definitions of the spring beans in the web part of the edoras framework.

Name edsAppCtrl
Class org.edorasframework.core.config.ApplicationContextController
Overrides definition from edsCore
Implements/Extends
Description Set the application context control into web mode.
Name edsWebMsg
Class org.edorasframework.core.locale.impl.PrefixResourceBundle
Implements/Extends java.util.ResourceBundle org.edorasframework.core.locale.MessageHandler
Description The web message handler, delegates to the global message handler but prefixes all keys with 'org.edorasframework.web.'
Name edsLocale
Class org.edorasframework.web.locale.JsfLocalisationController
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.locale.LocalisationController
Description Set the global localisation controller to use JSF and to delegate to a bean named 'edsLocaleProvider'.
Name edsPhaseListenerBeanPostProcessor
Class org.edorasframework.web.util.PhaseListenerBeanPostProcessor
Implements/Extends
Description Register a phase listener post processor, this causes spring beans which implement PhaseListener to be automatically registered in JSF to be a phase listener.
Name edsWebHtmlSec
Class org.edorasframework.websecurity.impl.NullHtmlSecurisator
Implements/Extends org.edorasframework.websecurity.HtmlSecurisator
Description Set the HTML securisator which removes any potentially dangerous tags and attributes from user provided HTML code.
Name edsWebLayoutManager
Class org.edorasframework.web.entity.LayoutManager
Implements/Extends org.edorasframework.web.entity.LayoutManager
Description The web layout manager that saved the available layouts.
Name edsWebCurrentLayout
Class org.edorasframework.web.entity.CurrentLayout
Implements/Extends org.edorasframework.web.entity.CurrentLayout
Description The web layout controller that saves the current layout during page creation.
Name edsDialogHandler
Class org.edorasframework.web.locale.JsfMessageDialogHandler
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.locale.DialogHandler
Description A dialog handler that shows dialogs using the JSF message functionality.
Name edsElEnvironment
Class org.edorasframework.web.util.JsfFactories
Overrides definition from edsCore
Implements/Extends org.edorasframework.core.el.ElEnvironment
Description An EL environment that bases on the EL implementation provided by JSF.
Name edsWebSecurity
Class org.edorasframework.web.security.impl.DefaultAccessSecurisator
Implements/Extends
Description