o

Tag Library Information 
InfoValue
ID (tag prefix)o
URIomnifaces
Tag Summary 
TagDescription
cache

The <o:cache> component allows to cache a fragment of rendered markup. The first request for a page that has this component on it will cause this markup to be put into the cache. Then for subsequent requests the cached content is used directly and none of the components, backing beans and services that were used to generate this content in the first place will be consulted.

Caching can take place in application scope, or in session scope. For individual fragments a time can be specified for which the cached content is valid. After this time is elapsed, the very first request to the page containing the cache component in question will cause new content to be rendered and put into the cache. A default time can be set per scope in web.xml.

For each scope a maximum capacity can be set. If the capacity for that scope is exceeded, an element will be removed following a least recently used policy (LRU).

Via a cache provider mechanism an alternative cache implementation can be configured in web.xml. The default cache is based on LruCache.

Setting a custom caching provider

A custom caching provider can be set by using the org.omnifaces.CACHE_PROVIDER context parameter in web.xml to point to an implementation of org.omnifaces.component.output.cache.CacheProvider. For example:

 <context-param>
     <param-name>org.omnifaces.CACHE_PROVIDER</param-name>
     <param-value>com.example.MyProvider</param-value>
 </context-param>
 

The default provider, org.omnifaces.component.output.cache.DefaultCacheProvider can be used as an example.

Global settings

For the default provider, the maximum capacity and the default time to live can be specified for the supported scopes "session" and "application". If the maximum capacity is reached, an entry will be evicted following a least recently used policy. The default time to live specifies for how long entries are considered to be valid. A value for the time attribute on this component will override this global default time to live. The following context parameters can be used in web.xml:

All available context parameters
org.omnifaces.CACHE_SETTING_APPLICATION_MAX_CAPACITY Sets the maximum number of elements that will be stored per web module (application scope). Default: no limit
org.omnifaces.CACHE_SETTING_SESSION_MAX_CAPACITY Sets the maximum number of elements that will be stored per session. Default: no limit.
org.omnifaces.CACHE_SETTING_APPLICATION_TTL Sets the maximum amount of time in seconds that cached content is valid for the application scope. Can be overriden by individal cache components. Default: no limit.
org.omnifaces.CACHE_SETTING_SESSION_TTL Sets the maximum amount of time in seconds that cached content is valid for the session scope. Can be overriden by individal cache components. Default: no limit.
org.omnifaces.CACHE_INSTALL_BUFFER_FILTER Boolean that when true installs a Servlet Filter (Servlet 3.0+ only) that works in conjunction with the useBuffer attribute of the Cache component to enable an alternative way to grab the content that needs to be cached. This is a convenience setting that is a short-cut for installing the org.omnifaces.servlet.BufferedHttpServletResponse filter manually. If more finegrained control is needed regarding which place in the filter chain the filter appears and which resources it exactly filters, this setting should not be used and the mentioned filter should be manually configured. Default: false.
cacheValueCacheValue is a replacement for ui:param and c:set that only evaluates a value expression once and thereafter resolves it from the cache.

A CacheValue piggybacks onto a parent Cache component for the control of caching scope and other parameters.

componentIdParam

The <o:componentIdParam> component allows to render just one or more components on a view via a GET parameter.

Components can be identified via both their client id or simple component id. Via the former it's possible to e.g. render only a specific row in a table. For specific cases, it's possible to render only the parent component and omit any children.

Among the use cases for this is creating simple mashups from various Faces based views, and scripts needing to obtain markup for specific components on an initial (non-faces) request.

Note that this is a rather specialized component and for many common use cases the user is advised to investigate if the existing AJAX and partial page requests in Faces don't already cover the requirements. For the moment this component only supports the direct output of the original markup and does not wrap it into any "partial response" envelope.

compositeConverter

The o:compositeConverter allows multiple converters to be chained together.

Usage

This converter is available by <o:compositeConverter> tag.

 <h:inputText value="#{bean.value}">
     <o:compositeConverter converterIds="trimConverter, sanitizeConverter, entityConverter" />
 </h:inputText>
 

Execution Order

The converters are executed in the order they are defined in the converterIds attribute during the getAsObject and in reverse order during the getAsString.

  • getAsObject: Executed 1st → 2nd → 3rd. The result of the first converter is passed as the input to the next converter.
  • getAsString: Executed 3rd → 2nd → 1st. The result of the last converter is passed as the input to the previous converter to ensure symmetry.
conditionalComment

The <o:conditionalComment> component renders a conditional comment. Conditional comments are an IE specific feature which enables the developer to (out)comment blocks of HTML depending on whether the client is using IE and if so even which version. They are often seen in combination with CSS stylesheets like so:

 <!--[if lte IE 7]>
     <link rel="stylesheet" href="ie6-ie7.css" />
 <![endif]-->
 

However, Facelets renders the comment's contents HTML-escaped which makes it unusable.

 <!--[if lte IE 7]&gt;
     &lt;link rel=&quot;stylesheet&quot; href=&quot;ie6-ie7.css&quot; /&gt;
 &lt;![endif]-->
 

Also, if jakarta.faces.FACELETS_SKIP_COMMENTS context param is set to true then it will even not be rendered at all. You would need to workaround this with an ugly <h:outputText escape="false">.

 <h:outputText
     value="&lt;!--[if lte IE 7]&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;ie6-ie7.css&quot; /&gt;&lt;![endif]--&gt;"
     escape="false" />
 

This component is designed to solve this problem.

 <o:conditionalComment if="lte IE 7">
     <link rel="stylesheet" href="ie6-ie7.css" />
 </o:conditionalComment>
 

Note that you cannot use this with <h:outputStylesheet> as it would implicitly be relocated as direct child of <h:head>.

converter

The <o:converter> is a taghandler that extends the standard <f:converter> tag family with support for deferred value expressions in all attributes. In other words, the converter attributes are not evaluated anymore on a per view build time basis, but just on every access like as with UI components and bean properties. This has among others the advantage that they can be evaluated on a per-iteration basis inside an iterating component, and that they can be set on a custom converter without needing to explicitly register it in a tagfile.

Usage

When you specify for example the standard <f:convertDateTime> by converterId="jakarta.faces.DateTime", then you'll be able to use all its attributes such as pattern and locale as per its documentation, but then with the possibility to supply deferred value expressions.

 <o:converter converterId="jakarta.faces.DateTime" pattern="#{item.pattern}" locale="#{item.locale}" />
 

The converter ID of all standard Faces converters can be found in their javadocs. First go to the javadoc of the class of interest, then go to CONVERTER_ID in its field summary and finally click the Constant Field Values link to see the value.

JSF 2.3 compatibility

The <o:converter> is currently not compatible with converters which are managed via the managed=true attribute set on the FacesConverter annotation, at least not when using Mojarra. Internally, the converters are wrapped in another instance which doesn't have the needed setter methods specified. In order to get them to work with <o:converter>, the managed=true attribute needs to be removed, so that OmniFaces ConverterManager will automatically manage them.

criticalStylesheet

The <o:criticalStylesheet> is a component based on the standard <h:outputStylesheet> which renders a <link rel="preload" as="style"> instead of <link rel="stylesheet"> and automatically changes the rel="preload" to rel="stylesheet" during window load event. Additionally, it will automatically be moved to the very top of the head.

Usage

Just use it the same way as a <h:outputStylesheet>, with a library and name.

 <o:criticalStylesheet library="yourlibrary" name="scripts/filename.js" />
 

You can even explicitly configure third-party stylesheet resources to be loaded this way, such as PrimeFaces stylesheets.

 <o:criticalStylesheet library="primefaces" name="components.css" />
 <o:criticalStylesheet library="primefaces" name="layout.css" />
 
deferredScript

The <o:deferredScript> is a component based on the standard <h:outputScript> which defers the loading of the given script resource to the window load event. In other words, the given script resource is only loaded when the window is really finished with loading. So, the enduser can start working with the webpage without waiting for the additional scripts to be loaded. Usually, it are those kind of scripts which are just for progressive enhancement and thus not essential for the functioning of the webpage.

This will give bonus points with among others the Google PageSpeed tool, on the contrary to placing the script at bottom of body, or using defer="true" or even async="true".

Since 2.4 this will render the crossorigin attribute with a value of anonymous. Since 3.13 this will also render the integrity attribute with a base64 encoded sha384 hash as SRI, see also MDN.

Usage

Just use it the same way as a <h:outputScript>, with a library and name.

 <o:deferredScript library="yourlibrary" name="scripts/filename.js" />
 

You can use the optional onbegin, onsuccess and onerror attributes to declare JavaScript code which needs to be executed respectively right before the script is loaded, right after the script is successfully loaded, and/or when the script loading failed.

enableRestorableView

The <o:enableRestorableView> taghandler instructs the view handler to recreate the entire view whenever the view has been expired, i.e. whenever ViewHandler#restoreView(FacesContext, String) returns null and the current request is a postback. This effectively prevents ViewExpiredException on the view. This tag needs to be placed in <f:metadata> of the view.

There are however technical design limitations: the recreated view is exactly the same as during the initial request. In other words, the view has lost its state. Any modifications which were made after the original initial request, either by taghandlers or (ajax) conditionally rendered components based on some view or even session scoped variables, are completely lost. Thus, the view should be designed that way that it can be used with a request scoped bean. You can use it with a view scoped bean, but then you should add a @PostConstruct which checks if the request is a postback and then fill the missing bean properties based on request parameters.

Usage

To enable the restorable view, just add the <enableRestorableView> to the view metadata.

 <f:metadata>
     <o:enableRestorableView/>
 </f:metadata>
 

Mojarra's new stateless mode

Since Mojarra 2.1.19, about 2 months after OmniFaces introduced the <o:enableRestorableView>, it's possible to enable a stateless mode on the view by simply setting its transient attribute to true:

 <f:view transient="true">
     ...
 </f:view>
 

This goes actually a step further than <o:enableRestorableView> as no state would be saved at all. However, on those kind of pages where <o:enableRestorableView> would work just fine, this statelessness should not form any problem at all. So, if you have at least Mojarra 2.1.19 at hands, use the transient="true" instead.

form

The <o:form> is a component that extends the standard <h:form> and submits to exactly the request URI with query string as seen in browser's address. Standard Faces <h:form> submits to the view ID and does not include any query string parameters or path parameters and may therefore fail in cases when the form is submitted to a request scoped bean which relies on the same initial query string parameters or path parameters still being present in the request URI. This is particularly useful if you're using FacesViews or forwarding everything to 1 page.

Additionally, it offers in combination with the <o:ignoreValidationFailed> tag on an UICommand component the possibility to ignore validation failures so that the invoke action phase will be executed anyway.

Since version 2.1 this component also supports adding query string parameters to the action URL via nested <f:param> and <o:param>.

Since version 3.0, it will also during ajax requests automatically send only the form data which actually need to be processed as opposed to the entire form, based on the execute attribute of any nested <f:ajax>. This feature is similar to partialSubmit feature of PrimeFaces. This will reduce the request payload when used in large forms such as editable tables.

You can use it the same way as <h:form>, you only need to change h: to o:.

Use request URI

This was available since version 1.6, but since version 3.0, this has become enabled by default. So just using <o:form> will already submit to the exact request URI with query string as seen in browser's address bar. In order to turn off this behavior, set useRequestURI attribute to false.

 <o:form useRequestURI="false">
 

Include request params

When you want to include request parameters only instead of the entire request URI with query string, set the includeRequestParams attribute to true. This will implicitly set useRequestURI attribute to false.

 <o:form includeRequestParams="true">
 

Partial submit

This is the default behavior. So just using <o:form> will already cause the <f:ajax> to send only the form data which actually need to be processed. In order to turn off this behavior, set partialSubmit attribute to false.

 <o:form partialSubmit="false">
 

Add query string parameters to action URL

The standard UIForm doesn't support adding query string parameters to the action URL. This component offers this possibility via nested <f:param> and <o:param>.

 <o:form>
     <f:param name="somename" value="somevalue" />
     ...
 </o:form>
 

The <f|o:param> will override any included view or request parameters on the same name. To conditionally add or override, use the disabled attribute of <f|o:param>.

The support was added in OmniFaces 2.2.

Ignore Validation Failed

In order to properly use the <o:ignoreValidationFailed> tag on an UICommand component, its parent <h:form> component has to be replaced by this <o:form> component. See also IgnoreValidationFailed.

genericEnumConverter

The omnifaces.GenericEnumConverter is intended for use in UISelectMany components whose value is been bound to a List<E> property where E is an enum. Even though Faces has already a built-in EnumConverter, this doesn't work for a List<E> property as the generic type information E is lost during runtime. The list would be filled with unconverted String values instead which may in turn cause ClassCastException during postprocessing in the business logic.

This can be solved by using a E[] property instead of List<E> (e.g. Role[] in case of a Role enum). If this is however is not an option due to some design restrictions (e.g. JPA @ElementCollection, etc), then you'd need to create an explicit converter for the enum type like follows:

 @FacesConverter("roleConverter")
 public class RoleConverter extends EnumConverter {
     public RoleConverter() {
         super(Role.class);
     }
 }
 
 <h:selectManyCheckbox value="#{bean.selectedRoles}" converter="roleConverter">
     <f:selectItems value="#{bean.availableRoles}" />
 </h:selectManyCheckbox>
 

However, creating a new converter for every single enum type, only and only for use in UISelectMany with a List<E> property, may be a bit clumsy. This generic enum converter is intended to remove the need to create a new enum converter every time.

Usage

This converter is available by converter ID omnifaces.GenericEnumConverter. Just specify it in the converter attribute of the multi-selection component holding <f:selectItems>. example:

 <h:selectManyCheckbox value="#{bean.selectedEnums}" converter="omnifaces.GenericEnumConverter">
     <f:selectItems value="#{bean.availableEnums}" />
 </h:selectManyCheckbox>
 

Since OmniFaces 4.5 it's also available by <o:genericEnumConverter> tag.

 <h:selectManyCheckbox value="#{bean.selectedEnums}">
     <f:selectItems value="#{bean.availableEnums}" />
     <o:genericEnumConverter />
 </h:selectManyCheckbox>
 

See also:
Use enum in <h:selectManyCheckbox>

JSF 2.3

This converter is not necessary anymore since JSF 2.3 thanks to the fixes in issue 1422.

 <h:selectManyCheckbox value="#{bean.selectedEnums}">
     <f:selectItems value="#{bean.availableEnums}" />
 </h:selectManyCheckbox>
 

However, when you're having an input component without a value attribute, and thus the exact type cannot be automatically determined by simply inspecting the return type of the associated getter method, then this converter may be still useful.

 <h:selectManyCheckbox converter="omnifaces.GenericEnumConverter">
     <f:selectItems value="#{bean.availableEnums}" />
 </h:selectManyCheckbox>
 
graphicImage

The <o:graphicImage> is a component that extends the standard <h:graphicImage> with support for referencing an InputStream or byte[] property in the value attribute, optionally as a data URI.

Data URI

Set dataURI attribute to true in order to render image in data URI format.

 <o:graphicImage name="icon.png" dataURI="true" /> <!-- Faces resource as data URI -->
 <o:graphicImage value="#{bean.icon}" dataURI="true" /> <!-- byte[]/InputStream property as data URI -->
 

This basically renders the image inline in HTML output immediately during Faces render response phase. This approach is very useful for a "preview" feature of uploaded images and works also in combination with view scoped beans. This approach is however not recommended for "permanent" and/or "large" images as it doesn't offer the browser any opportunity to cache the images for reuse, ~10KB would typically be the max even less so if there are more such images on the same page.

Image streaming

When not rendered as data URI, the InputStream or byte[] property must point to a stateless @GraphicImageBean or @Named @ApplicationScoped bean. The property will namely be evaluated at the moment the browser requests the image content based on the URL as specified in HTML <img src>, which is usually a different request than the one which rendered the Faces page. E.g.

 @Named
 @RequestScoped
 public class Bean {

     private List<Image> images; // Image class should NOT have "content" property, or at least it be lazy loaded.

     @Inject
     private ImageService service;

     @PostConstruct
     public void init() {
         images = service.list();
     }

     public List<Image> getImages() {
         return images;
     }

 }
 
 @GraphicImageBean
 public class Images {

     @Inject
     private ImageService service;

     public byte[] get(Long id) {
         return service.getContent(id);
     }

 }
 
 <ui:repeat value="#{bean.images}" var="image">
     <o:graphicImage value="#{images.get(image.id)}" />
 </ui:repeat>
 

A @RequestScoped and @SessionScoped bean would theoretically work, but this is wrong design (a servlet is inherently also application scoped and stateless, not without reason). A @ViewScoped wouldn't work because the image request doesn't share the Faces view state.

In case the property is a method expression taking arguments, each of those arguments will be converted to a string HTTP request parameter and back to actual objects using the converters registered by class as available via Application#createConverter(Class). So, most of standard types like Long are already implicitly supported. In case you need to supply a custom object as argument for some reason, you need to explicitly register a converter for it yourself via @FacesConverter(forClass).

Caching

In case your "image" entity supports it, you can also supply the "last modified" property which will be used in the ETag and Last-Modified headers and in If-Modified-Since checks, hereby improving browser caching. The lastModified attribute supports both Date and Long as timestamp in milliseconds.

 <ui:repeat value="#{bean.images}" var="image">
     <o:graphicImage value="#{images.get(image.id)}" lastModified="#{image.lastModified}" />
 </ui:repeat>
 

When unspecified, then the "default resource maximum age" as set in either the Mojarra specific context parameter com.sun.faces.defaultResourceMaxAge or MyFaces specific context parameter org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES will be used, else a default of 1 week will be assumed.

Image types

When rendered as data URI, the content type will be guessed based on content header. So far, WEBP, JPEG, PNG, GIF, ICO, SVG, BMP and TIFF are recognized. If the content header is unrecognized, or when the image is rendered as regular image source, then the content type will default to "image" without any subtype. This should work for most images in most browsers. This may however fail on newer images or in older browsers. In that case, you can explicitly specify the image type via the type attribute which must represent a valid file extension. E.g.

 <o:graphicImage value="#{images.get(image.id)}" type="svg" />
 

The content type will be resolved via Faces#getMimeType(String). You can add unrecognized ones as <mime-mapping> in web.xml. E.g.

 <mime-mapping>
     <extension>svg</extension>
     <mime-type>image/svg+xml</mime-type>
 </mime-mapping>
 

SVG view modes

When serving a SVG image, you can use fragment attribute to trigger SVG view modes (beware of browser support). E.g.

 <o:graphicImage value="#{images.get(image.id)}" type="svg" fragment="svgView(viewBox(0,50,200,200))" />
 

Lazy loading

Since OmniFaces 3.10, you can set the lazy attribute to true to indicate that the referenced image should only be loaded when the window is finished loading and the image is visible in the viewport.

 <o:graphicImage ... lazy="true" />
 

This attribute is ignored when the dataURI attribute is set to true.

Design notes

The bean class name and method name will end up in the image source URL. Although this is technically harmless and not tamperable by hackers, you might want to choose a "sensible" class and method name for this purpose.

Like <h:graphicImage>, the value attribute is ignored when the name attribute is specified (for Faces resources). And, the value attribute of <o:graphicImage> does not support URLs anymore. For that, just keep using <h:graphicImage> or even plain <img>.

hashParam

The <o:hashParam> is a component that extends the standard <f:viewParam> with support for setting hash query parameter values in bean and automatically reflecting updated model values in hash query string.

The "hash query string" is the part in URL after the # which could be formatted in the same format as a regular request query string (the part in URL after the ?). An example:

 https://example.com/page.xhtml#foo=baz&bar=kaz
 

This specific part of the URL (also called hash fragment identifier) is by default not sent to the server. This component will on page load and on every window.onhashchange event send it anyway so that the Faces model gets updated, and on every Faces ajax request update the hash query string in client side when the Faces model value has changed.

Usage

It's very similar to the <o:viewParam>.

 <f:metadata>
     <o:hashParam name="foo" value="#{bean.foo}" />
     <o:hashParam name="bar" value="#{bean.bar}" />
 </f:metadata>
 

You can use the render attribute to declare which components should be updated when a hash parameter value is present.

 <f:metadata>
     <o:hashParam name="foo" value="#{bean.foo}" render="fooResult" />
     <o:hashParam name="bar" value="#{bean.bar}" />
 </f:metadata>
 ...
 <h:body>
     ...
     <h:panelGroup id="fooResult">
         ...
     </h:panelGroup>
     ...
 </h:body>
 

In case you need to invoke a bean method before rendering, e.g. to preload the rendered contents based on new hash param values, then you can observe the HashChangeEvent. See the "Events" section for an usage example.

You can use the default attribute to declare a non-null value which should be interpreted as the default value. In other words, when the current model value matches the default value, then the hash parameter will be removed.

 <f:metadata>
     <o:hashParam name="foo" value="#{bean.foo}" />
     <o:hashParam name="bar" value="#{bean.bar}" default="kaz" />
 </f:metadata>
 

When #{bean.foo} is "baz" and #{bean.bar} is "kaz" or empty, then the reflected hash query string will become https://example.com/page.xhtml#foo=baz. If #{bean.bar} is any other value, then it will appear in the hash query string.

Note that as it extends from the standard <f:viewParam>, its built-in conversion and validation functionality is also supported on this component.

Events

When the hash query string is changed by the client side, e.g. by following a #foo=baz&bar=kaz link, or by manually manipulating the URL, then a CDI HashChangeEvent will be fired which can be observed in any CDI managed bean as below:

 public void onHashChange(@Observes HashChangeEvent event) {
     String oldHashString = event.getOldValue();
     String newHashString = event.getNewValue();
     // ...
 }
 

This is useful in case you want to preload the model for whatever is rendered by <o:hashParam render>.

highlight

The <o:highlight> is a helper component which highlights all invalid UIInput components and the associated labels by adding an error style class to them. Additionally, it by default focuses the first invalid UIInput component. The <o:highlight /> component can be placed anywhere in the view, as long as there's only one of it. Preferably put it somewhere in the master template for forms.

 <h:form>
     <h:inputText value="#{bean.input1}" required="true" />
     <h:inputText value="#{bean.input2}" required="true" />
     <h:commandButton value="Submit" action="#{bean.submit}" />
 </h:form>
 <o:highlight />
 

The default error style class name is error. You need to specify a CSS style associated with the class yourself. For example,

 label.error {
     color: #f00;
 }
 input.error, select.error, textarea.error {
     background-color: #fee;
 }
 

You can override the default error style class by the styleClass attribute:

 <o:highlight styleClass="invalid" />
 

You can disable the default focus on the first invalid input element setting the focus attribute.

 <o:highlight styleClass="invalid" focus="false" />
 

Since version 2.5, the error style class will be removed from the input element and its associated label when the enduser starts using the input element.

ignoreValidationFailed

The <o:ignoreValidationFailed> taghandler allows the developer to ignore validation failures when executing an UICommand action. This taghandler must be placed inside an UICommand component and the parent UIForm must be an <o:form>. When executing an ajax action, make sure that the parent UIForm is also included in the <f:ajax execute>.

Usage

For example:

 <o:form>
     ...
     <h:commandButton value="save valid data" action="#{bean.saveValidData}">
         <o:ignoreValidationFailed />
         <f:ajax execute="@form" />
     </h:commandButton>
 </o:form>
 

Note that the model values will (obviously) only be updated for components which have actually passed the validation. Also the validation messages will still be displayed. If you prefer to not display them, then you'd need to exclude them from rendering by <f:ajax render>, or to put a proper condition in the rendered attribute.

implicitNumberConverter

This converter won't output the percent or currency symbols, that's up to the UI. This converter will implicitly infer percent or currency symbols on submitted value when absent, just to prevent an unnecessary conversion error.

Usage

This converter is available by converter ID omnifaces.ImplicitNumberConverter. Just specify it as <o:converter> nested in the component referring the Number property. For example:

 <span class="currency">
     <span class="symbol">$</span>
     <h:inputText value="#{bean.price}">
         <o:converter converterId="omnifaces.ImplicitNumberConverter" type="currency" currencySymbol="$" />
     </h:inputText>
 </span>
 

Since OmniFaces 4.5 it's also available by <o:implicitNumberConverter> tag.

 <span class="currency">
     <span class="symbol">$</span>
     <h:inputText value="#{bean.price}">
         <o:implicitNumberConverter type="currency" currencySymbol="$" />
     </h:inputText>
 </span>
 
importConstants

The <o:importConstants> taghandler allows the developer to have a mapping of all constant field values of the given fully qualified name of a type in the request scope. The constant field values are those public static final fields. This works for classes, interfaces and enums.

Usage

For example:

 public class Foo {
     public static final String FOO1 = "foo1";
     public static final String FOO2 = "foo2";
 }

 public interface Bar {
     public String BAR1 = "bar1";
     public String BAR2 = "bar2";
 }

 public enum Baz {
     BAZ1, BAZ2;
 }

 public enum Faz implements Bar {
     FAZ1, FAZ2;
 }
 

The constant field values of the above types can be mapped into the request scope as follows:

 <o:importConstants type="com.example.Foo" />
 <o:importConstants type="com.example.Bar" />
 <o:importConstants type="com.example.Baz" var="Bazzz" />
 <o:importConstants type="com.example.Faz" />
 ...
 #{Foo.FOO1}, #{Foo.FOO2}, #{Bar.BAR1}, #{Bar.BAR2}, #{Bazzz.BAZ1}, #{Bazzz.BAZ2}, #{Faz.FAZ1}, #{Faz.BAR2}
 ...
 <h:selectOneMenu>
     <f:selectItems value="#{Faz.values()}" /> <!-- FAZ1, FAZ2, BAR1, BAR2 -->
 </h:selectOneMenu>
 

The map is by default stored in the request scope by the simple name of the type as variable name. You can override this by explicitly specifying the var attribute, as demonstrated for com.example.Baz in the above example.

The resolved constants are by reference stored in the cache to improve retrieving performance. There is also a runtime (no, not compiletime as that's just not possible in EL) check during retrieving the constant value. If a constant value doesn't exist, then an IllegalArgumentException will be thrown.

Since version 4.3, you can use the loader attribute to specify an object whose class loader will be used to load the class specified in the type attribute. The class loader of the given object is resolved as specified in Utils#getClassLoader(Object). In the end this should allow you to use a more specific class when there are duplicate instances in the runtime classpath, e.g. via multiple (plugin) libraries.

Since version 4.6, when the class specified in the type attribute is an enum, such as Baz or Faz in the above example, then you can use #{Faz.members()} to exclusively access enum members rather than all constant field values.

 <h:selectOneMenu>
     <f:selectItems value="#{Faz.members()}" /> <!-- FAZ1, FAZ2 -->
 </h:selectOneMenu>
 

JSF 2.3

JSF 2.3 also offers a <f:importConstants>, however it requires being placed in <f:metadata> which may not be appropriate when you intend to import constants only from a include, tagfile or a composite component.

importFunctions

The <o:importFunctions> taghandler allows the developer to have access to all functions of the given fully qualified name of a type in the Facelet scope using the usual EL functions syntax without the need to register them in .taglib.xml file. The functions are those public static methods with a non-void return type.

Usage

For example:

 <o:importFunctions type="java.lang.Math" var="m" />
 ...
 #{m:abs(-10)}
 #{m:max(bean.number1, bean.number2)}
 

The functions prefix becomes by default the simple name of the type. You can override this by explicitly specifying the var attribute.

The resolved functions are by reference stored in the cache to improve retrieving performance.

Precaution as to multiple functions with exactly the same method name

EL functions does not support method overloading. It's therefore not possible to provide overloaded methods like Math#abs(int), Math#abs(long), Math#abs(float) and Math#abs(double) in four separate EL functions.

If there are multiple function methods discovered with exactly the same name, then the one with the least amount of parameters will be used. If there are multiple function methods with exactly the same name and amount of parameters, then the choice is unspecified (technically, JVM-dependent, the first one in the methods array as found by reflection would be picked up) and should not be relied upon. So if you absolutely need to differentiate functions in such case, give them each a different name.

Since version 4.3, you can use the loader attribute to specify an object whose class loader will be used to load the class specified in the type attribute. The class loader of the given object is resolved as specified in Utils#getClassLoader(Object). In the end this should allow you to use a more specific class when there are duplicate instances in the runtime classpath, e.g. via multiple (plugin) libraries.

Design notes

Note that the colon : operator to invoke the method is as required by EL functions spec. It's by design not easily possible to change it to the period . operator. Also note that in case of org.omnifaces.util.Faces it's considered poor practice if the same functionality is already available through the implicit EL objects #{faces}, #{facesContext}, #{view}, #{request}, etc such as #{faces.development} or #{request.contextPath} which should be preferred over #{Faces:isDevelopment()} or #{Faces:getRequestContextPath()}.

inputFile

The <o:inputFile> is a component that extends the standard <h:inputFile> and adds support for directory and maxsize attributes, along with built-in server side validation on accept and maxsize attributes.

Usage

You can use it the same way as <h:inputFile>, you only need to change h: into o: to get the extra support for accept, directory and maxsize attributes. Here's are some usage examples.

Single file selection

It is basically not different from <h:inputFile>. You might as good use it instead.

 <h:form enctype="multipart/form-data">
     <o:inputFile value="#{bean.file}" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
 </h:form>
 
 private Part file; // +getter+setter

 public void upload() {
     if (file != null) {
         var name = Servlets.getSubmittedFileName(file);
         var type = file.getContentType();
         var size = file.getSize();
         var content = file.getInputStream();
         // ...
     }
 }
 

Note that it's strongly recommended to use Servlets#getSubmittedFileName(Part) to obtain the submitted file name to make sure that any path is stripped off. Some browsers are known to incorrectly include the client side path or even a fake path along with the file name.

Multiple file selection

The multiple attribute can be set to true to enable multiple file selection. With this setting the enduser can use control/command/shift keys to select multiple files. It is basically also not different from <h:inputFile>. You might as good use it instead.

 <h:form enctype="multipart/form-data">
     <o:inputFile value="#{bean.files}" multiple="true" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
 </h:form>
 
 private List<Part> files; // +getter+setter

 public void upload() {
     if (files != null) {
         for (var file : files) {
             var name = Servlets.getSubmittedFileName(file);
             var type = file.getContentType();
             var size = file.getSize();
             var content = file.getInputStream();
             // ...
         }
     }
 }
 

Folder selection

The directory attribute can be set to true to enable folder selection. This implicitly also sets multiple attribute to true and renders an additional webkitdirectory attribute to HTML for better browser compatibility.

 <h:form enctype="multipart/form-data">
     <o:inputFile value="#{bean.files}" directory="true" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
 </h:form>
 
 private List<Part> files; // +getter+setter

 public void upload() {
     if (files != null) {
         for (var file : files) {
             var name = Servlets.getSubmittedFileName(file);
             var type = file.getContentType();
             var size = file.getSize();
             var content = file.getInputStream();
             // ...
         }
     }
 }
 

Do note that this does not send physical folders, but only files contained in those folders.

Media type filtering

The accept attribute can be set with a comma separated string of media types of files to filter in browse dialog. An overview of all registered media types can be found at IANA.

 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.losslessImageFile}" accept="image/png,image/gif" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message for="file" />
 </h:form>
 
 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.anyImageFile}" accept="image/*" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message for="file" />
 </h:form>
 
 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.anyMediaFile}" accept="audio/*,image/*,video/*" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message for="file" />
 </h:form>
 

This will also be validated in the server side using a built-in validator. Do note that the accept attribute only filters in client side and validates in server side based on the file extension, and this does thus not strictly validate the file's actual content. To cover that as well, you should in the bean's action method parse the file's actual content using the tool suited for the specific media type, such as ImageIO#read() for image files, and then checking if it returns the expected result.

The default message for server side validation of accept attribute is:

{0}: Media type of file ''{1}'' does not match ''{2}''

Where {0} is the component's label and {1} is the submitted file name and {2} is the value of accept attribute.

You can override the default message by the acceptMessage attribute:

 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.anyImageFile}" accept="image/*" acceptMessage="File {1} is unacceptable!" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message for="file" />
 </h:form>
 

Or by the custom message bundle file as identified by <application><message-bundle> in faces-config.xml. The message key is org.omnifaces.component.input.InputFile.accept.

 org.omnifaces.component.input.InputFile.accept = File {1} is unacceptable!
 

File size validation

The maxsize attribute can be set with the maximum file size in bytes which will be validated on each selected file in the client side if the client supports HTML5 File API. This validation will be performed by custom JavaScript in client side instead of by Faces in server side. This only requires that there is a <h:message> or <h:messages> component and that it has its id set.

 <o:inputFile id="file" ... />
 <h:message id="messageForFile" for="file" /> <!-- This must have 'id' attribute set! -->
 

This way the client side can trigger Faces via an ajax request to update the message component with the client side validation message. Noted should be that the file(s) will not be sent, hereby saving network bandwidth.

 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.file}" maxsize="#{10 * 1024 * 1024}" /> <!-- 10MiB -->
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message id="messageForFile" for="file" />
 </h:form>
 

This will also be validated in the server side using a built-in validator.

The default message for both client side and server side validation of maxsize attribute is:

{0}: Size of file ''{1}'' is larger than maximum of {2}

Where {0} is the component's label and {1} is the submitted file name and {2} is the value of maxsize attribute.

You can override the default message by the maxsizeMessage attribute:

 <h:form enctype="multipart/form-data">
     <o:inputFile id="file" value="#{bean.file}" maxsize="#{10 * 1024 * 1024}" maxsizeMessage="File {1} is too big!" />
     <h:commandButton value="Upload" action="#{bean.upload}" />
     <h:message id="messageForFile" for="file" />
 </h:form>
 

Or by the custom message bundle file as identified by <application><message-bundle> in faces-config.xml. The message key is org.omnifaces.component.input.InputFile.maxsize.

 org.omnifaces.component.input.InputFile.maxsize = File {1} is too big!
 
inputHidden

The <o:inputHidden> is a component that extends the standard <h:inputHidden> and changes the behavior to immediately convert, validate and update during apply request values phase, regardless of any conversion/validation errors on other UIInput components within the same form. The standard <h:inputHidden> follows the same lifecycle as other UIInput components which is in the end unintuive as hidden input fields are usually under control of the developer.

Use case 1: Imagine a form with a <h:inputHidden> and a <h:inputText>. The hidden input holds some prepopulated value of a request scoped bean which is intended to be passed through to the request scoped bean instance of the next request. However, when conversion/validation fails on the text input, then the hidden input won't update the bean property and then becomes empty. I.e. the original value gets permanently lost. This can be bypassed by using ajax to update only specific fields, but this will fail when the update of the hidden input is actually needed (e.g. because the value can possibly be adjusted in action/listener method).

Use case 2: Imagine a form with an UIInput or UICommand component whose rendered attribute relies on a request scoped bean property which is retained for the next request through a <h:inputHidden>. However, when Faces needs to decode the UIInput or UICommand component during the postback, the rendered attribute has defaulted back to false because the <h:inputHidden> hasn't yet updated the request scoped bean property yet.

This behavior cannot be achieved by using immediate="true" on <h:inputHidden>. It would only move the conversion/validation into the apply request values phase. The model still won't be updated on time.

Also, the <h:inputHidden> didn't support the readonly attribute. This is however useful when used in combination with a validator which should block the form submit. Since version 4.1, the <o:inputHidden> supports this use case by simply grabbing and validating the model value during the apply request values phase. The setter method associated with the model won't be invoked.

Usage

You can use it the same way as <h:inputHidden>, you only need to change h: into o: to get the "immediate v2.0" behavior.

 <h:form>
     <o:inputHidden value="#{bean.hidden}" />
     ...
 </h:form>
 

When using ajax, don't forget to make sure that the component is also covered by the execute attribute.

link

The <o:link> is a component that extends the standard <h:link> and allows including the request query string parameters of the current URL into the link's target URL. Standard Faces <h:link> does not include any query string parameters which are not declared as view parameters. This is particularly useful if you expect some state in the target page and don't want to repeat <f|o:param> all over place.

You can use it the same way as <h:link>, you only need to change h: to o:.

Include request params

When you want to include request query string parameters of the current URL into the link's target URL, set the includeRequestParams attribute to true.

 <o:link value="Go to some page with same query string" outcome="some-page" includeRequestParams="true">
 
listConverter

The omnifaces.ListConverter is intented for use in specialized selection components which doesn't use SelectItems as the source for their selectable items, but work directly via a List of entities, and therefore the SelectItemsConverter isn't usable on them.

This converter allows you to populate a selection component with complex Java objects and have Faces convert those automatically back without the need to provide a custom converter which may need to do the job based on possibly expensive service/DAO operations. This converter automatically converts based on the #toString() of the selected item.

Usage

This converter is available by converter ID omnifaces.ListConverter and should be used in combination with <o:converter> in order to be able to pass the List source to it, which it can use for conversion. Here's a basic usage example with PrimeFaces <p:pickList>, which is one of the few select components which doesn't use SelectItems as the source, but work directly via a List.

 <p:pickList value="#{bean.dualListModel}" var="entity" itemValue="#{entity}" itemLabel="#{entity.someProperty}">
     <o:converter converterId="omnifaces.ListConverter" list="#{bean.dualListModel.source}" />
 </p:pickList>
 

Since OmniFaces 4.5 it's also available by <o:listConverter> tag.

 <p:pickList value="#{bean.dualListModel}" var="entity" itemValue="#{entity}" itemLabel="#{entity.someProperty}">
     <o:listConverter" list="#{bean.dualListModel.source}" />
 </p:pickList>
 

Make sure that your entity has a good toString() implementation

For detail, refer the javadoc of SelectItemsConverter and substitute "SelectItemsConverter" by "ListConverter" and "SelectItemsIndexConverter" by "ListIndexConverter".

listIndexConverter

The omnifaces.ListIndexConverter is a variant of the ListConverter which automatically converts based on the position (index) of the selected item in the list instead of the #toString() of the selected item.

Usage

This converter is available by converter ID omnifaces.ListIndexConverter and should be used in combination with <o:converter> in order to be able to pass the List source to it, which it can use for conversion. Here's a basic usage example with PrimeFaces <p:pickList>, which is one of the few select components which doesn't use SelectItems as the source, but work directly via a List.

 <p:pickList value="#{bean.dualListModel}" var="entity" itemValue="#{entity}" itemLabel="#{entity.someProperty}">
     <o:converter converterId="omnifaces.ListIndexConverter" list="#{bean.dualListModel.source}" />
 </p:pickList>
 

Since OmniFaces 4.5 it's also available by <o:listIndexConverter> tag.

 <p:pickList value="#{bean.dualListModel}" var="entity" itemValue="#{entity}" itemLabel="#{entity.someProperty}">
     <o:listIndexConverter" list="#{bean.dualListModel.source}" />
 </p:pickList>
 

Pros and cons as compared to ListConverter

For detail, refer the javadoc of SelectItemsIndexConverter and substitute "SelectItemsIndexConverter" by "ListIndexConverter" and "SelectItemsConverter" by "ListConverter".

loadBundle

The <o:loadBundle> taghandler basically extends the standard <f:loadBundle> with a new loader attribute allowing you to explicitly set the desired ClassLoader where the resource bundle should be looked up. Also the Locale of the bundle is obtained with better default values than the default Faces implementation.

You can use the loader attribute to specify an object whose class loader will be used to load the resource bundle specified in the basename attribute. The class loader of the given object is resolved as specified in Utils#getClassLoader(Object). In the end this should allow you to use a more specific resource bundle when there are duplicate instances in the runtime classpath, e.g. via multiple (plugin) libraries.

The locale of the resource bundle is obtained as specified in Faces#getLocale().

Usage

You can use it the same way as <f:loadBundle>, you only need to change f: into o: to get the extra support for loader attribute and the improved locale resolving.

massAttribute

The <o:massAttribute> sets an attribute of the given name and value on all nested components, if they don't already have an attribute set. On boolean attributes like disabled, readonly and rendered, any literal (static) attribute value will be ignored and overridden. Only if they have already a value expression #{...} as attribute value, then it won't be overridden. This is a technical limitation specifically for boolean attributes as they don't default to null.

Usage

For example, the following setup

 <o:massAttribute name="disabled" value="true">
     <h:inputText id="input1" />
     <h:inputText id="input2" disabled="true" />
     <h:inputText id="input3" disabled="false" />
     <h:inputText id="input4" disabled="#{true}" />
     <h:inputText id="input5" disabled="#{false}" />
 </o:massAttribute>
 
will set the disabled="true" attribute in input1, input2 and input3 as those are the only components without a value expression on the boolean attribute.

As another general example without booleans, the following setup

 <o:massAttribute name="styleClass" value="#{component.valid ? '' : 'error'}">
     <h:inputText id="input1" />
     <h:inputText id="input2" styleClass="some" />
     <h:inputText id="input3" styleClass="#{'some'}" />
     <h:inputText id="input4" styleClass="#{null}" />
 </o:massAttribute>
 
will only set the styleClass="#{component.valid ? '' : 'error'}" attribute in input1 as that's the only component on which the attribute is absent. Do note that the specified EL expression will actually be evaluated on a per-component basis.

To target a specific component (super)class, use the target attribute. The example below skips labels (as that would otherwise fail in the example below because they don't have the valid property):

 <o:massAttribute name="styleClass" value="#{component.valid ? '' : 'error'}" target="jakarta.faces.component.UIInput">
     <h:outputLabel for="input1" />
     <h:inputText id="input1" />
     <h:outputLabel for="input2" />
     <h:inputText id="input2" />
     <h:outputLabel for="input3" />
     <h:inputText id="input3" />
 </o:massAttribute>
 

Since OmniFaces 3.10, the target attribute supports a commaseparated string.

messages

The <o:messages> is a component that extends the standard <h:messages> with the following new features:

Multiple for components

Possibility to specify multiple client IDs space separated in the for attribute. The example below would only display messages for input1 and input3:

 <h:form>
     <o:messages for="input1 input3" />
     <h:inputText id="input1" />
     <h:inputText id="input2" />
     <h:inputText id="input3" />
     <h:inputText id="input4" />
 </h:form>
 

It can even refer non-input components which in turn contains input components. The example below would only display messages for input1 and input2:

 <h:form>
     <o:messages for="inputs" />
     <h:panelGroup id="inputs">
         <h:inputText id="input1" />
         <h:inputText id="input2" />
     </h:panelGroup>
     <h:inputText id="input3" />
     <h:inputText id="input4" />
 </h:form>
 

You can even combine them. The example below would only display messages for input1, input2 and input4.

 <h:form>
     <o:messages for="inputs input4" />
     <h:panelGroup id="inputs">
         <h:inputText id="input1" />
         <h:inputText id="input2" />
     </h:panelGroup>
     <h:inputText id="input3" />
     <h:inputText id="input4" />
 </h:form>
 

Displaying single message

Show a single custom message whenever the component has received any faces message. This is particularly useful when you want to display a global message in case any of the in for specified components has a faces message. For example:

 <o:messages for="form" message="There are validation errors. Please fix them." />
 <h:form id="form">
     <h:inputText id="input1" /><h:message for="input1" />
     <h:inputText id="input2" /><h:message for="input2" />
     <h:inputText id="input3" /><h:message for="input3" />
 </h:form>
 

HTML escaping

Control HTML escaping by the escape attribute.

 <o:messages escape="false" />
 

Beware of potential XSS attack holes when user-controlled input is redisplayed through messages!

Iteration markup control

Control iteration markup fully by the var attribute which sets the current FacesMessage in the request scope and disables the default table/list rendering. For example,

 <dl>
     <o:messages var="message">
         <dt>#{message.severity}</dt>
         <dd title="#{message.detail}">#{message.summary}</dd>
     </o:messages>
 </dl>
 

Note: the iteration is by design completely stateless. It's therefore not recommended to nest form components inside the <o:messages> component. It should be used for pure output only, like as the standard <h:messages>. Plain output links are however no problem. Also note that the message and escape attributes have in this case no effect. With a single message, there's no point of iteration. As to escaping, just use <h:outputText escape="false"> the usual way.

Design notice

The component class is named OmniMessages instead of Messages to avoid confusion with the Messages utility class.

methodParam

The <o:methodParam> is a tag handler that can be used to pass a method expression as attribute into a Facelets tag. By default this is not possible, and the expression that's intended to be a method expression will be created and made available as a value expression.

This handler wraps a value expression that's actually a method expression by another value expression that returns a method expression that gets the value of first value expression, which as "side-effect" executes the original method expression. This somewhat over-the-top chain of wrapping is done so a method expression can be passed as attribute into a Facelet tag.

moveComponent

The <o:moveComponent> component is a utility component via which components, facets and behaviors can be moved at runtime to a target component in various ways. This allows for simple programmatic composition of components using a declarative page author centric approach.

The destination of a move operation is specified in terms of a location that's relative to a given target component. The following shows a list of supported destinations:

  • BEFORE - Component is moved right before target component, i.e. as a sibling with an index that's 1 position lower.
  • ADD_FIRST - Component is added as the first child of the target component, any other children will have their index increased by 1.
  • ADD_LAST - Component is added as the last child of the target component, any other children will stay at their original location.
  • FACET - Component will be moved to the facet section of the target component under the name denoted by "facet".
  • BEHAVIOR - A Behavior will be moved to the behavior section of the target component.
  • AFTER - Component is moved right after target component, i.e. as a sibling with an index that's 1 position higher.
notification

The <o:notification> is a UIComponent which integrates the browser Web Notifications API with SSE (Server-Sent Events) based push. It opens a one-way (server to client) SSE connection and shows incoming push messages as browser notifications.

Prerequisites

This component requires the PWAResourceHandler to be activated by adding the following line to the <h:head> because it provides the service worker mandatory for cross-platform notification support via ServiceWorkerRegistration.showNotification():

 <link rel="manifest" href="#{resource['omnifaces:manifest.webmanifest']}" />
 

The browser notification permission must be requested via a user gesture before any notification can be shown:

 <button type="button" onclick="OmniFaces.Notification.requestPermission()">Enable Notifications</button>
 

The CDI backing bean must have at least one @Push(type=NOTIFICATION) qualified injection point using the channel name matching the channel attribute of this component, so that the SseEndpoint will be auto-activated.

Basic Usage

Declare the <o:notification> tag in the Faces view with a channel name.

 <o:notification channel="notifications" />
 

In the server side, inject the push context and send notification messages created via Notification#createNotificationMessage(String, String).

 @Inject @Push(type=NOTIFICATION)
 private PushContext notifications;

 public void sendNotification() {
     notifications.send(Notification.createNotificationMessage("Order shipped", "Your order #1234 has been shipped."));
 }
 

You can also add a URL so that clicking the notification will navigate to it:

 notifications.send(Notification.createNotificationMessage("Order shipped", "Your order has been shipped.", "https://example.com/orders/1234"));
 

Relative URLs are also accepted:

 notifications.send(Notification.createNotificationMessage("Order shipped", "Your order has been shipped.", "/orders/1234"));
 

User-targeted Notifications

The optional user attribute can be set to the unique identifier of the logged-in user, so that notifications can be targeted to a specific user.

 <o:notification channel="notifications" user="#{request.remoteUser}" />
 

The notification can then be sent to a specific user:

 notifications.send(Notification.createNotificationMessage("New message", "You have a new message."), recipientUserId);
 

Display behavior

By default, each new notification replaces the previous one from the same component. To let notifications stack independently instead, set the stacked attribute to true:

 <o:notification channel="notifications" stacked="true" />
 

The requireInteraction attribute controls whether the notification remains visible until the user explicitly interacts with it (click or dismiss), rather than auto-closing after a timeout. This is useful for important alerts that should not be missed:

 <o:notification channel="alerts" requireInteraction="true" />
 

The silent attribute suppresses the device's notification sound and vibration:

 <o:notification channel="updates" silent="true" />
 

Event Handlers

The <o:notification> supports click and close event handlers.

 <o:notification channel="notifications" onclick="handleClick" onclose="handleClose" />
 

The event's detail object contains data and tag. The data object contains the channel name and the optional url. The tag is set to the component's client ID (when not #setStacked(boolean) stacked) and is used by the browser for notification deduplication: a new notification with the same tag replaces the previous one instead of stacking.

 function handleClick(event) {
     console.log("Channel: " + event.detail.data.channel);
     console.log("URL (if any): " + event.detail.data.url);
     console.log("Tag (if not stacked): " + event.detail.tag);
 }
 function handleClose(event) {
     console.log("Channel: " + event.detail.data.channel);
     console.log("Tag (if not stacked): " + event.detail.tag);
 }
 

When you need to invoke a server-side action on notification click, use <h:commandScript> to bridge the client-side event to the server. For example, to mark a notification as read when the user clicks it:

 <o:notification channel="notifications" onclick="handleNotificationClick" />
 <h:form>
     <h:commandScript name="markAsRead" action="#{notificationBean.markAsRead}" />
 </h:form>
 

With this handler:

 function handleNotificationClick(event) {
     markAsRead({ "notification.url": event.detail.data?.url });
 }
 

And this bean:

 public void markAsRead() {
     var url = Faces.getRequestParameter("notification.url");
     // ...
 }
 

JavaScript API

The current permission can be checked via OmniFaces.Notification.getPermission(), which returns "granted", "denied", "default", or "unsupported".

 const notificationPermission = OmniFaces.Notification.getPermission();
 

You can use OmniFaces.Notification.show to programmatically show notifications using JavaScript. The first argument is the channel name, the second the title, the optional third the body, and the optional fourth a URL:

 OmniFaces.Notification.show("notifications", "Please wait ...");
 OmniFaces.Notification.show("notifications", "Hello!", "This is a notification.");
 OmniFaces.Notification.show("notifications", "Click me!", "Opens a link.", "https://omnifaces.org");
 

Platform limitations

The icon attribute is passed to the Notifications API, but custom notification icons are not guaranteed to work across all platforms. As of March 2026, macOS and Linux with GNOME always display the browser's own application icon instead, due to OS/desktop-environment-level policies. Custom icons do work on Windows and Android. Use PNG format at 192x192 or larger for best results.

 <o:notification channel="alerts" icon="#{resource['icons/alert.png']}" />
 
onloadScript

The <o:onloadScript is a component that extends the standard <h:outputScript> which will be executed in the end of the HTML body (thus when all HTML elements are initialized in the HTML DOM tree) and will re-execute its script body on every ajax request. This is particularly useful if you want to re-execute a specific helper script to manipulate the HTML DOM tree, such as (re-)adding fancy tooltips, performing highlights, etcetera, also after changes in the HTML DOM tree on ajax responses.

You can put it anywhere in the view, it will always be relocated to the end of body.

 <o:onloadScript>alert('OnloadScript is invoked!');</o:onloadScript>
 

The <o:onloadScript> is implicitly relocated to the end of the <body>, exactly like as <h:outputScript target="body"> does. So it's always executed when the entire <body> is finished populating and thus you don't need a window.onload or a $(document).ready() in there. Again, the difference with <h:outputScript target="body"> is that the <o:onloadScript> is also executed on every ajax request.

outputFormat

The <o:outputFormat> is a component that extends the standard <h:outputFormat> with support for capturing the output and exposing it into the request scope by the variable name as specified by the var attribute.

You can use it the same way as <h:outputFormat>, you only need to change h: into o: to get the extra support for var attribute. Here's are some usage examples:

 <o:outputFormat value="#{i18n['link.title']}" var="_link_title">
     <f:param value="#{bean.foo}" />
     <f:param value="#{bean.bar}" />
 </o:outputFormat>
 <h:commandLink value="#{i18n['link.value']}" title="#{_link_title}" />
 
 <o:outputFormat value="#{bean.number}" var="_percentage">
     <f:convertNumber type="percent" />
 </o:outputFormat>
 <div title="Percentage: #{_percentage}" />
 

Make sure that the var attribute value doesn't conflict with any of existing variable names in the current EL scope, such as managed bean names. It would be a good naming convention to start their names with _.

outputLabel

The <o:outputLabel> is a component that extends the standard <h:outputLabel> with support for automatically setting its value as the label of the component identified by its for attribute (if any). This way there's no need to duplicate the very same label into the label attribute of the input component. After submitting the form without having entered a value, a validation message is posted that should contain the label printed before the input instead of some generated ID.

You can use it the same way as <h:outputLabel>, you only need to change h: into o:.

param

The <o:param> is a component that extends the standard UIParameter to implement ValueHolder and thus support a Converter to convert the supplied value to string, if necessary.

You can use it the same way as <f:param>, you only need to change f: into o: to get the extra support for a Converter by usual means via the converter attribute of the tag, or the nested <f:converter> tag, or just automatically if a converter is already registered for the target class via @FacesConverter(forClass).

Also, if no value is specified, but children are present, then the encoded output of children will be returned as param value. This is useful when you want to supply Faces components or HTML as parameter of an unescaped <h:outputFormat>. For example,

 <h:outputFormat value="#{bundle.paragraph}" escape="false">
     <o:param><h:link outcome="contact" value="#{bundle.contact}" /></o:param>
 </h:outputFormat>
 

with this bundle

 paragraph = Please {0} for more information.
 contact = contact us
 

will result in the link being actually encoded as output format parameter value.

pathParamThe <o:pathParam> is a component that extends the OmniFaces Param to support MultiViews feature of FacesViews. It is done by rendering the supplied parameters of such components as <h:link> and <h:button> among others as path parameters and not as query parameters as otherwise will be produced by <o:param> and <f:param> tags.

The component has built-in support for a Converter to convert the supplied value to string by usual means via the converter attribute of the tag, or the nested <f:converter> tag, or just automatically if a converter is already registered for the target class via @FacesConverter(forClass).

This component doesn't support returning encoded output of its children as parameter value in case no value is present. This feature is provided by Param component instead.

Also, the name attribute must not be specified for this component as it already evaluates to a predefined one.

This component is used to create bookmarkable URLs via standard outcome target components that take into account <o:pathParam> tags nested in the components. The path parameters will be rendered in the order they were declared for a view id that is defined as a multi view and if the view was not defined as a multi view then they won't be rendered at all. Additionally, declaring path parameters for a non-multi view will be logged as a warning and a faces warning message will be added for any stage different from Production.

In the following example the link to the multi view page will be rendered with two path parameters:

 <h:link value="Link" outcome="multiview-supported-path">
     <o:pathParam value="first" />
     <o:pathParam value="second" />
 </h:link>
 
The code above will be rendered as: <a id="..." name="..." href="/context-path/multiview-supported-path/first/second">Link</a>. The path parameters will be available via @Inject @Param(pathIndex=0) private String first; and @Inject @Param(pathIndex=1) private String second; the usual way.
requiredCheckboxValidator

The omnifaces.RequiredCheckboxValidator is intented to solve a peculiar problem with required="true" attribute of UISelectBoolean components like <h:selectBooleanCheckbox>. If you want to require the user to tick the desired checkbox, you would expect that setting required="true" is sufficient. But it is not, the validation wil always pass.

As for every other UIInput component the default required="true" validator would only check if the value is actually filled and been sent to the server side, i.e. the value is not null nor empty. In case of a <h:selectBooleanCheckbox>, which accepts Boolean or boolean properties only, EL will coerce the unchecked value to Boolean.FALSE during apply request values phase right before validations phase. This value is not null nor empty! Thus, the required attribute of the <h:selectBooleanCheckbox> is fairly pointless. It would always pass the validation and thus never display the desired required message in case of an unticked checkbox.

Usage

This validator is available by validator ID omnifaces.RequiredCheckboxValidator. Just specify it as <f:validator> of the boolean selection component:

 <h:selectBooleanCheckbox id="agree" value="#{bean.agree}" requiredMessage="You must agree!">
     <f:validator validatorId="omnifaces.RequiredCheckboxValidator" />
 </h:selectBooleanCheckbox>
 

Since OmniFaces 4.5 it's also available by <o:requiredCheckboxValidator> tag.

 <h:selectBooleanCheckbox id="agree" value="#{bean.agree}" requiredMessage="You must agree!">
     <o:requiredCheckboxValidator" />
 </h:selectBooleanCheckbox>
 

The validator will use the message as specified in requiredMessage. If it's absent, then it will use the default required message as specified in custom <message-bundle> in faces-config.xml. If it's absent, then it will default to

{0}: a tick is required"
resolveComponent

The <o:resolveComponent> component is a utility component via which a component can be looked up by its ID and a reference to it put in either the "facelet scope" (default) or the request scope.

resourceInclude

The <o:resourceInclude> component can be used to catch the output from a JSP or Servlet resource and render it as output to the Faces writer. In effect, this allows you to include both Servlets and JSP pages in e.g. Facelets.

Note that this isn't recommended as a lasting solution, but it might ease a migration from legacy JSP with smelly scriptlets and all on them to a more sane and modern Facelets application.

scriptErrorHandler

The <o:scriptErrorHandler> is a component that catches uncaught JavaScript errors and unhandled promise rejections on the client and sends them to the server via navigator.sendBeacon(), where they are fired as ScriptError CDI events. This allows server-side logging of client-side JavaScript errors without any additional endpoint boilerplate.

Usage (client)

Just put the component in the <h:head> of the master template. It will automatically move itself to head even when placed elsewhere, but placing it in <h:head> makes the intent explicit.

 <h:head>
     <o:scriptErrorHandler />
 </h:head>
 

This will register window.onerror and unhandledrejection event listeners which report any uncaught client-side errors to the server. You can optionally specify a CSS selector via ignoreSelector to suppress error reporting when a matching element exists in the document (e.g. on error pages where errors are expected).

 <o:scriptErrorHandler ignoreSelector="body.errorPage" />
 

Usage (server)

Create a CDI bean (typically application scoped) that observes the ScriptError event.

 @ApplicationScoped
 public class ScriptErrorObserver {

     private static final Logger logger = Logger.getLogger(ScriptErrorObserver.class.getName());

     public void onScriptError(@Observes ScriptError error) {
         logger.warning(error.toString());
     }
 }
 

The ScriptError event provides the following information:

  • ScriptError#pageURL(): the URL of the page where the error occurred.
  • ScriptError#errorMessage(): the error message.
  • ScriptError#sourceURL(): the URL of the script file where the error occurred.
  • ScriptError#lineNumber(): the line number in the script.
  • ScriptError#columnNumber(): the column number in the script.
  • ScriptError#errorName(): the error type (e.g. "TypeError", "ReferenceError").
  • ScriptError#errorStack(): the full stack trace.
  • ScriptError#remoteAddr(): the remote address.
  • ScriptError#userAgent(): the User-Agent header.
  • ScriptError#userPrincipal(): the authenticated user principal name.

Deduplication

To prevent flooding the server with repeated errors (e.g. from a requestAnimationFrame loop), the client-side script deduplicates errors by message, source URL, and line number. The deduplication queue size and expiry time can be configured via the maxRecentErrors and errorExpiry attributes.

scriptParam

The <o:scriptParam> is a component that extends the standard <f:viewParam> with support for setting results of client-side evaluated JavaScript code in bean.

Usage

It's similar to the <f:viewParam>.

 <f:metadata>
     <o:scriptParam script="new Date().getTimezoneOffset()" value="#{bean.clientTimeZoneOffset}" />
     <o:scriptParam script="window.screen.width" value="#{bean.clientScreenWidth}" />
     <o:scriptParam script="someFunctionName()" value="#{bean.resultOfSomeFunctionName}" />
 </f:metadata>
 

You can use the render attribute to declare which components should be updated when a script parameter has been set.

 <f:metadata>
     <o:scriptParam script="foo()" value="#{bean.resultOfFoo}" render="fooResult" />
 </f:metadata>
 ...
 <h:body>
     ...
     <h:panelGroup id="fooResult">
         <ui:fragment rendered="#{not empty bean.resultOfFoo}">
             The result of foo() script is: #{bean.resultOfFoo}
         </ui:fragment>
     </h:panelGroup>
     ...
 </h:body>
 

Note that as it extends from the standard <f:viewParam>, its built-in conversion and validation functionality is also supported on this component. So, the following is also possible:

 <f:metadata>
     <o:scriptParam script="window.navigator" value="#{bean.clientNavigator}" />
 </f:metadata>
 
With a clientNavigator being an instance of jakarta.json.JsonObject:
 private JsonObject clientNavigator;
 
And this converter:
 package com.example;

 import java.io.StringReader;
 import jakarta.faces.component.UIComponent;
 import jakarta.faces.context.FacesContext;
 import jakarta.faces.convert.Converter;
 import jakarta.faces.convert.ConverterException;
 import jakarta.faces.convert.FacesConverter;
 import jakarta.json.Json;
 import jakarta.json.JsonObject;

 @FacesConverter(forClass = JsonObject.class)
 public class JsobObjectConverter implements Converter<JsonObject> {

     @Override
     public String getAsString(FacesContext context, UIComponent component, JsonObject modelValue) {
         if (modelValue == null) {
             return "";
         }

         return modelValue.toString();
     }

     @Override
     public JsonObject getAsObject(FacesContext context, UIComponent component, String submittedValue) {
         if (submittedValue == null || submittedValue.isEmpty()) {
             return null;
         }

         try {
             return Json.createReader(new StringReader(submittedValue)).readObject();
         }
         catch (Exception e) {
             throw new ConverterException("Not a valid JSON object", e);
         }
     }
 }
 

Events

When the script params have been set, then any method with the PostScriptParam annotation will be fired:

 @PostScriptParam
 public void initScriptParams() {
     // ...
 }
 

This is useful in case you want to preload the model for whatever is rendered by <o:scriptParam render>.

selectItemGroups

The o:selectItemGroups is an extension of UISelectItems which allows you to iterate over a nested collection representing groups of select items. This is basically the UIComponent counterpart of jakarta.faces.model.SelectItemGroup. There is no equivalent (yet) in the standard Faces API. Currently the only way to represent SelectItemGroup in UI is to manually create and populate them in a backing bean which can end up to be quite verbose.

Usage

Below example assumes a List<Category> as value wherein Category in turn has a List<Product>.

 <h:selectOneMenu value="#{bean.selectedProduct}" converter="omnifaces.SelectItemsConverter">
     <f:selectItem itemValue="#{null}" />
     <o:selectItemGroups value="#{bean.categories}" var="category" itemLabel="#{category.name}">
         <f:selectItems value="#{category.products}" var="product" itemLabel="#{product.name}" />
     </o:selectItemGroups>
 </h:selectOneMenu>
 
selectItemsConverter

The omnifaces.SelectItemsConverter allows you to populate a selection component with complex Java model objects (entities) as value of <f:selectItems> and have Faces convert those automatically back without the need to provide a custom converter which may need to do the job based on possibly expensive service/DAO operations. This converter automatically converts based on the #toString() of the selected item.

Usage

This converter is available by converter ID omnifaces.SelectItemsConverter. Just specify it in the converter attribute of the selection component holding <f:selectItems>.

 <h:selectOneMenu value="#{bean.selectedItem}" converter="omnifaces.SelectItemsConverter">
     <f:selectItems value="#{bean.availableItems}" />
 </h:selectOneMenu>
 

Since OmniFaces 4.5 it's also available by <o:selectItemsConverter> tag.

 <h:selectOneMenu value="#{bean.selectedItem}">
     <f:selectItems value="#{bean.availableItems}" />
     <o:selectItemsConverter />
 </h:selectOneMenu>
 

Make sure that your entity has a good toString() implementation

The base converter uses by default the toString() method of the entity to uniquely identify the instance during the conversion. This is sufficient if your (abstract base) entity has a toString() implementation which looks something like this:

 @Override
 public String toString() {
     return String.format("%s[id=%d]", getClass().getSimpleName(), getId());
 }
 

By the way, you should also make sure that your entity has a good equals() and hashCode() implementation, otherwise Faces won't be able to set the right entity back in the model. Please note that this problem is in turn unrelated to the SelectItemsConverter, you would have faced the same problem when using any other converter.

If your entity can't have a good toString() implementation

However, if the entity doesn't have a toString() implementation (and thus relies on the default fqn@hashcode implementation), or the existing implementation doesn't necessarily uniquely identify the instance, and you can't implement/change it, then it is recommended to extend the SelectItemsConverter class and override only the getAsString method wherein the desired implementation is provided. For example:

 @FacesConverter("exampleEntitySelectItemsConverter")
 public class ExampleEntitySelectItemsConverter extends SelectItemsConverter {

     @Override
     public String getAsString(FacesContext context, UIComponent component, Object value) {
         Long id = (value instanceof ExampleEntity) ? ((ExampleEntity) value).getId() : null;
         return (id != null) ? String.valueOf(id) : null;
     }

 }
 

Again, you do not need to override the getAsObject() method which would only need to perform possibly expensive service/DAO operations. The SelectItemsConverter base converter will already do it automatically based on the available items and the getAsString() implementation.

An alternative is to switch to SelectItemsIndexConverter, which will convert based on the position (index) of the selected item in the list instead of the #toString() of the selected item.

selectItemsIndexConverter

The omnifaces.SelectItemsIndexConverter is a variant of the SelectItemsConverter which automatically converts based on the position (index) of the selected item in the list instead of the #toString() of the selected item.

Usage

This converter is available by converter ID omnifaces.SelectItemsIndexConverter. Just specify it in the converter attribute of the selection component holding <f:selectItems>.

 <h:selectOneMenu value="#{bean.selectedItem}" converter="omnifaces.SelectItemsIndexConverter">
     <f:selectItems value="#{bean.availableItems}" />
 </h:selectOneMenu>
 

Since OmniFaces 4.5 it's also available by <o:selectItemsIndexConverter> tag.

 <h:selectOneMenu value="#{bean.selectedItem}">
     <f:selectItems value="#{bean.availableItems}" />
     <o:selectItemsIndexConverter />
 </h:selectOneMenu>
 

Pros and cons as compared to SelectItemsConverter

This converter has the following advantages over SelectItemsConverter:

  • No need to rely on #toString() method of the object.
  • No need to extend the SelectItemsConverter when #toString() method of the object cannot be used.
  • No need to expose the object's unique key in its #toString(),if that's a problem.

This converter has the following disadvantage over SelectItemsConverter:

  • The "Validation Error: value is not valid" will never occur anymore for the case that the available select items has incompatibly changed during the postback due to a developer's mistake. The developer should make absolutely sure that exactly the same list is preserved on postback (e.g. by making it a property of a view scoped or broader scoped bean).
sitemapUrl

The <o:sitemapUrl> is a component which renders the given target URL or Faces view ID as a sitemap URL with support for adding additional query string parameters to the URL via nested <f:param> and <o:param>.

This component is largely based off the Url component behind <o:url>, but then tailored specifically for usage in sitemap.xml file. The ViewResourceHandler must be registered in faces-config.xml in order to get Faces components to run in /sitemap.xml.

Values

You can supply the sitemap URL via either the value attribute or the viewId attribute. When both are specified, the value attribute takes precedence and the viewId attribute is ignored.

Domain

When the target URL is specified as viewId, then the domain of the target URL defaults to the current domain. It is possible to provide a full qualified domain name (FQDN) via the domain attribute which the URL is to be prefixed with. This can be useful if a canonical page shall point to a different domain or a specific subdomain.

Valid formats and values for domain attribute are:

  • <o:sitemapUrl ... domain="https://example.com" />
  • <o:sitemapUrl ... domain="//example.com" />
  • <o:sitemapUrl ... domain="example.com" />
  • <o:sitemapUrl ... domain="/" />
  • <o:sitemapUrl ... domain="//" />

The domain value will be validated by URL and throw an illegal argument exception when invalid. If the domain equals /, then the URL becomes domain-relative. If the domain equals or starts with //, or does not contain any scheme, then the URL becomes scheme-relative. If the value attribute is specified, then the domain attribute is ignored.

Request parameters

You can add query string parameters to the URL via nested <f:param> and <o:param>. To conditionally add or override, use the disabled attribute of <f|o:param>.

Usage

Usage example of /sitemap.xml as a Faces view:

 <?xml version="1.0" encoding="UTF-8"?>
 <urlset
     xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
     xmlns:ui="jakarta.faces.facelets"
     xmlns:o="omnifaces"
 >
     <ui:repeat value="#{sitemapBean.products}" var="product">
         <o:sitemapUrl viewId="/product.xhtml" lastModified="#{product.lastModified}" changeFrequency="weekly" priority="1.0">
             <o:param name="id" value="#{product}" converter="productConverter" />
         </o:sitemapUrl>
     </ui:repeat>
 </urlset>
 
skipValidators

The <o:skipValidators> taghandler allows the developer to entirely skip validation when executing an UICommand or ClientBehaviorHolder action. This taghandler must be placed inside an UICommand or ClientBehaviorHolder component (client behavior holder components are those components supporting <f:ajax>).

Usage

For example, when adding a new row to the data table, you'd like to not immediately validate all empty rows.

 <h:form>
     <h:dataTable value="#{bean.items}" var="item">
         <h:column>
             <h:inputText value="#{item.value}" required="true" />
         </h:column>
     </h:dataTable>
     <h:commandButton value="add new row" action="#{bean.add}">
         <o:skipValidators />
     </h:commandButton>
     <h:commandButton value="save all data" action="#{bean.save}" />
     <h:messages />
 </h:form>
 

Note that converters will still run and that model values will still be updated. This behavior is by design.

socket

The <o:socket> is an UIComponent whith opens an one-way (server to client) web socket based push connection in client side which can be reached from server side via PushContext interface injected in any CDI/container managed artifact via @Push annotation.

Configuration

Since OmniFaces 5.2, the web socket endpoint is automatically registered when @Inject @Push PushContext is used anywhere in the application. No additional configuration is needed.

Alternatively, if you want to explicitly enable the endpoint without using @Push injection, you can set the below boolean context parameter in web.xml:

 <context-param>
     <param-name>org.omnifaces.SOCKET_ENDPOINT_ENABLED</param-name>
     <param-value>true</param-value>
 </context-param>
 

Usage (client)

Declare <o:socket> tag in the Faces view with at least a channel name and an onmessage JavaScript listener function. The channel name may not be an EL expression and it may only contain alphanumeric characters, hyphens, underscores and periods.

Here's an example which refers an existing JavaScript listener function (do not include the parentheses!).

 <o:socket channel="someChannel" onmessage="socketListener" />
 
 function socketListener(message, channel, event) {
     console.log(message);
 }
 

Here's an example which declares an inline JavaScript listener function.

 <o:socket channel="someChannel" onmessage="function(message) { console.log(message); }" />
 

The onmessage JavaScript listener function will be invoked with three arguments:

  • message: the push message as JSON object.
  • channel: the channel name, useful in case you intend to have a global listener, or want to manually control the close.
  • event: the raw MessageEvent instance, useful in case you intend to inspect it.

In case your server is configured to run WS container on a different TCP port than the HTTP container, then you can use the optional port attribute to explicitly specify the port.

 <o:socket port="8000" ... />
 

When successfully connected, the web socket is by default open as long as the document is open, and it will auto-reconnect at increasing intervals when the connection is closed/aborted as result of e.g. a network error or server restart. It will not auto-reconnect when the very first connection attempt already fails. The web socket will be implicitly closed once the document is unloaded (e.g. navigating away, close of browser window/tab, etc).

In order to successfully reconnect after a server restart, or when switching to a new server node, you need to ensure that session persistence is enabled on the server.

Usage (server)

In WAR side, you can inject PushContext via @Push annotation on the given channel name in any CDI/container managed artifact such as @Named, @WebServlet, etc wherever you'd like to send a push message and then invoke PushContext#send(Object) with any Java object representing the push message.

 @Inject @Push
 private PushContext someChannel;

 public void sendMessage(Object message) {
     someChannel.send(message);
 }
 

By default the name of the channel is taken from the name of the variable into which injection takes place. The channel name can be optionally specified via the channel attribute. The example below injects the push context for channel name foo into a variable named bar.

 @Inject @Push(channel="foo")
 private PushContext bar;
 

The message object will be encoded as JSON and be delivered as message argument of the onmessage JavaScript listener function associated with the channel name. It can be a plain vanilla String, but it can also be a collection, map and even a javabean. For supported argument types, see also Json#encode(Object).

Although web sockets support two-way communication, the <o:socket> push is designed for one-way communication, from server to client. In case you intend to send some data from client to server, just continue using Faces ajax the usual way, if necessary from JavaScript on with <h:commandScript> or perhaps <p:remoteCommand> or similar. This has among others the advantage of maintaining the Faces view state, the HTTP session and, importantingly, all security constraints on business service methods. Namely, those security constraints are not available during an incoming web socket message per se. See also a.o. WS spec issue 238.

Scopes and users

By default the web socket is application scoped, i.e. any view/session throughout the web application having the same web socket channel open will receive the same push message. The push message can be sent by all users and the application itself. This is useful for application-wide feedback triggered by site itself such as real time updates of a certain page (e.g. site-wide statistics, top100 lists, stock updates, etc).

The optional scope attribute can be set to session to restrict the push messages to all views in the current user session only. The push message can only be sent by the user itself and not by the application. This is useful for session-wide feedback triggered by user itself (e.g. as result of asynchronous tasks triggered by user specific action).

 <o:socket channel="someChannel" scope="session" ... />
 

The scope attribute can also be set to view to restrict the push messages to the current view only. The push message will not show up in other views in the same session even if it's the same URL. The push message can only be sent by the user itself and not by the application. This is useful for view-wide feedback triggered by user itself (e.g. progress bar tied to a user specific action on current view).

 <o:socket channel="someChannel" scope="view" ... />
 

The scope attribute may not be an EL expression and allowed values are application, session and view, case insensitive.

Additionally, the optional user attribute can be set to the unique identifier of the logged-in user, usually the login name or the user ID. This way the push message can be targeted to a specific user and can also be sent by other users and the application itself. The value of the user attribute must at least implement Serializable and have a low memory footprint, so putting entire user entity is not recommended.

E.g. when you're using container managed authentication or a related framework/library:

 <o:socket channel="someChannel" user="#{request.remoteUser}" ... />
 

Or when you have a custom user entity around in EL as #{someLoggedInUser} which has an id property representing its identifier:

 <o:socket channel="someChannel" user="#{someLoggedInUser.id}" ... />
 

When the user attribute is specified, then the scope defaults to session and cannot be set to application. It can be set to view, but this is kind of unusual and should only be used if the logged-in user represented by user has a shorter lifetime than the HTTP session (e.g. when your application allows changing a logged-in user during same HTTP session without invaliding it — which is in turn poor security practice). If in such case a session scoped socket is reused, undefined behavior may occur when user-targeted push message is sent. It may target previously logged-in user only. This can be solved by setting the scope to view, but better is to fix the logout to invalidate the HTTP session altogether.

When the user attribute is an EL expression and it changes during an ajax request, then the socket user will be actually switched, even though you did not cover the <o:socket> component in any ajax render/update. So make sure the value is tied to at least a view scoped property in case you intend to control it during the view scope.

In the server side, the push message can be targeted to the user specified in the user attribute via PushContext#send(Object, Serializable). The push message can be sent by all users and the application itself. This is useful for user-specific feedback triggered by other users (e.g. chat, admin messages, etc) or by application's background tasks (e.g. notifications, event listeners, etc).

 @Inject @Push
 private PushContext someChannel;

 public void sendMessage(Object message, User recipientUser) {
     Long recipientUserId = recipientUser.getId();
     someChannel.send(message, recipientUserId);
 }
 

Multiple users can be targeted by passing a Collection holding user identifiers to PushContext#send(Object, Collection).

 public void sendMessage(Object message, Group recipientGroup) {
     Collection<Long> recipientUserIds = recipientGroup.getUserIds();
     someChannel.send(message, recipientUserIds);
 }
 

Channel design hints

You can declare multiple push channels on different scopes with or without user target throughout the application. Be however aware that the same channel name can easily be reused across multiple views, even if it's view scoped. It's more efficient if you use as few different channel names as possible and tie the channel name to a specific push socket scope/user combination, not to a specific Faces view. In case you intend to have multiple view scoped channels for different purposes, best is to use only one view scoped channel and have a global JavaScript listener which can distinguish its task based on the delivered message. E.g. by sending the message in server as below:

 Map<String, Object> message = new HashMap<>();
 message.put("functionName", "someFunction");
 message.put("functionData", functionData); // Can be Map or Bean.
 someChannel.send(message);
 

Which is processed in the onmessage JavaScript listener function as below:

 function someSocketListener(message) {
     window[message.functionName](message.functionData);
 }

 function someFunction(data) {
     // ...
 }

 function otherFunction(data) {
     // ...
 }

 // ...
 

Conditionally connecting

You can use the optional connected attribute to control whether to auto-connect the web socket or not.

 <o:socket ... connected="#{bean.pushable}" />
 

It defaults to true and it's under the covers interpreted as a JavaScript instruction whether to open or close the web socket push connection. If the value of the connected or rendered attribute is an EL expression and it becomes false during an ajax request, then any opened push connection will explicitly be closed during oncomplete of that ajax request, even though you did not cover the <o:socket> component in ajax render/update. So make sure the value is tied to at least a view scoped property in case you intend to control it during the view scope.

You can also explicitly set it to false and manually open the push connection in client side by invoking OmniFaces.Push.open(channel), passing the channel name, for example in an onclick listener function of a command button which initiates a long running asynchronous task in server side. This is particularly useful on view scoped sockets which doesn't necessarily need to immediately open on page load.

 <h:commandButton ... onclick="OmniFaces.Push.open('foo')">
     <f:ajax ... />
 </h:commandButton>
 <o:socket channel="foo" scope="view" ... connected="false" />
 

In case you intend to have an one-time push and don't expect more messages, usually because you only wanted to present the result of an one-time asynchronous action in a manually opened view scoped push socket as in above example, you can optionally explicitly close the push connection from client side by invoking OmniFaces.Push.close(channel), passing the channel name. For example, in the onmessage JavaScript listener function as below:

 function someSocketListener(message, channel) {
     // ...
     OmniFaces.Push.close(channel);
 }
 

Noted should be that both ways should not be mixed. Choose either the server side way of an EL expression in connected attribute, or the client side way of explicitly setting connected="false" and manually invoking OmniFaces.Push functions. Mixing them ends up in undefined behavior because the associated Faces view state in the server side can't be notified if a socket is manually opened in client side.

Events (client)

The optional onopen JavaScript listener function can be used to listen on open of a web socket in client side. This will be invoked on the very first connection attempt, regardless of whether it will be successful or not. This will not be invoked when the web socket auto-reconnects a broken connection after the first successful connection.

 <o:socket ... onopen="socketOpenListener" />
 
 function socketOpenListener(channel) {
     // ...
 }
 

The onopen JavaScript listener function will be invoked with one argument:

  • channel: the channel name, useful in case you intend to have a global listener.

The optional onerror JavaScript listener function can be used to listen on a connection error whereby the web socket will attempt to reconnect. This will be invoked when the web socket can make an auto-reconnect attempt on a broken connection after the first successful connection. This will be not invoked when the very first connection attempt fails, or the server has returned close reason code 1000 (normal closure) or 1008 (policy violated), or the maximum reconnect attempts has exceeded. Instead, the onclose will be invoked.

 <o:socket ... onerror="socketErrorListener" />
 
 function socketErrorListener(code, channel, event) {
     if (code == 1001) {
         // Server has returned an unexpected response code. E.g. 503, because it's shutting down.
     } else if (code == 1006) {
         // Server is not reachable anymore. I.e. it's not anymore listening on TCP/IP requests.
     } else {
         // Any other reason which is usually not -1, 1000 or 1008, as the onclose will be invoked instead.
     }

     // In any case, the web socket will attempt to reconnect. This function will be invoked again.
     // Once the web socket gives up reconnecting, the onclose will finally be invoked.
 }
 

The onerror JavaScript listener function will be invoked with three arguments:

  • code: the close reason code as integer. See also RFC 6455 section 7.4.1 and CloseCodes API for an elaborate list of all close codes.
  • channel: the channel name, useful in case you intend to have a global listener.
  • event: the raw CloseEvent instance, useful in case you intend to inspect it.

The optional onclose JavaScript listener function can be used to listen on (ab)normal close of a web socket. This will be invoked when the very first connection attempt fails, or the server has returned close reason code 1000 (normal closure) or 1008 (policy violated), or the maximum reconnect attempts has exceeded. This will not be invoked when the web socket can make an auto-reconnect attempt on a broken connection after the first successful connection. Instead, the onerror will be invoked.

 <o:socket ... onclose="socketCloseListener" />
 
 function socketCloseListener(code, channel, event) {
     if (code == -1) {
         // Web sockets not supported by client.
     } else if (code == 1000) {
         // Normal close (as result of expired session or view).
     } else {
         // Abnormal close reason (as result of an error).
     }
 }
 

The onclose JavaScript listener function will be invoked with three arguments:

  • code: the close reason code as integer. If this is -1, then the web socket is simply not supported by the client. If this is 1000, then it was normally closed due to an expired session or view. Else if this is not 1000, then there may be an error. See also RFC 6455 section 7.4.1 and CloseCodes API for an elaborate list of all close codes.
  • channel: the channel name, useful in case you intend to have a global listener.
  • event: the raw CloseEvent instance, useful in case you intend to inspect it.

When a session or view scoped socket is automatically closed with close reason code 1000 by the server (and thus not manually by the client via OmniFaces.Push.close(channel)), then it means that the session or view has expired. In case of a session scoped socket you could take the opportunity to let JavaScript show a "Session expired" message and/or immediately redirect to the login page via window.location. In case of a view scoped socket the handling depends on the reason of the view expiration. A view can be expired when the associated session has expired, but it can also be expired as result of (accidental) navigation or rebuild, or when the Faces "views per session" configuration setting is set relatively low and the client has many views (windows/tabs) open in the same session. You might take the opportunity to warn the client and/or let JavaScript reload the page as submitting any form in it would throw ViewExpiredException anyway.

Events (server)

When a web socket has been opened, a new CDI SocketEvent will be fired with @Opened qualifier. When the user attribute of the <o:socket> changes, a new CDI SocketEvent will be fired with @Switched qualifier. When a web socket has been closed, a new CDI SocketEvent will be fired with @Closed qualifier. They can only be observed and collected in an application scoped CDI bean as below. Observing in a request/view/session scoped CDI bean is not possible as there's no means of a HTTP request anywhere at that moment.

 @ApplicationScoped
 public class SocketObserver {

     public void onOpen(@Observes @Opened SocketEvent event) {
         String channel = event.getChannel(); // Returns <o:socket channel>.
         Long userId = event.getUser(); // Returns <o:socket user>, if any.
         // Do your thing with it. E.g. collecting them in a concurrent/synchronized collection.
         // Do note that a single person can open multiple sockets on same channel/user.
     }

     public void onSwitch(@Observes @Switched SocketEvent event) {
         String channel = event.getChannel(); // Returns <o:socket channel>.
         Long currentUserId = event.getUser(); // Returns current <o:socket user>, if any.
         Long previousUserId = event.getPreviousUser(); // Returns previous <o:socket user>, if any.
         // Do your thing with it. E.g. updating in a concurrent/synchronized collection.
     }

     public void onClose(@Observes @Closed SocketEvent event) {
         String channel = event.getChannel(); // Returns <o:socket channel>.
         Long userId = event.getUser(); // Returns <o:socket user>, if any.
         CloseCode code = event.getCloseCode(); // Returns close reason code.
         // Do your thing with it. E.g. removing them from collection.
     }

 }
 

You could take the opportunity to send another push message to an application scoped socket, e.g. "User X has been logged in" (or out) when a session scoped socket is opened (or closed).

Security considerations

If the socket is declared in a page which is only restricted to logged-in users with a specific role, then you may want to add the URL of the push handshake request URL to the set of restricted URLs.

The push handshake request URL is composed of the URI prefix /omnifaces.socket/, followed by channel name. So, in case of for example container managed security which has already restricted an example page /user/foo.xhtml to logged-in users with the example role USER on the example URL pattern /user/* in web.xml like below,

 <security-constraint>
     <web-resource-collection>
         <web-resource-name>Restrict access to role USER.</web-resource-name>
         <url-pattern>/user/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
         <role-name>USER</role-name>
     </auth-constraint>
 </security-constraint>
 

.. and the page /user/foo.xhtml in turn contains a <o:socket channel="foo">, then you need to add a restriction on push handshake request URL pattern of /omnifaces.socket/foo like below.

 <security-constraint>
     <web-resource-collection>
         <web-resource-name>Restrict access to role USER.</web-resource-name>
         <url-pattern>/user/*</url-pattern>
         <url-pattern>/omnifaces.socket/foo</url-pattern>
     </web-resource-collection>
     <auth-constraint>
         <role-name>USER</role-name>
     </auth-constraint>
 </security-constraint>
 

As extra security, particularly for those public channels which can't be restricted by security constraints, the <o:socket> will register all so far declared channels in the current HTTP session, and any incoming web socket open request will be checked whether they match the so far registered channels in the current HTTP session. In case the channel is unknown (e.g. randomly guessed or spoofed by endusers or manually reconnected after the session is expired), then the web socket will immediately be closed with close reason code 1008 (CloseCodes#VIOLATED_POLICY). Also, when the HTTP session gets destroyed, all session and view scoped channels which are still open will explicitly be closed from server side with close reason code 1000 (CloseCodes#NORMAL_CLOSURE). Only application scoped sockets remain open and are still reachable from server end even when the session or view associated with the page in client side is expired.

Business service design hints

In case you'd like to trigger a push from business service side to an application scoped push socket, then you could make use of CDI events. First create a custom bean class representing the push event something like PushEvent below taking whatever you'd like to pass as push message.

 public final class PushEvent {

     private final String message;

     public PushEvent(String message) {
         this.message = message;
     }

     public String getMessage() {
         return message;
     }
 }
 

Then use jakarta.enterprise.inject.spi.BeanManager#getEvent() to fire the CDI event.

 @Inject
 private BeanManager beanManager;

 public void onSomeEntityChange(Entity entity) {
     beanManager.getEvent().select().fire(new PushEvent(entity.getSomeProperty()));
 }
 

Note that OmniFaces own Beans#fireEvent(Object, java.lang.annotation.Annotation...) utility method is insuitable as it is not allowed to use WAR (front end) frameworks and libraries like Faces and OmniFaces in business service (back end) side.

Finally just @Observes it in some request or application scoped CDI managed bean in WAR and delegate to PushContext as below.

 @Inject @Push
 private PushContext someChannel;

 public void onPushEvent(@Observes PushEvent event) {
     someChannel.send(event.getMessage());
 }
 

Note that a request scoped bean wouldn't be the same one as from the originating page for the simple reason that there's no means of a HTTP request anywhere at that moment. For exactly this reason a view and session scoped bean would not work (as they require respectively the Faces view state and HTTP session which can only be identified by a HTTP request). A view and session scoped push socket would also not work, so the push socket really needs to be application scoped. The FacesContext will also be unavailable in the above event listener method.

In case the trigger in business service side is an asynchronous service method which is in turn initiated in WAR side, then you could make use of callbacks from WAR side. Let the business service method take a callback instance as argument, e.g. the java.util.function.Consumer functional interface.

 @Asynchronous
 public void someAsyncServiceMethod(Entity entity, Consumer<Object> callback) {
     // ... (some long process)
     callback.accept(entity.getSomeProperty());
 }
 

And invoke the asynchronous service method in WAR as below.

 @Inject
 private SomeService someService;

 @Inject @Push
 private PushContext someChannel;

 public void someAction() {
     someService.someAsyncServiceMethod(entity, message -> someChannel.send(message));
 }
 

This would be the only way in case you intend to asynchronously send a message to a view or session scoped push socket, and/or want to pass something from FacesContext or the initial request/view/session scope along as (final) argument.

Cluster design hints

In case your web application is deployed to a server cluster with multiple nodes, and the push event could be triggered in a different node than where the client is connected to, then it won't reach the socket. One solution is to activate and configure a JMS topic in the server configuration, trigger the push event via JMS instead of CDI, and use a JMS listener (a message driven bean, MDB) to delegate the push event to CDI.

Below is an example extending on the above given business service example.

 @ApplicationScoped
 public class PushManager {

     @Resource(lookup = "java:/jms/topic/push")
     private Topic jmsTopic;

     @Inject
     private JMSContext jmsContext;

     public void fireEvent(PushEvent pushEvent) {
         try {
             Message jmsMessage = jmsContext.createMessage();
             jmsMessage.setStringProperty("message", pushEvent.getMessage());
             jmsContext.createProducer().send(jmsTopic, jmsMessage);
         }
         catch (Exception e) {
             // Handle.
         }
     }
 }
 
 @MessageDriven(activationConfig = {
     @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/topic/push")
 })
 public class PushListener implements MessageListener {

     @Inject
     private BeanManager beanManager;

     @Override
     public void onMessage(Message jmsMessage) {
         try {
             String message = jmsMessage.getStringProperty("message");
             beanManager.fireEvent(new PushEvent(message));
         }
         catch (Exception e) {
             // Handle.
         }
     }
 }
 

Then, in your business service, instead of using BeanManager#fireEvent() to fire the CDI event,

 @Inject
 private BeanManager beanManager;

 public void onSomeEntityChange(Entity entity) {
     beanManager.fireEvent(new PushEvent(entity.getSomeProperty()));
 }
 

use the newly created PushManager#fireEvent() to fire the JMS event from one server node of the cluster, which in turn will fire the CDI event in all server nodes of the cluster.

 @Inject
 private PushManager pushManager;

 public void onSomeEntityChange(Entity entity) {
     pushManager.fireEvent(new PushEvent(entity.getSomeProperty()));
 }
 

UI update design hints

In case you'd like to perform complex UI updates, then easiest would be to put <f:ajax> inside <o:socket>. The support was added in OmniFaces 2.6. Here's an example:

 <h:panelGroup id="foo">
     ... (some complex UI here) ...
 </h:panelGroup>

 <h:form>
     <o:socket channel="someChannel" scope="view">
         <f:ajax event="someEvent" listener="#{bean.pushed}" render=":foo" />
     </o:socket>
 </h:form>
 

Here, the push message simply represents the ajax event name. You can use any custom event name.

 someChannel.send("someEvent");
 

An alternative is to combine <o:socket> with <h:commandScript>. E.g.

 <h:panelGroup id="foo">
     ... (some complex UI here) ...
 </h:panelGroup>

 <o:socket channel="someChannel" scope="view" onmessage="someCommandScript" />
 <h:form>
     <h:commandScript name="someCommandScript" action="#{bean.pushed}" render=":foo" />
 </h:form>
 

If you pass a Map<String,V> or a JavaBean as push message object, then all entries/properties will transparently be available as request parameters in the command script method #{bean.pushed}.

sse

The <o:sse> is an UIComponent which opens an one-way (server to client) SSE (Server-Sent Events) based push connection in client side which can be reached from server side via PushContext interface injected in any CDI/container managed artifact via @Push(type=SSE) annotation.

Important: All servlet filters mapped on /* must have asyncSupported=true for SSE to work.

SSE vs WebSocket

Both <o:sse> and <o:socket> provide one-way (server to client) push. The table below summarizes the key differences to help you choose the right transport.

SSE (<o:sse>) vs WebSocket (<o:socket>)
SSE (<o:sse>)WebSocket (<o:socket>)
TransportPlain HTTPWebSocket protocol upgrade
DependenciesNone (async servlet)Requires jakarta.websocket
Proxy/CDN/firewallWorks through HTTP infrastructureMay be blocked by proxies or corporate firewalls
ReconnectBuilt-in (EventSource API)Manual (with cumulative backoff)
HTTP/2 multiplexingYes (shares TCP connection)No (separate TCP connection)
Connection limitMax 6 per origin without HTTP/2Not affected (protocol upgrade)
CDI eventsSseEvent on open/close/switchSocketEvent on open/close/switch
Dynamic connect/disconnectNot availableconnected attribute

When to prefer SSE: for typical unidirectional push use cases (notifications, live updates, dashboards) where HTTP infrastructure compatibility and simplicity are important. SSE is the simpler and more robust choice for most server-to-client push scenarios.

When to prefer WebSocket: when you need dynamic connect/disconnect via the connected attribute, or when your server does not support HTTP/2.

Note: browsers limit concurrent HTTP/1.1 connections to 6 per origin. When the server does not support HTTP/2, multiple SSE channels across multiple tabs may exhaust this limit and queue further HTTP requests (including Ajax requests!). This can be resolved by configuring the server to use HTTP/2, where SSE streams are multiplexed over a single TCP connection.

Configuration

No explicit configuration is needed. The SSE endpoint is automatically registered during application startup when at least one @Push(type=SSE) qualified injection point is detected.

Usage (client)

Declare <o:sse> tag in the Faces view with at least a channel name and an onmessage JavaScript listener function. The channel name may not be an EL expression and it may only contain alphanumeric characters, hyphens, underscores and periods.

Here's an example which refers an existing JavaScript listener function (do not include the parentheses!).

 <o:sse channel="someChannel" onmessage="sseListener" />
 
 function sseListener(message, channel, event) {
     console.log(message);
 }
 

Here's an example which declares an inline JavaScript listener function.

 <o:sse channel="someChannel" onmessage="function(message) { console.log(message); }" />
 

The onmessage JavaScript listener function will be invoked with three arguments:

  • message: the push message as JSON object.
  • channel: the channel name, useful in case you intend to have a global listener.
  • event: the raw MessageEvent instance, useful in case you intend to inspect it.

The SSE connection is automatically established when the page loads and will auto-reconnect when the connection is lost due to e.g. a network error or server restart. This is a built-in feature of the browser's EventSource API. The SSE connection will be implicitly closed once the document is unloaded (e.g. navigating away, close of browser window/tab, etc).

In order to successfully reconnect after a server restart, or when switching to a new server node, you need to ensure that session persistence is enabled on the server.

Usage (server)

In WAR side, you can inject PushContext via @Push(type=SSE) annotation on the given channel name in any CDI/container managed artifact such as @Named, @WebServlet, etc wherever you'd like to send a push message and then invoke PushContext#send(Object) with any Java object representing the push message.

 @Inject @Push(type=SSE)
 private PushContext someChannel;

 public void sendMessage(Object message) {
     someChannel.send(message);
 }
 

By default the name of the channel is taken from the name of the variable into which injection takes place. The channel name can be optionally specified via the channel attribute. The example below injects the push context for channel name foo into a variable named bar.

 @Inject @Push(type=SSE, channel="foo")
 private PushContext bar;
 

The message object will be encoded as JSON and be delivered as message argument of the onmessage JavaScript listener function associated with the channel name. It can be a plain vanilla String, but it can also be a collection, map and even a javabean. For supported argument types, see also Json#encode(Object).

Scopes and users

By default the SSE channel is application scoped, i.e. any view/session throughout the web application having the same SSE channel open will receive the same push message. The push message can be sent by all users and the application itself. This is useful for application-wide feedback triggered by site itself such as real time updates of a certain page (e.g. site-wide statistics, top100 lists, stock updates, etc).

The optional scope attribute can be set to session to restrict the push messages to all views in the current user session only. The push message can only be sent by the user itself and not by the application. This is useful for session-wide feedback triggered by user itself (e.g. as result of asynchronous tasks triggered by user specific action).

 <o:sse channel="someChannel" scope="session" ... />
 

The scope attribute can also be set to view to restrict the push messages to the current view only. The push message will not show up in other views in the same session even if it's the same URL. The push message can only be sent by the user itself and not by the application. This is useful for view-wide feedback triggered by user itself (e.g. progress bar tied to a user specific action on current view).

 <o:sse channel="someChannel" scope="view" ... />
 

The scope attribute may not be an EL expression and allowed values are application, session and view, case insensitive.

Additionally, the optional user attribute can be set to the unique identifier of the logged-in user, usually the login name or the user ID. This way the push message can be targeted to a specific user and can also be sent by other users and the application itself. The value of the user attribute must at least implement Serializable and have a low memory footprint, so putting entire user entity is not recommended.

E.g. when you're using container managed authentication or a related framework/library:

 <o:sse channel="someChannel" user="#{request.remoteUser}" ... />
 

Or when you have a custom user entity around in EL as #{someLoggedInUser} which has an id property representing its identifier:

 <o:sse channel="someChannel" user="#{someLoggedInUser.id}" ... />
 
When the user attribute is specified, then the scope defaults to session and cannot be set to application. It can be set to view, but this is kind of unusual and should only be used if the logged-in user represented by user has a shorter lifetime than the HTTP session (e.g. when your application allows changing a logged-in user during same HTTP session without invaliding it — which is in turn poor security practice). If in such case a session scoped channel is reused, undefined behavior may occur when user-targeted push message is sent. It may target previously logged-in user only. This can be solved by setting the scope to view, but better is to fix the logout to invalidate the HTTP session altogether.

When the user attribute is an EL expression and it changes during an ajax request, then the SSE user will be actually switched, even though you did not cover the <o:sse> component in any ajax render/update. So make sure the value is tied to at least a view scoped property in case you intend to control it during the view scope.

In the server side, the push message can be targeted to the user specified in the user attribute via PushContext#send(Object, Serializable). The push message can be sent by all users and the application itself. This is useful for user-specific feedback triggered by other users (e.g. chat, admin messages, etc) or by application's background tasks (e.g. notifications, event listeners, etc).

 @Inject @Push(type=SSE)
 private PushContext someChannel;

 public void sendMessage(Object message, User recipientUser) {
     Long recipientUserId = recipientUser.getId();
     someChannel.send(message, recipientUserId);
 }
 

Multiple users can be targeted by passing a Collection holding user identifiers to PushContext#send(Object, Collection).

 public void sendMessage(Object message, Group recipientGroup) {
     Collection<Long> recipientUserIds = recipientGroup.getUserIds();
     someChannel.send(message, recipientUserIds);
 }
 

Channel design hints

You can declare multiple push channels on different scopes with or without user target throughout the application. Be however aware that the same channel name can easily be reused across multiple views, even if it's view scoped. It's more efficient if you use as few different channel names as possible and tie the channel name to a specific push channel scope/user combination, not to a specific Faces view. In case you intend to have multiple view scoped channels for different purposes, best is to use only one view scoped channel and have a global JavaScript listener which can distinguish its task based on the delivered message. E.g. by sending the message in server as below:

 Map<String, Object> message = new HashMap<>();
 message.put("functionName", "someFunction");
 message.put("functionData", functionData); // Can be Map or Bean.
 someChannel.send(message);
 

Which is processed in the onmessage JavaScript listener function as below:

 function someSseListener(message) {
     window[message.functionName](message.functionData);
 }

 function someFunction(data) {
     // ...
 }

 function otherFunction(data) {
     // ...
 }

 // ...
 

Events (client)

The optional onopen JavaScript listener function can be used to listen on open of an SSE connection in client side. It will be invoked with one argument:

  • channel: the channel name, useful in case you intend to have a global listener.
 <o:sse ... onopen="sseOpenListener" />
 
 function sseOpenListener(channel) {
     // ...
 }
 

The optional onerror JavaScript listener function can be used to listen on a connection error whereby the browser will automatically attempt to reconnect. This will be invoked when a transient connection error occurs (e.g. temporary network interruption) while the browser's EventSource is still attempting to reconnect. This will not be invoked when the server has explicitly closed the connection (e.g. unknown channel, or expired session or view), or when the EventSource API is not supported. Instead, the onclose will be invoked.

 <o:sse ... onerror="sseErrorListener" />
 
 function sseErrorListener(code, channel, event) {
     if (code == 500) {
         // Connection error. The browser will automatically attempt to reconnect.
     }
 }
 

The onerror JavaScript listener function will be invoked with three arguments:

  • code: synthetic HTTP-based close code as integer. Currently this is always 500 (connection error, browser will auto-reconnect).
  • channel: the channel name, useful in case you intend to have a global listener.
  • event: the raw Event instance from the EventSource API. Note that unlike WebSocket's CloseEvent, the SSE error event does not carry a close code or reason.

The optional onclose JavaScript listener function can be used to listen on the final close of an SSE connection. This will be invoked when the EventSource API is not supported by the client, or when the server has explicitly closed the connection (e.g. on session or view expiry, or unknown channel), or when the client has explicitly closed the connection via OmniFaces.Push.close(channel). This will not be invoked when the browser can make an auto-reconnect attempt. Instead, the onerror will be invoked.

 <o:sse ... onclose="sseCloseListener" />
 
 function sseCloseListener(code, channel, event) {
     if (code == -1) {
         // EventSource API not supported by client.
     } else if (code == 200) {
         // Server explicitly closed the connection (e.g. expired session or view).
     } else if (code == 204) {
         // Client explicitly closed the connection via OmniFaces.Push.close().
     } else if (code == 404) {
         // Unknown channel (e.g. randomly guessed or spoofed by endusers or manually reconnected after session expiry).
     } else {
         // Abnormal close reason (as result of an error).
     }
 }
 

The onclose JavaScript listener function will be invoked with three arguments:

  • code: synthetic HTTP-based close code as integer. If this is -1, then the EventSource API is simply not supported by the client. If this is 200, then the server explicitly closed the connection (e.g. due to an expired session or view). If this is 204, then the client explicitly closed the connection via OmniFaces.Push.close(channel). If this is 404, then the channel is unknown (e.g. randomly guessed or spoofed by endusers or manually reconnected after the session is expired).
  • channel: the channel name, useful in case you intend to have a global listener.
  • event: the raw Event instance, if available. This is present when the server closed the connection (codes 200 and 404), but absent when the EventSource API is not supported (code -1) or the client explicitly closed the connection (code 204).

Events (server)

When an SSE connection has been opened, a new CDI SseEvent will be fired with @Opened qualifier. When the user attribute of the <o:sse> changes, a new CDI SseEvent will be fired with @Switched qualifier. When an SSE connection has been closed, a new CDI SseEvent will be fired with @Closed qualifier. They can only be observed and collected in an application scoped CDI bean as below. Observing in a request/view/session scoped CDI bean is not possible as there's no means of a HTTP request anywhere at that moment.

 @ApplicationScoped
 public class SseObserver {

     public void onOpen(@Observes @Opened SseEvent event) {
         String channel = event.getChannel(); // Returns <o:sse channel>.
         Long userId = event.getUser(); // Returns <o:sse user>, if any.
         // Do your thing with it. E.g. collecting them in a concurrent/synchronized collection.
         // Do note that a single person can open multiple SSE connections on same channel/user.
     }

     public void onSwitch(@Observes @Switched SseEvent event) {
         String channel = event.getChannel(); // Returns <o:sse channel>.
         Long currentUserId = event.getUser(); // Returns current <o:sse user>, if any.
         Long previousUserId = event.getPreviousUser(); // Returns previous <o:sse user>, if any.
         // Do your thing with it. E.g. updating in a concurrent/synchronized collection.
     }

     public void onClose(@Observes @Closed SseEvent event) {
         String channel = event.getChannel(); // Returns <o:sse channel>.
         Long userId = event.getUser(); // Returns <o:sse user>, if any.
         // Do your thing with it. E.g. removing them from collection.
     }

 }
 

You could take the opportunity to send another push message to an application scoped channel, e.g. "User X has been logged in" (or out) when a session scoped channel is opened (or closed).

Security considerations

If the SSE channel is declared in a page which is only restricted to logged-in users with a specific role, then you may want to add the URL of the SSE connection to the set of restricted URLs.

The SSE request URL is composed of the URI prefix /omnifaces.sse/, followed by channel name. So, in case of for example container managed security which has already restricted an example page /user/foo.xhtml to logged-in users with the example role USER on the example URL pattern /user/* in web.xml like below,

 <security-constraint>
     <web-resource-collection>
         <web-resource-name>Restrict access to role USER.</web-resource-name>
         <url-pattern>/user/*</url-pattern>
     </web-resource-collection>
     <auth-constraint>
         <role-name>USER</role-name>
     </auth-constraint>
 </security-constraint>
 

.. and the page /user/foo.xhtml in turn contains a <o:sse channel="foo">, then you need to add a restriction on SSE connection request URL pattern of /omnifaces.sse/foo like below.

 <security-constraint>
     <web-resource-collection>
         <web-resource-name>Restrict access to role USER.</web-resource-name>
         <url-pattern>/user/*</url-pattern>
         <url-pattern>/omnifaces.sse/foo</url-pattern>
     </web-resource-collection>
     <auth-constraint>
         <role-name>USER</role-name>
     </auth-constraint>
 </security-constraint>
 

As extra security, particularly for those public channels which can't be restricted by security constraints, the <o:sse> will register all so far declared channels in the current HTTP session, and any incoming SSE connection request will be checked whether it matches a registered channel in the current HTTP session. In case the channel is unknown (e.g. randomly guessed or spoofed by endusers or manually reconnected after the session is expired), then the SSE connection will immediately be completed. Also, when the HTTP session gets destroyed, all session and view scoped channels which are still open will explicitly be closed from server side. Only application scoped channels remain open and are still reachable from server end even when the session or view associated with the page in client side is expired.

Business service design hints

In case you'd like to trigger a push from business service side to an application scoped push channel, then you could make use of CDI events. First create a custom bean class representing the push event something like PushEvent below taking whatever you'd like to pass as push message.

 public final class PushEvent {

     private final String message;

     public PushEvent(String message) {
         this.message = message;
     }

     public String getMessage() {
         return message;
     }
 }
 

Then use jakarta.enterprise.inject.spi.BeanManager#getEvent() to fire the CDI event.

 @Inject
 private BeanManager beanManager;

 public void onSomeEntityChange(Entity entity) {
     beanManager.getEvent().select().fire(new PushEvent(entity.getSomeProperty()));
 }
 

Note that OmniFaces own Beans#fireEvent(Object, java.lang.annotation.Annotation...) utility method is insuitable as it is not allowed to use WAR (front end) frameworks and libraries like Faces and OmniFaces in business service (back end) side.

Finally just @Observes it in some request or application scoped CDI managed bean in WAR and delegate to PushContext as below.

 @Inject @Push(type=SSE)
 private PushContext someChannel;

 public void onPushEvent(@Observes PushEvent event) {
     someChannel.send(event.getMessage());
 }
 

Note that a request scoped bean wouldn't be the same one as from the originating page for the simple reason that there's no means of a HTTP request anywhere at that moment. For exactly this reason a view and session scoped bean would not work (as they require respectively the Faces view state and HTTP session which can only be identified by a HTTP request). A view and session scoped push channel would also not work, so the push channel really needs to be application scoped. The FacesContext will also be unavailable in the above event listener method.

In case the trigger in business service side is an asynchronous service method which is in turn initiated in WAR side, then you could make use of callbacks from WAR side. Let the business service method take a callback instance as argument, e.g. the java.util.function.Consumer functional interface.

 @Asynchronous
 public void someAsyncServiceMethod(Entity entity, Consumer<Object> callback) {
     // ... (some long process)
     callback.accept(entity.getSomeProperty());
 }
 

And invoke the asynchronous service method in WAR as below.

 @Inject
 private SomeService someService;

 @Inject @Push(type=SSE)
 private PushContext someChannel;

 public void someAction() {
     someService.someAsyncServiceMethod(entity, message -> someChannel.send(message));
 }
 

This would be the only way in case you intend to asynchronously send a message to a view or session scoped push channel, and/or want to pass something from FacesContext or the initial request/view/session scope along as (final) argument.

Cluster design hints

In case your web application is deployed to a server cluster with multiple nodes, and the push event could be triggered in a different node than where the client is connected to, then it won't reach the client. One solution is to activate and configure a JMS topic in the server configuration, trigger the push event via JMS instead of CDI, and use a JMS listener (a message driven bean, MDB) to delegate the push event to CDI.

Below is an example extending on the above given business service example.

 @ApplicationScoped
 public class PushManager {

     @Resource(lookup = "java:/jms/topic/push")
     private Topic jmsTopic;

     @Inject
     private JMSContext jmsContext;

     public void fireEvent(PushEvent pushEvent) {
         try {
             Message jmsMessage = jmsContext.createMessage();
             jmsMessage.setStringProperty("message", pushEvent.getMessage());
             jmsContext.createProducer().send(jmsTopic, jmsMessage);
         }
         catch (Exception e) {
             // Handle.
         }
     }
 }
 
 @MessageDriven(activationConfig = {
     @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/topic/push")
 })
 public class PushListener implements MessageListener {

     @Inject
     private BeanManager beanManager;

     @Override
     public void onMessage(Message jmsMessage) {
         try {
             String message = jmsMessage.getStringProperty("message");
             beanManager.fireEvent(new PushEvent(message));
         }
         catch (Exception e) {
             // Handle.
         }
     }
 }
 

Then, in your business service, instead of using BeanManager#fireEvent() to fire the CDI event,

 @Inject
 private BeanManager beanManager;

 public void onSomeEntityChange(Entity entity) {
     beanManager.fireEvent(new PushEvent(entity.getSomeProperty()));
 }
 

use the newly created PushManager#fireEvent() to fire the JMS event from one server node of the cluster, which in turn will fire the CDI event in all server nodes of the cluster.

 @Inject
 private PushManager pushManager;

 public void onSomeEntityChange(Entity entity) {
     pushManager.fireEvent(new PushEvent(entity.getSomeProperty()));
 }
 

UI update design hints

In case you'd like to perform complex UI updates, then easiest would be to put <f:ajax> inside <o:sse>. Here's an example:

 <h:panelGroup id="foo">
     ... (some complex UI here) ...
 </h:panelGroup>

 <h:form>
     <o:sse channel="someChannel" scope="view">
         <f:ajax event="someEvent" listener="#{bean.pushed}" render=":foo" />
     </o:sse>
 </h:form>
 

Here, the push message simply represents the ajax event name. You can use any custom event name.

 someChannel.send("someEvent");
 

An alternative is to combine <o:sse> with <h:commandScript>. E.g.

 <h:panelGroup id="foo">
     ... (some complex UI here) ...
 </h:panelGroup>

 <o:sse channel="someChannel" scope="view" onmessage="someCommandScript" />
 <h:form>
     <h:commandScript name="someCommandScript" action="#{bean.pushed}" render=":foo" />
 </h:form>
 

If you pass a Map<String,V> or a JavaBean as push message object, then all entries/properties will transparently be available as request parameters in the command script method #{bean.pushed}.

tagAttribute

The <o:tagAttribute> is a tag handler that can be used to explicitly declare a tag attribute on a Facelets tag file. This makes sure that any tag attribute with the same name on a parent tag file is cleared out, which does not properly happen in Mojarra.

Consider the following custom tag structure:

 <my:tag id="foo">
     <my:tag id="bar" />
 </my:tag>
 

Inside the nested tag, the #{id} will just evaluate to "bar". However, if this isn't declared on the nested tag like so,

 <my:tag id="foo">
     <my:tag />
 </my:tag>
 

then #{id} of the nested tag would evaluate to "foo" instead of null, even when you explicitly specify the attribute in the *.taglib.xml file.

This tag handler is designed to overcome this peculiar problem and unintuitive behavior of nested tagfiles in Mojarra.

Usage

Just declare the attribute name in top of the tagfile as below.

 <o:tagAttribute name="id" />
 

You can optionally provide a default value.

 <o:tagAttribute name="type" default="text" />
 
Since OmniFaces 2.7/3.2 there is a special case for a <o:tagAttribute name="id"> without a default value: it will override any autogenerated ID into the form of j_ido[tagId] where [tagId] is the <o:tagAttribute> tag's own unique ID.
toCollectionConverter

The omnifaces.ToCollectionConverter is intented to convert submitted String values to a Java collection based on a delimiter. Additionally, it trims any whitespace around each delimited submitted value. This is useful for among others comma separated value inputs.

Usage

This converter is available by converter ID omnifaces.ToCollectionConverter. Just specify it in the converter attribute of the component referring the Collection property. For example:

 <h:inputText value="#{bean.commaSeparatedValues}" converter="omnifaces.ToCollectionConverter" />
 

Since OmniFaces 4.5 it's also available by <o:toCollectionConverter> tag.

 <h:inputText value="#{bean.commaSeparatedValues}">
     <o:toCollectionConverter />
 </h:inputText>
 

The default delimiter is comma followed by space , and the default collection type is java.util.LinkedHashSet for a Set property and java.util.ArrayList for anything else, and the default converter for each item will in getAsString() be determined based on item type and in getAsObject() be determined based on generic return type of the getter method.

The delimiter must be a String, the collectionType must be a FQN and the itemConverter can be anything which is acceptable by Faces#createConverter(Object).

 <h:inputText value="#{bean.uniqueOrderedSemiColonSeparatedNumbers}">
     <o:toCollectionConverter delimiter=";"
                                 collectionType="java.util.TreeSet"
                                 itemConverter="jakarta.faces.Integer" />
 </h:inputText>
 
toLowerCaseConverter

The omnifaces.ToLowerCaseConverter is intented to convert submitted String values to lower case based on current Locale. Additionally, it trims any whitespace from the submitted value. This is useful for among others email address inputs.

This converter does by design no conversion in getAsString().

Usage

This converter is available by converter ID omnifaces.ToLowerCaseConverter. Just specify it in the converter attribute of the component referring the String property. For example:

 <h:inputText value="#{bean.email}" converter="omnifaces.ToLowerCaseConverter" />
 

Since OmniFaces 4.5 it's also available by <o:toLowerCaseConverter> tag.

 <h:inputText value="#{bean.email}">
     <o:toLowerCaseConverter />
 </h:inputText>
 
toUpperCaseConverter

The omnifaces.ToUpperCaseConverter is intented to convert submitted String values to upper case based on current Locale. Additionally, it trims any whitespace from the submitted value. This is useful for among others zip code inputs.

This converter does by design no conversion in getAsString().

Usage

This converter is available by converter ID omnifaces.ToUpperCaseConverter. Just specify it in the converter attribute of the component referring the String property. For example:

 <h:inputText value="#{bean.zipCode}" converter="omnifaces.ToUpperCaseConverter" />
 

Since OmniFaces 4.5 it's also available by <o:toUpperCaseConverter> tag.

 <h:inputText value="#{bean.zipCode}">
     <o:toUpperCaseConverter />
 </h:inputText>
 
tree

The <o:tree> allows the developers to have full control over the markup of a tree hierarchy by declaring the appropriate Faces components or HTML elements in the markup. The <o:tree> does namely not render any HTML markup by itself.

The component value must point to a tree of data objects represented by a TreeModel instance, typically established via a ValueExpression. During iterative processing over the nodes of tree in the tree model, the object for the current node is exposed as a request attribute under the key specified by the var attribute. The node itself is exposed as a request attribute under the key specified by the varNode attribute.

The <o:tree> tag supports only child tags of type <o:treeNode>, representing parent tree nodes. There can be multiple <o:treeNode> tags, each representing a separate parent tree node level, so that different markup could be declared for each tree node level, if necessary. The <o:treeNode> tag in turn supports child tag <o:treeNodeItem> which represents each child of the current parent tree node. The <o:treeNodeItem> in turn supports child tag <o:treeInsertChildren> which represents the insertion point of the grand children.

Here is a basic usage example where each parent tree node level is treated the same way via a single <o:treeNode>:

 <o:tree value="#{bean.treeModel}" var="item" varNode="node">
     <o:treeNode>
         <ul>
             <o:treeNodeItem>
                 <li>
                     #{node.index} #{item.someProperty}
                     <o:treeInsertChildren />
                 </li>
             </o:treeNodeItem>
         </ul>
     </o:treeNode>
 </o:tree>
 

treeNode

The <o:treeNode> represents the parent tree node. Within this component, the var attribute of the <o:tree> will expose the parent tree node. Each of its children is processed by <o:treeNodeItem> on which the var attribute of the <o:tree> in turn exposes each child of the parent tree node.

The optional level attribute can be used to specify for which tree node level as obtained by TreeModel#getLevel() the <o:treeNode> should be rendered. The root tree node has level 0. If the level attribute is unspecified, then the <o:treeNode> will be rendered for any tree node level which hasn't already a <o:treeNode level="x"> specified.

treeNodeItem

The <o:treeNodeItem> represents the child item of the parent tree note as represented by <o:treeNode>. Within this component, the var attribute of the parent <o:tree> component will expose the child tree node.

Within <o:treeNodeItem> you can use <o:treeInsertChildren> to declare the place where to recursively render the <o:treeNode> whereby the current child item is in turn interpreted as a parent tree node (i.e. where you'd like to insert the grand-children).

treeInsertChildren

The <o:treeInsertChildren> represents the insertion point for the grand children. This is in turn further interpreted as <o:treeNode>.

treeInsertChildren

The <o:treeInsertChildren> is an UIComponent that represents the insertion point for the children of a parent tree node which is represented by TreeNodeItem.

This component does not allow any children.

treeNode

The <o:treeNode> is an UIComponent that represents a single tree node within a parent Tree component. Within this component, the var attribute of the parent Tree component will expose the tree node. Each of its children is processed by TreeNodeItem.

The level attribute can be used to specify for which tree node level as obtained by TreeModel#getLevel() this component should render the children by TreeNodeItem. The root tree node has level 0.

treeNodeItem

The <o:treeNodeItem> is an UIComponent that represents a single child tree node within a parent TreeNode component. Within this component, the var attribute of the parent Tree component will expose the child tree node.

This component allows a child component of type TreeInsertChildren which indicates the place to insert the children of the current child tree node recursively by a TreeNode component associated with the children's level in the same parent Tree component.

trimConverter

The omnifaces.TrimConverter is intented to trim any whitespace from submitted String values. This keeps the data store free of whitespace pollution.

This converter does by design no conversion in getAsString().

Usage

This converter is available by converter ID omnifaces.TrimConverter. Just specify it in the converter attribute of the component referring the String property. For example:

 <h:inputText value="#{bean.username}" converter="omnifaces.TrimConverter" />
 

Since OmniFaces 4.5 it's also available by <o:trimConverter> tag.

 <h:inputText value="#{bean.username}">
     <o:trimConverter />
 </h:inputText>
 

You can also configure it application wide via below entry in faces-config.xml without the need to specify it in every single input component:

 <converter>
     <converter-for-class>java.lang.String</converter-for-class>
     <converter-class>org.omnifaces.converter.TrimConverter</converter-class>
 </converter>
 
url

The <o:url> is a component which renders the given target URL or Faces view ID as a bookmarkable URL with support for adding additional query string parameters to the URL via nested <f:param> and <o:param>, and for exposing it into the request scope by the variable name as specified by the var attribute instead of rendering it.

This component fills the gap caused by absence of JSTL <c:url> in Facelets. This component is useful for generating URLs for usage in e.g. plain HTML <link> elements and JavaScript variables.

Values

You can supply the target URL via either the value attribute or the viewId attribute. When both are specified, the value attribute takes precedence and the viewId attribute is ignored. When none are specified, then the viewId will default to the current view ID. The support for value attribute was added in OmniFaces 3.0.

Domain

When the target URL is specified as viewId, then the domain of the target URL defaults to the current domain. It is possible to provide a full qualified domain name (FQDN) via the domain attribute which the URL is to be prefixed with. This can be useful if a canonical page shall point to a different domain or a specific subdomain.

Valid formats and values for domain attribute are:

  • <o:url domain="https://example.com" />
  • <o:url domain="//example.com" />
  • <o:url domain="example.com" />
  • <o:url domain="/" />
  • <o:url domain="//" />

The domain value will be validated by URL and throw an illegal argument exception when invalid. If the domain equals /, then the URL becomes domain-relative. If the domain equals or starts with //, or does not contain any scheme, then the URL becomes scheme-relative. If the value attribute is specified, then the domain attribute is ignored.

Request and view parameters

You can add query string parameters to the URL via nested <f:param> and <o:param>. You can optionally include all GET request query string parameters or only Faces view parameters in the resulting URL via includeRequestParams="true" or includeViewParams="true". The includeViewParams is ignored when includeRequestParams="true". The <f|o:param> will override any included request or view parameters on the same name. To conditionally add or override, use the disabled attribute of <f|o:param>.

Usage

Some examples:

 <p>Full URL of current page is: <o:url /></p>
 <p>Full URL of another page is: <o:url viewId="/another.xhtml" /></p>
 <p>Full URL of current page including view params is: <o:url includeViewParams="true" /></p>
 <p>Full URL of current page including query string is: <o:url includeRequestParams="true" /></p>
 <p>Domain-relative URL of current page is: <o:url domain="/" /></p>
 <p>Scheme-relative URL of current page is: <o:url domain="//" /></p>
 <p>Scheme-relative URL of current page on a different domain is: <o:url domain="sub.example.com" /></p>
 <p>Full URL of current page on a different domain is: <o:url domain="https://sub.example.com" /></p>
 <p>External URL with encoded parameters appended: <o:url value="https://google.com/search">
     <o:param name="q" value="#{bean.search}" />
 </url></p>
 
 <o:url var="_linkCanonical">
     <o:param name="foo" value="#{bean.foo}" />
 </o:url>
 <link rel="canonical" href="#{_linkCanonical}" />
 
 <o:url var="_linkNext" includeViewParams="true">
     <f:param name="page" value="#{bean.pageIndex + 1}" />
 </o:url>
 <link rel="next" href="#{_linkNext}" />
 
validateAll

The <o:validateAll> validates if ALL of the given UIInput components have been filled out. One could of course also just put required="true" on all of those UIInput components, but sometimes it's desireable to invalidate all of those fields and/or to have just only one message for it, which isn't possible with the standard Faces API.

The default message is

{0}: Please fill out all of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateAllOrNone

The <o:validateAllOrNone> validates if at least ALL of the given UIInput components have been filled out or that NONE of the given UIInput components have been filled out.

The default message is

{0}: Please fill out all or none of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateBean

The <o:validateBean> allows the developer to control bean validation on a per-UICommand or UIInput component basis, as well as validating a given bean at the class level.

The standard <f:validateBean> only allows validation control on a per-form or a per-request basis (by using multiple tags and conditional EL expressions in its attributes) which may end up in boilerplate code.

The standard <f:validateBean> also, despite its name, does not actually have any facilities to validate a bean at all.

Usage

Some examples

Control bean validation per component

 <h:commandButton value="submit" action="#{bean.submit}">
     <o:validateBean validationGroups="jakarta.validation.groups.Default,com.example.MyGroup" />
 </h:commandButton>
 
 <h:selectOneMenu value="#{bean.selectedItem}">
     <f:selectItems value="#{bean.availableItems}" />
     <o:validateBean disabled="true" />
     <f:ajax execute="@form" listener="#{bean.itemChanged}" render="@form" />
 </h:selectOneMenu>
 

Validate a bean at the class level

 <h:inputText value="#{bean.product.item}" />
 <h:inputText value="#{bean.product.order}" />

 <o:validateBean value="#{bean.product}" />
 

Since OmniFaces 3.8, nested properties are also supported with @jakarta.validation.Valid cascade

 <h:inputText value="#{bean.product.item}" />
 <h:inputText value="#{bean.product.order}" />

 <o:validateBean value="#{bean}" />
 

Whereby the product property looks like this:

 @Valid
 private Product product;
 

When using <o:validateBean method="validateCopy" /> (which is the default), then only beans, lists, maps and arrays are considered as nested properties and the copied bean will be autopopulated with defaults. If this fails, then consider creating a custom copier as instructed in next section.

Class level validation details

In order to validate a bean at the class level, all values from input components should first be actually set on that bean and only thereafter should the bean be validated. This however does not play well with the Faces approach where a model is only updated when validation passes. But for class level validation we seemingly can not validate until the model is updated. To break this tie, a copy of the model bean is made first, and then values are stored in this copy and validated there. If validation passes, the original bean is updated.

A bean is copied using the following strategies (in the order indicated):

  1. Cloning - Bean must implement the Cloneable interface and support cloning according to the rules of that interface. See CloneCopier
  2. Serialization - Bean must implement the Serializable interface and support serialization according to the rules of that interface. See SerializationCopier
  3. Copy constructor - Bean must have an additional constructor (next to the default constructor) taking a single argument of its own type that initializes itself with the values of that passed in type. See CopyCtorCopier
  4. New instance - Bean should have a public no arguments (default) constructor. Every official JavaBean satisfies this requirement. Note that in this case no copy is made of the original bean, but just a new instance is created. See NewInstanceCopier

If the above order is not ideal, or if an custom copy strategy is needed (e.g. when it's only needed to copy a few fields for the validation) a strategy can be supplied explicitly via the copier attribute. The value of this attribute can be any of the build-in copier implementations given above, or can be a custom implementation of the Copier interface.

If the copying strategy is not possible due to technical limitations, then you could set method attribute to "validateActual".

 <o:validateBean value="#{bean.product}" method="validateActual" />
 

This will update the model values and run the validation after update model values phase instead of the validations phase. The disadvantage is that the invalid values remain in the model and that the action method is anyway invoked. You would need an additional check for FacesContext#isValidationFailed() in the action method to see if it has failed or not.

Faces messages

By default, the faces message is added with client ID of the parent UIForm.

 <h:form id="formId">
     ...
     <h:message for="formId" />
     <o:validateBean ... />
 </h:form>
 

The faces message can also be shown for all invalidated components using showMessageFor="@all".

 <h:form>
     <h:inputText id="foo" />
     <h:message for="foo" />
     <h:inputText id="bar" />
     <h:message for="bar" />
     ...
     <o:validateBean ... showMessageFor="@all" />
 </h:form>
 

The faces message can also be shown as global message using showMessageFor="@global".

 <h:form>
     ...
     <o:validateBean ... showMessageFor="@global" />
 </h:form>
 <h:messages globalOnly="true" />
 

The faces message can also be shown for specific components referenced by a space separated collection of their client IDs in showMessageFor attribute.

 <h:form>
     <h:inputText id="foo" />
     <h:message for="foo" />
     <h:inputText id="bar" />
     <h:message for="bar" />
     ...
     <o:validateBean ... showMessageFor="foo bar" />
 </h:form>
 

The faces message can also be shown for components which match jakarta.validation.ConstraintViolation#getPropertyPath() Property Path of the ConstraintViolation using showMessageFor="@violating", and when no matching component can be found, the message will fallback to being added with client ID of the parent UIForm.

 <h:form id="formId">
     ...
     <!-- Unmatched messages shown here: -->
     <h:message for="formId" />
     ...
     <h:inputText id="foo" value="#{bean.product.item}" />

     <!-- Messages where ConstraintViolation PropertyPath is "item" are shown here: -->
     <h:message for="foo" />
     ...
     <o:validateBean ... value="#{bean.product}" showMessageFor="@violating" />
 </h:form>
 

The showMessageFor attribute is new since OmniFaces 2.6 and it defaults to @form. The showMessageFor attribute does by design not have any effect when validateMethod="actual" is used.

Message format

The faces message uses a predefined message format, which corresponds to the value of BeanValidator#MESSAGE_ID in the message bundle. The default message format of {1}: {0} prepends the labels of all the validated fields. This is useful in the case of validating a single bean property, but sometimes confusing in the case of validating a bean with many properties.

In a form containing properties like First Name, Last Name, Address, Zip Code, and Phone Number where at the bean level, at least one of the name fields must be non-null, overriding the message format can help make a more clear error message.

This can be done by overriding the BeanValidator#MESSAGE_ID line in the message bundle:

 jakarta.faces.validator.BeanValidator.MESSAGE = Errors encountered: {0}
 

However, this change affects all bean validation messages site-wide. In case you'd like to fine-tune the bean validation message on a per-<o:validateBean>-basis, then you can since OmniFaces 3.12 use the messageFormat attribute. Any {0} placeholder will be substituted with the error message and any {1} placeholder will be substituted with the labels of all validated fields.

 <!-- Displays: "First Name, Last Name, Address, Zip Code, Phone Number: First Name and Last Name cannot both be null" -->
 <o:validateBean />

 <!-- Displays: "Errors encountered: First Name and Last Name cannot both be null" -->
 <o:validateBean messageFormat="Errors encountered: {0}" />"
 
validateEqual

The <o:validateEqual> validates if ALL of the given UIInput components have the same value.

The default message is

{0}: Please fill out the same value for all of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateMultiple

The <o:validateMultiple> allows the developer to validate multiple fields by either a custom validator method:

 <o:validateMultiple id="myId" components="foo bar baz" validator="#{bean.someMethod}" />
 <h:message for="myId" />
 <h:inputText id="foo" />
 <h:inputText id="bar" />
 <h:inputText id="baz" />
 

whereby the method has the following signature (method name is free to your choice):

 public boolean someMethod(FacesContext context, List<UIInput> components, List<Object> values) {
     // ...
 }
 

Or, by a managed bean instance which implements the MultiFieldValidator interface:

 <o:validateMultiple id="myId" components="foo bar baz" validator="#{validateValuesBean}" />
 <h:message for="myId" />
 <h:inputText id="foo" />
 <h:inputText id="bar" />
 <h:inputText id="baz" />
 
 @ManagedBean
 @RequestScoped
 public class ValidateValuesBean implements MultiFieldValidator {
     @Override
     public boolean validateValues(FacesContext context, List<UIInput> components, List<Object> values) {
         // ...
     }
 }
 

Design notice

Note that this validator does not throw ValidatorException, but returns a boolean! Message handling and invalidation job is up to the ValidateMultipleFields implementation who will call this method. You can customize the message by the message attribute of the tag. Refer ValidateMultipleFields documentation for general usage instructions.

validateOne

The <o:validateOne> validates if ONLY ONE of the given UIInput components have been filled out.

The default message is

{0}: Please fill out only one of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateOneOrMore

The <o:validateOneOrMore> validates if at least ONE of the given UIInput components has been filled out.

The default message is

{0}: Please fill out at least one of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateOneOrNone

The <o:validateOneOrNone> validates if ONLY ONE of the given UIInput components has been filled out or that NONE of the given UIInput components have been filled out.

The default message is

{0}: Please fill out only one or none of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateOrder

The <o:validateOrder> validates if the values of the given UIInput components as specified in the components attribute are in the order as specified by the type attribute which accepts the following values:

  • lt (default): from least to greatest, without duplicates.
  • lte: from least to greatest, allowing duplicates (equal values next to each other).
  • gt: from greatest to least, without duplicates.
  • gte: from greatest to least, allowing duplicates (equal values next to each other).

This validator has the additional requirement that the to-be-validated values must implement Comparable. This validator throws an IllegalArgumentException when one or more of the values do not implement it. Note that when this validator is placed before all of the components, then it will only compare the raw unconverted submitted string values, not the converted object values. If you need to compare by the converted object values, then you need to place this validator after all of the components.

The default message is

{0}: Please fill out the values of all those fields in order

For general usage instructions, refer ValidateMultipleFields documentation.

validateUnique

The <o:validateUnique> validates if ALL of the given UIInput components have an unique value.

The default message is

{0}: Please fill out an unique value for all of those fields

For general usage instructions, refer ValidateMultipleFields documentation.

validateUniqueColumn

The <o:validateUniqueColumn> validates if the given UIInput component in an UIData component has an unique value throughout all rows, also those not visible by pagination. This validator works directly on the data model and may therefore not work as expected if the data model does not represent all available rows of the UIData component (e.g. when there's means of lazy loading).

The default message is

{0}: Please fill out an unique value for the entire column. Duplicate found in row {1}

Usage

Usage example:

 <h:dataTable value="#{bean.items}" var="item">
     <h:column>
         <h:inputText value="#{item.value}">
             <o:validateUniqueColumn />
         </h:inputText>
     </h:column>
 </h:dataTable>
 

In an invalidating case, only the first row on which the value is actually changed (i.e. the value change event has been fired on the input component in the particular row) will be marked invalid and a faces message will be added on the client ID of the input component in the particular row. The default message can be changed by the message attribute. Any "{0}" placeholder in the message will be substituted with the label of the input component. Any "{1}" placeholder in the message will be substituted with the 1-based row index of the data model. Note that this does not take pagination into account and that this needs if necessary to be taken care of in the custom message yourself.

 <o:validateUniqueColumn message="Duplicate value!" />
 
validator

The <o:validator> is a taghandler that extends the standard <f:validator> tag family with support for deferred value expressions in all attributes. In other words, the validator attributes are not evaluated anymore on a per view build time basis, but just on every access like as with UI components and bean properties. This has among others the advantage that they can be evaluated on a per-iteration basis inside an iterating component, and that they can be set on a custom validator without needing to explicitly register it in a tagfile.

Usage

When you specify for example the standard <f:validateLongRange> by validatorId="jakarta.faces.LongRange", then you'll be able to use all its attributes such as minimum and maximum as per its documentation, but then with the possibility to supply deferred value expressions.

 <o:validator validatorId="jakarta.faces.LongRange" minimum="#{item.minimum}" maximum="#{item.maximum}" />
 

The validator ID of all standard Faces validators can be found in their javadocs. First go to the javadoc of the class of interest, then go to VALIDATOR_ID in its field summary and finally click the Constant Field Values link to see the value.

It is also possible to specify the validator message on a per-validator basis using the message attribute. Any "{0}" placeholder in the message will be substituted with the label of the referenced input component. Note that this attribute is ignored when the parent component has already validatorMessage specified.

 <o:validator validatorId="jakarta.faces.LongRange" minimum="#{item.minimum}" maximum="#{item.maximum}"
     message="Please enter between #{item.minimum} and #{item.maximum} characters" />
 

JSF 2.3 compatibility

The <o:validator> is currently not compatible with validators which are managed via the managed=true attribute set on the FacesValidator annotation, at least not when using Mojarra. Internally, the converters are wrapped in another instance which doesn't have the needed setter methods specified. In order to get them to work with <o:validator>, the managed=true attribute needs to be removed, so that OmniFaces ValidatorManager will automatically manage them.

viewAction

The <o:viewAction> is a component that extends the standard <f:viewAction> and changes the if attribute to be evaluated during INVOKE_APPLICATION phase instead of the APPLY_REQUEST_VALUES phase. This allows developers to let the if attribute check the converted and validated model values before performing the view action, which results in much more intuitive behavior.

In below example, the FooConverter may convert a non-null parameter to null without causing a validation or conversion error, and the intent is to redirect the current page to otherpage.xhtml when the converted result is null.

 <f:viewParam name="foo" value="#{bean.foo}" converter="fooConverter" />
 <f:viewAction action="otherpage" if="#{bean.foo eq null}" />
 

This is however not possible with standard <f:viewAction> as it evaluates the if attribute already before the conversion has taken place. This component solves that by postponing the evaluation of the if attribute to the INVOKE_APPLICATION phase.

 <f:viewParam name="foo" value="#{bean.foo}" converter="fooConverter" />
 <o:viewAction action="otherpage" if="#{bean.foo eq null}" />
 

Only when you set immediate="true", then it will behave the same as the standard <f:viewAction>.

Usage

You can use it the same way as <f:viewAction>, you only need to change f: to o:.

 <o:viewAction action="otherpage" if="#{bean.property eq null}" />
 

Messaging

You can use the message attribute to add a global flash warning message.

 <o:viewAction ... message="Please use a valid link from within the site" />
 

Note that the message will only be shown when the redirect has actually taken place. The support was added in OmniFaces 3.2.

viewParam

The <o:viewParam> is a component that extends the standard <f:viewParam> and provides a stateless mode of operation and fixes the issue wherein null model values are converted to empty string parameters in query string (e.g. when includeViewParams=true) and the (bean) validation never being triggered when the parameter is completely absent in query string, causing e.g. @NotNull to fail.

Stateless mode to avoid unnecessary conversion, validation and model updating on postbacks

The standard UIViewParameter implementation calls the model setter again after postback. This is not always desired when being bound to a view scoped bean and can lead to performance problems when combined with an expensive converter. To solve this, this component by default stores the submitted value as a component property instead of in the model (and thus in the view state in case the binding is to a view scoped bean).

The standard UIViewParameter implementation calls the converter and validators again on postbacks. This is not always desired when you have e.g. a required="true", but the parameter is not retained on form submit. You would need to retain it on every single command link/button by <f:param>. To solve this, this component doesn't call the converter and validators again on postbacks.

Using name as default for label

The <o:viewParam> also provides a default for the label atrribute. When the label attribute is omitted, the name attribute will be used as label.

Avoid unnecessary empty parameter in query string

The standard UIViewParameter implementation calls the converter regardless of whether the evaluated model value is null or not. As converters by specification return an empty string in case of null value, this is being added to the query string as an empty parameter when e.g. includeViewParams=true is used. This is not desired. The workaround was added in OmniFaces 1.8.

Support bean validation and triggering validate events on null value

The standard UIViewParameter implementation uses in JSF 2.0-2.2 an internal "is required" check when the submitted value is null, hereby completely bypassing the standard UIInput validation, including any bean validation annotations and even the PreValidateEvent and PostValidateEvent events. This is not desired. The workaround was added in OmniFaces 2.0. In JSF 2.3, this has been fixed and has only effect when jakarta.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL context param is set to true.

Default value when no parameter is set

The <o:viewParam> also supports providing a default value via the default attribute. When the parameter is not available, then the value specified in default attribute will be set in the model instead. The support was added in OmniFaces 2.2.

Usage

You can use it the same way as <f:viewParam>, you only need to change f: to o:.

 <o:viewParam name="foo" value="#{bean.foo}" />
 
viewParamValidationFailed

<o:viewParamValidationFailed> allows the developer to handle a view parameter validation failure with either a redirect or an HTTP error status, optionally with respectively a flash message or HTTP error message. This tag can be placed inside <f:metadata> or <f|o:viewParam>. When placed in <f|o:viewParam>, it will be applied when the particular view parameter has a validation error as per UIViewParameter#isValid(). When placed in <f:metadata>, and no one view parameter has already handled the validation error via its own <o:viewParamValidationFailed>, it will be applied when there's a general validation error as per FacesContext#isValidationFailed().

When the sendRedirect attribute is set, a call to Faces#redirect(String, Object...) is made internally to send the redirect. So, the same rules as to scheme and leading slash apply here. When the sendError attribute is set, a call to Faces#responseSendError(int, String) is made internally to send the error. You can therefore customize HTTP error pages via <error-page> entries in web.xml. Otherwise the server-default one will be displayed instead.

<f:viewParam required="true"> fail

As a precaution; be aware that <f:viewParam required="true"> has a design error in current Mojarra and MyFaces releases (as of now, Mojarra 2.2.7 and MyFaces 2.2.4). When the parameter is not specified in the query string, it is retrieved as null, which causes an internal isRequired() check to be performed instead of delegating the check to the standard UIInput implementation. This has the consequence that PreValidateEvent and PostValidateEvent listeners are never invoked, which the <o:viewParamValidationFailed> is actually relying on. This is fixed in <o:viewParam>.

Examples

In the example below the client will be presented an HTTP 400 error when at least one view param is absent.

 <f:metadata>
     <o:viewParam name="foo" required="true" />
     <o:viewParam name="bar" required="true" />
     <o:viewParamValidationFailed sendError="400" />
 </f:metadata>
 

In the example below the client will be redirected to "login.xhtml" when the "foo" parameter is absent, regardless of the "bar" parameter. When the "foo" parameter is present, but the "bar" parameter is absent, nothing new will happen. The process will proceed "as usual". I.e. the validation error will end up as a faces message in the current view the usual way.

 <f:metadata>
     <o:viewParam name="foo" required="true">
         <o:viewParamValidationFailed sendRedirect="login.xhtml" />
     </o:viewParam>
     <o:viewParam name="bar" required="true" />
 </f:metadata>
 

In the example below the client will be presented an HTTP 401 error when the "foo" parameter is absent, regardless of the "bar" or "baz" parameters. When the "foo" parameter is present, but either the "bar" or "baz" parameter is absent, the client will be redirected to "search.xhtml".

 <f:metadata>
     <o:viewParam name="foo" required="true">
         <o:viewParamValidationFailed sendError="401" />
     </o:viewParam>
     <o:viewParam name="bar" required="true" />
     <o:viewParam name="baz" required="true" />
     <o:viewParamValidationFailed sendRedirect="search.xhtml" />
 </f:metadata>
 

In a nutshell: when there are multiple <o:viewParamValidationFailed> tags, they will be applied in the same order as they are declared in the view. So, with the example above, the one nested in <f|o:viewParam> takes precedence over the one nested in <f:metadata>.

Messaging

By default, the first occurring faces message on the parent component will be copied, or when there is none then the first occurring global faces message will be copied. When sendRedirect is used, it will be set as a global flash error message. When sendError is used, it will be set as HTTP status message.

You can override this message by explicitly specifying the message attribute. This is applicable for both sendRedirect and sendError.

 <o:viewParamValidationFailed sendRedirect="search.xhtml" message="You need to perform a search." />
 ...
 <o:viewParamValidationFailed sendError="401" message="Authentication failed. You need to login." />
 

Note, although all of above examples use required="true", this does not mean that you can only use <o:viewParamValidationFailed> in combination with required="true" validation. You can use it in combination with any kind of conversion/validation on <f|o:viewParam>, even bean validation.

Design notes

You can technically nest multiple <o:viewParamValidationFailed> inside the same parent, but this is not the documented approach and only the first one would be used.

You can not change the HTTP status code of a redirect. This is not a Faces limitation, but an HTTP limitation. The status code of a redirect will always end up as the one of the redirected response. If you intend to "redirect" with a different HTTP status code, then you should be using sendError instead and specify the desired page as <error-page> in web.xml.

Function Summary 
TypeFunctionDescription
java.lang.Stringabbreviate(java.lang.String, int)Abbreviate the given text on the given size limit with ellipsis.
java.lang.ObjectaddDays(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of days.
java.lang.ObjectaddHours(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of hours.
java.lang.ObjectaddMinutes(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of minutes.
java.lang.ObjectaddMonths(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of months.
java.lang.ObjectaddSeconds(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of seconds.
java.lang.ObjectaddWeeks(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of weeks.
java.lang.ObjectaddYears(java.lang.Object, int)Returns a new date instance which is a sum of the given date and the given amount of years.
java.lang.Stringcapitalize(java.lang.String)Capitalize the given string, i.e. uppercase the first character.
java.lang.Objectcoalesce(java.lang.Object, java.lang.Object)Returns the first non-null object from the provided two objects. So, if the first object is not null, then it will be returned, otherwise the second object will be returned.
java.lang.Stringconcat(java.lang.Object, java.lang.Object)Concatenate the string representation of the given objects. This is useful when you don't know beforehand if one of the both hands is a string or is null, otherwise the EL #{bean.string1.concat(bean.string2)} can just be used.
booleancontains(java.lang.Object[], java.lang.Object)Returns true if the string representation of an item of the given array equals to the string representation of the given item. This returns false if either the array or the item is null. This is useful if you want to for example check if #{paramValues.foo} contains a certain value.
java.lang.Stringconvert(java.lang.String, java.lang.Object)Convert given object to string using Converter#getAsString(FacesContext, UIComponent, Object) of the converter identified by the given converter ID, invoked with FacesContext#getCurrentInstance(), UIComponent#getCurrentComponent(FacesContext) and given object as arguments.
java.lang.Object[]createArray(int)Creates and returns a dummy object array of the given size. This is useful if you want to iterate n times over an <ui:repeat>, which doesn't support EL in begin and end attributes.
java.lang.Integer[]createIntegerArray(int, int)Creates and returns an integer array which starts at the given integer and ends at the given integer, inclusive. This is useful if you want to for example populate a <f:selectItems> which shows an integer range to represent days and years. If the begin is greater than end, then the array will be decremental. If the begin equals end, then the array will contain only one item.
intdaysBetween(java.lang.Object, java.lang.Object)Returns the amount of days between two given dates. This will be negative when the end date is before the start date.
java.lang.StringencodeBase64(java.lang.String)Base64-encode the given string. This is useful for cases where you need to create data URLs.
java.lang.StringencodeURI(java.lang.String)URI-encode the given string using UTF-8. This is useful for cases where you need to embed path parameters in URLs.
java.lang.StringencodeURL(java.lang.String)URL-encode the given string using UTF-8. This is useful for cases where you can't use <f:param>.
java.lang.StringescapeJS(java.lang.String)Escapes the given string according the JavaScript code rules. This escapes among others the special characters, the whitespace, the quotes and the unicode characters. Useful whenever you want to use a Java string variable as a JavaScript string variable.
java.lang.ObjectevalAttribute(jakarta.faces.component.UIComponent, java.lang.String)Evaluates an attribute of a component by first checking if there's a value expression associated with it, and only if there isn't one look at a component property with that name.

The regular attribute collection (UIComponent#getAttributes()) does exactly the reverse; it looks at a component property first, then at the attribute collection and only looks at a value binding as the last option.

java.lang.StringflagEmoji(java.lang.String)Converts the given ISO 3166-1 alpha-2 country code to corresponding Unicode flag emoji.
java.lang.Stringformat1(java.lang.String, java.lang.Object)Format the given string with 1 parameter using MessageFormat API. The locale is obtained by Faces#getLocale(). Design notice: There are five formatX() methods, each taking 1 to 5 format parameters because EL functions do not support varargs methods nor overloaded function names.
java.lang.Stringformat2(java.lang.String, java.lang.Object, java.lang.Object)Format the given string with 2 parameters using MessageFormat API. The locale is obtained by Faces#getLocale(). Design notice: There are five formatX() methods, each taking 1 to 5 format parameters because EL functions do not support varargs methods nor overloaded function names.
java.lang.Stringformat3(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Object)Format the given string with 3 parameters using MessageFormat API. The locale is obtained by Faces#getLocale(). Design notice: There are five formatX() methods, each taking 1 to 5 format parameters because EL functions do not support varargs methods nor overloaded function names.
java.lang.Stringformat4(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)Format the given string with 4 parameters using MessageFormat API. The locale is obtained by Faces#getLocale(). Design notice: There are five formatX() methods, each taking 1 to 5 format parameters because EL functions do not support varargs methods nor overloaded function names.
java.lang.Stringformat5(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)Format the given string with 5 parameters using MessageFormat API. The locale is obtained by Faces#getLocale(). Design notice: There are five formatX() methods, each taking 1 to 5 format parameters because EL functions do not support varargs methods nor overloaded function names.
java.lang.StringformatBytes(java.lang.Long)Format the given bytes to nearest 10n in the default pattern of the default locale with IEC binary unit (KiB, MiB, etc) with rounding precision of 1 fraction. For example (with English locale):
  • 1023 bytes will appear as 1023 B
  • 1024 bytes will appear as 1.0 KiB
  • 500000 bytes will appear as 488.3 KiB
  • 1048576 bytes will appear as 1.0 MiB
The default locale is the one as obtained by Faces#getLocale().
java.lang.StringformatBytesForLocale(java.lang.Long, java.lang.Object)Format the given bytes to nearest 10n in the default pattern of the given locale with IEC binary unit (KiB, MiB, etc) with rounding precision of 1 fraction. For example (with English locale):
  • 1023 bytes will appear as 1023 B
  • 1024 bytes will appear as 1.0 KiB
  • 500000 bytes will appear as 488.3 KiB
  • 1048576 bytes will appear as 1.0 MiB
The given locale can be a Locale object or a string representation.
java.lang.StringformatCurrency(java.lang.Number, java.lang.String)Format the given number as currency with the given symbol in the default pattern of the default locale. This is useful when you want to format numbers as currency in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The format locale will be set to the one as obtained by Faces#getLocale().
java.lang.StringformatCurrencyForLocale(java.lang.Number, java.lang.String, java.lang.Object)Format the given number as currency with the given symbol in the default pattern of the given locale. This is useful when you want to format numbers as currency in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The given locale can be a Locale object or a string representation.
java.lang.StringformatDate(java.lang.Object, java.lang.String)Format the given date in the given pattern with the default timezone. This is useful when you want to format dates in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertDateTime> tag. The format locale will be set to the one as obtained by Faces#getLocale().
java.lang.StringformatDateWithTimezone(java.lang.Object, java.lang.String, java.lang.Object)Format the given date in the given pattern with the given timezone. This is useful when you want to format dates in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertDateTime> tag. The format locale will be set to the one as obtained by Faces#getLocale().
java.lang.StringformatNumber(java.lang.Number, java.lang.String)Format the given number in the given pattern. This is useful when you want to format numbers in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The format locale will be set to the one as obtained by Faces#getLocale().
java.lang.StringformatNumberDefault(java.lang.Number)Format the given number in the default pattern of the default locale. This is useful when you want to format numbers in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The default locale is the one as obtained by Faces#getLocale().
java.lang.StringformatNumberDefaultForLocale(java.lang.Number, java.lang.Object)Format the given number in the default pattern of the given locale. This is useful when you want to format numbers in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The given locale can be a Locale object or a string representation.
java.lang.StringformatPercent(java.lang.Number)Format the given number as percentage in the default pattern of the default locale. This is useful when you want to format numbers as percentage in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The default locale is the one as obtained by Faces#getLocale().
java.lang.StringformatPercentForLocale(java.lang.Number, java.lang.Object)Format the given number as percentage in the default pattern of the given locale. This is useful when you want to format numbers as percentage in for example the title attribute of an UI component, or the itemLabel attribute of select item, or wherever you can't use the <f:convertNumber> tag. The given locale can be a Locale object or a string representation.
java.lang.StringformatThousands(java.lang.Number)Format the given number to nearest 10n (rounded to thousands) in the default pattern of the default locale, immediately suffixed (without space) with metric unit (k, M, G, T, P or E), rounding half up with a precision of 3 digits, whereafter trailing zeroes in fraction part are stripped. For example (with English locale):
  • 1.6666 will appear as 1.67
  • 999.4 will appear as 999
  • 999.5 will appear as 1k
  • 1004 will appear as 1k
  • 1005 will appear as 1.01k
  • 1594 will appear as 1.59k
  • 1595 will appear as 1.6k
  • 9000 will appear as 9k
  • 9900 will appear as 9.9k
  • 9994 will appear as 9.99k
  • 9995 will appear as 10k
  • 99990 will appear as 100k
  • 9994999 will appear as 9.99M
  • 9995000 will appear as 10M
The default locale is the one as obtained by Faces#getLocale(). If the value is null, NaN or infinity, then this will return null.
java.lang.StringformatThousandsForLocale(java.lang.Number, java.lang.Object)Format the given number to nearest 10n (rounded to thousands) in the default pattern of the given locale, immediately suffixed (without space) with metric unit (k, M, G, T, P or E), rounding half up with a precision of 3 digits, whereafter trailing zeroes in fraction part are stripped. For example (with English locale):
  • 1.6666 will appear as 1.67
  • 999.4 will appear as 999
  • 999.5 will appear as 1k
  • 1004 will appear as 1k
  • 1005 will appear as 1.01k
  • 1594 will appear as 1.59k
  • 1595 will appear as 1.6k
  • 9000 will appear as 9k
  • 9900 will appear as 9.9k
  • 9994 will appear as 9.99k
  • 9995 will appear as 10k
  • 99990 will appear as 100k
  • 9994999 will appear as 9.99M
  • 9995000 will appear as 10M
The given locale can be a Locale object or a string representation. If the value is null, NaN or infinity, then this will return null.
java.lang.StringformatThousandsUnit(java.lang.Number, java.lang.String)Format the given number to nearest 10n (rounded to thousands) in the default pattern of the default locale, suffixed with a space, the metric unit prefix (k, M, G, T, P or E) and the given unit, rounding half up with a precision of 3 digits, whereafter trailing zeroes in fraction part are stripped. For example (with English locale and unit B):
  • 1.6666 will appear as 1.67 B
  • 999.4 will appear as 999 B
  • 999.5 will appear as 1 kB
  • 1004 will appear as 1 kB
  • 1005 will appear as 1.01 kB
  • 1594 will appear as 1.59 kB
  • 1595 will appear as 1.6 kB
  • 9000 will appear as 9 kB
  • 9900 will appear as 9.9 kB
  • 9994 will appear as 9.99 kB
  • 9995 will appear as 10 kB
  • 99990 will appear as 100 kB
  • 9994999 will appear as 9.99 MB
  • 9995000 will appear as 10 MB
The default locale is the one as obtained by Faces#getLocale(). If the value is null, NaN or infinity, then this will return null.
java.lang.StringformatThousandsUnitForLocale(java.lang.Number, java.lang.String, java.lang.Object)Format the given number to nearest 10n (rounded to thousands) in the default pattern of the given locale, suffixed with a space, the metric unit prefix (k, M, G, T, P or E) and the given unit, rounding half up with a precision of 3 digits, whereafter trailing zeroes in fraction part are stripped. For example (with English locale and unit B):
  • 1.6666 will appear as 1.67 B
  • 999.4 will appear as 999 B
  • 999.5 will appear as 1 kB
  • 1004 will appear as 1 kB
  • 1005 will appear as 1.01 kB
  • 1594 will appear as 1.59 kB
  • 1595 will appear as 1.6 kB
  • 9000 will appear as 9 kB
  • 9900 will appear as 9.9 kB
  • 9994 will appear as 9.99 kB
  • 9995 will appear as 10 kB
  • 99990 will appear as 100 kB
  • 9994999 will appear as 9.99 MB
  • 9995000 will appear as 10 MB
The given locale can be a Locale object or a string representation. If the value is null, NaN or infinity, then this will return null.
java.lang.StringgetDayOfWeek(java.lang.Integer)Returns the day of week name from the mapping associated with the given day of week number in ISO 8601 order (Monday first) for the current locale. For example: "1=Monday", "2=Tuesday", etc. The locale is obtained by Faces#getLocale().
java.util.MapgetDaysOfWeek()Returns a mapping of day of week names in ISO 8601 order (Monday first) for the current locale. For example: "Monday=1", "Tuesday=2", etc. This is useful if you want to for example populate a <f:selectItems> which shows all days of week. The locale is obtained by Faces#getLocale(). The mapping is per locale stored in a local cache to improve retrieving performance.
java.lang.StringgetMonth(java.lang.Integer)Returns the month name from the mapping associated with the given month number for the current locale. For example: "1=January", "2=February", etc. The locale is obtained by Faces#getLocale().
java.util.MapgetMonths()Returns a mapping of month names by month numbers for the current locale. For example: "January=1", "February=2", etc. This is useful if you want to for example populate a <f:selectItems> which shows all months. The locale is obtained by Faces#getLocale(). The mapping is per locale stored in a local cache to improve retrieving performance.
java.lang.StringgetRemoteAddr()Returns the Internet Protocol (IP) address of the client that sent the request. This will first check the X-Forwarded-For request header and if it's present, then return its first IP address, else just return HttpServletRequest#getRemoteAddr() unmodified.

This is also available in EL as #{faces.remoteAddr}.

java.lang.StringgetRequestBaseURL()Returns the HTTP request base URL. This is the URL from the scheme, domain until with context path, including the trailing slash. This is the value you could use in HTML <base> tag.

This is also available in EL as #{faces.requestBaseURL}.

java.lang.StringgetRequestDomainURL()Returns the HTTP request domain URL. This is the URL with the scheme and domain, without any trailing slash.

This is also available in EL as #{faces.requestDomainURL}.

java.lang.StringgetRequestURLWithQueryString()Returns the HTTP request URL with query string. This is the full request URL with query string as the enduser sees in browser address bar.

This is also available in EL as #{faces.requestURLWithQueryString}.

java.lang.StringgetShortDayOfWeek(java.lang.Integer)Returns the short day of week name from the mapping associated with the given day of week number in ISO 8601 order (Monday first) for the current locale. For example: "1=Mon", "2=Tue", etc. The locale is obtained by Faces#getLocale().
java.util.MapgetShortDaysOfWeek()Returns a mapping of short day of week names in ISO 8601 order (Monday first) for the current locale. For example: "Mon=1", "Tue=2", etc. This is useful if you want to for example populate a <f:selectItems> which shows all short days of week. The locale is obtained by Faces#getLocale(). The mapping is per locale stored in a local cache to improve retrieving performance.
java.lang.StringgetShortMonth(java.lang.Integer)Returns the short month name from the mapping associated with the given month number for the current locale. For example: "1=Jan", "2=Feb", etc. The locale is obtained by Faces#getLocale().
java.util.MapgetShortMonths()Returns a mapping of short month names by month numbers for the current locale. For example: "Jan=1", "Feb=2", etc. This is useful if you want to for example populate a <f:selectItems> which shows all short months. The locale is obtained by Faces#getLocale(). The mapping is per locale stored in a local cache to improve retrieving performance.
java.lang.StringgraphicImageURL(java.lang.String)

Returns @GraphicImageBean URL based on given expression string.

Usage example:

 <a href="#{o:graphicImageURL('images.full(product.imageId)')}">
     <o:graphicImage value="#{images.thumb(product.imageId)}" />
 </a>
 
java.lang.StringgraphicImageURLWithType(java.lang.String, java.lang.String)

Returns @GraphicImageBean URL based on given expression string and image type.

Usage example:

 <a href="#{o:graphicImageURLWithType('images.full(product.imageId)', 'png')}">
     <o:graphicImage value="#{images.thumb(product.imageId)}" type="png" />
 </a>
 
java.lang.StringgraphicImageURLWithTypeAndLastModified(java.lang.String, java.lang.String, java.lang.Object)

Returns @GraphicImageBean URL based on given expression string, image type and last modified.

Usage example:

 <a href="#{o:graphicImageURLWithTypeAndLastModified('images.full(product.imageId)', 'png', product.lastModified)}">
     <o:graphicImage value="#{images.thumb(product.imageId)}" type="png" lastModified="#{product.lastModified}" />
 </a>
 
longhoursBetween(java.lang.Object, java.lang.Object)Returns the amount of hours between two given dates. This will be negative when the end date is before the start date.
booleanisInstance(java.lang.String, java.lang.Object)Returns true if given object is an instance of the class as identified by given class name.
java.util.ListiterableToList(java.lang.Iterable)Converts a Iterable<E> to a List<E>.

When iterating specifically over a Set using the above mentioned components Converters#setToList(Set) is an alternative to this.

jakarta.faces.model.DataModeliterableToModel(java.lang.Iterable)Converts an Iterable<E> to a DataModel<E>.

When iterating specifically over a Set using the above mentioned components Converters#setToList(Set) is an alternative to this. Use this for more general cases or when the exact collection type is unknown.

For those same components Converters#iterableToList(Iterable) is another alternative. Use this when a DataModel is specifically needed.

java.lang.StringjoinArray(java.lang.Object, java.lang.String)Joins all elements of the given array to a single string, separated by the given separator.
java.lang.StringjoinCollection(java.util.Collection, java.lang.String)Joins all elements of the given collection to a single string, separated by the given separator.
java.lang.StringjoinMap(java.util.Map, java.lang.String, java.lang.String)Joins all elements of the given map to a single string, separated by the given key-value pair separator and entry separator.
java.util.ListmapToList(java.util.Map)Converts a Map<K, V> to a List<Map.Entry<K, V>>. Each of the entries has the usual getKey() and getValue() methods.
booleanmatches(java.lang.String, java.lang.String)Returns true if the given string matches the given pattern.
longminutesBetween(java.lang.Object, java.lang.Object)Returns the amount of minutes between two given dates. This will be negative when the end date is before the start date.
intmonthsBetween(java.lang.Object, java.lang.Object)Returns the amount of months between two given dates. This will be negative when the end date is before the start date.
java.lang.Stringparenthesize(java.lang.Object)Parenthesize the given object. This will only wrap the given object in parenthesis when it's not empty or zero.
java.lang.StringprettyURL(java.lang.String)URL-prettify the given string. It performs the following tasks:
  • Lowercase the string.
  • Remove combining diacritical marks.
  • Replace non-alphanumeric characters by hyphens.
This is useful when populating links with dynamic paths obtained from user controlled variables, such as blog titles.
java.lang.StringprintStackTrace(java.lang.Throwable)Print the stack trace of the given exception.
java.lang.StringreplaceAll(java.lang.String, java.lang.String, java.lang.String)Replace all matches of the given pattern on the given string with the given replacement.
java.lang.Object[]reverseArray(java.lang.Object[])Returns a copy of the array with items in reversed order.
longsecondsBetween(java.lang.Object, java.lang.Object)Returns the amount of seconds between two given dates. This will be negative when the end date is before the start date.
java.util.ListsetToList(java.util.Set)Converts a Set<E> to a List<E>.
java.lang.Object[][]splitArray(java.lang.Object, int)Splits the given array into an array of subarrays of the given fragment size. This is useful for creating nested <ui:repeat> structures, for example, when positioning a list of items into a grid based layout system such as Twitter Bootstrap.
java.util.ListsplitList(java.util.List, int)Splits the given list into a list of sublists of the given fragment size. This is useful for creating nested <ui:repeat> structures, for example, when positioning a list of items into a grid based layout system such as Twitter Bootstrap.
java.lang.StringstripTags(java.lang.String)Remove XML tags from a string and return only plain text.
java.lang.StringtoJson(java.lang.Object)Encode given object as JSON. Currently, this delegates directly to Json#encode(Object).
intweeksBetween(java.lang.Object, java.lang.Object)Returns the amount of weeks between two given dates. This will be negative when the end date is before the start date.
intyearsBetween(java.lang.Object, java.lang.Object)Returns the amount of years between two given dates. This will be negative when the end date is before the start date.

Output generated by Vdldoc View Declaration Language Documentation Generator.