Annotation Interface DynTab
Placed on a class that implements DyntabBeanInterface.
The DynTabs library automatically scans all beans with this annotation
and registers them in DynTabRegistry.
This eliminates the need for manual registration in a DynTabConfig subclass!
The annotation is @Repeatable - it can be placed multiple times on the same class.
This allows a single CDI bean to serve as the basis for multiple different tabs,
each with its own name, title, and parameters. Typical example: same XHTML page
and same bean, but with different parameters controlling behavior.
Single tab example:
@Named
@TabScoped
@DynTab(name = "UsersDynTab",
uniqueIdentifier="Users",
title = "The Users",
includePage = "/WEB-INF/include/users/users.xhtml")
public class UsersBean implements DyntabBeanInterface {
// just business logic, no manual registration needed
}
Two tabs on the same bean (one secured with declarative roles):
@Named
@TabScoped
@DynTab(name = "DocumentsDynTab",
uniqueIdentifier="Documents",
title = "The Documents",
includePage = "/WEB-INF/include/docs/docs.xhtml",
parameters = {"listAll=false"})
@DynTab(name = "AllDocsDynTab",
uniqueIdentifier="AllDocs",
title = "All Documents",
closeable = true,
securedResource = true,
allowedRoles = {"ADMIN", "MANAGER"},
includePage = "/WEB-INF/include/docs/docs.xhtml",
parameters = {"listAll=true"})
public class DocsBean implements DyntabBeanInterface {
// "Documents" tab is open to everyone
// "AllDocs" tab requires ADMIN or MANAGER role
}
Menu items can then simply use:
<p:menuitem value="Users" action="uishell:Users" />
<p:menuitem value="Documents" action="uishell:Documents" />
<p:menuitem value="All Documents" action="uishell:AllDocs" />
so, the pattern for action atribute value is: "uishell:_dynTab_uniqueIdentifier"
NOTE: The bean MUST implement DyntabBeanInterface.
Using @TabScoped instead of @ViewScoped is recommended for isolation between tabs.
- Author:
- DynTabs
- See Also:
-
Required Element Summary
Required Elements -
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptionString[]Roles allowed to access this tab (declarative access control).booleanWhether the user can close the tab by clicking the X button.String[]Tab parameters in "key=value" format.booleanWhether this dynamic tab is a secured (protected) resource.Human-readable display name for this secured resource.booleanWhether opening this tab should record aNAVIGATIONentry on the ambient activity timeline, so an AI assistant wired with.withActivityContext(...)knows the user just navigated here.Unique identifier for the tab.
-
Element Details
-
name
String nameThe tab name for registration (e.g. "UsersDynTab").This name is used in action outcomes on XHTML pages:
action="uishell:Users"will look for a tab registered as "UsersDynTab". Convention: bean name + "DynTab" suffix. -
title
String titleThe tab title displayed to the user in the tab header.Can be:
- Plain text: "Users"
- EL expression:
"#{msg['users.title']}" - EL expression with a bean:
"#{usersBean.tabTitle}"
-
includePage
String includePagePath to the XHTML page included in the tab.Example: "/WEB-INF/include/users/users.xhtml"
This page will be rendered inside the tab and has access to the dynTab object via the
#{dynTab}parameter. -
closeable
boolean closeableWhether the user can close the tab by clicking the X button.Default: true
For "Home" or "Dashboard" tabs that should always remain open, set this to false.
- Default:
true
-
uniqueIdentifier
String uniqueIdentifierUnique identifier for the tab.Used to check if a tab already exists (to prevent opening duplicates).
If not specified, it is automatically derived from the
name()attribute by removing the "DynTab" suffix (e.g. "UsersDynTab" -> "Users").- Default:
""
-
securedResource
boolean securedResourceWhether this dynamic tab is a secured (protected) resource.When set to
true, theAbstractSecuredResourceScannerregisters this tab'suniqueIdentifier()as a secured resource at deploy time. TheAbstractAccessCheckInterceptorthen enforces access control when the tab is opened viacallAccessPointMethod().Access rights can be granted in two ways:
- Declarative (InMemory): Specify
allowedRoles()in this annotation. TheInMemorySecuredResourceScannerreads bothsecuredResourceandallowedRolesat deploy time and stores them in memory. The pairedInMemoryAccessCheckInterceptorenforces access based on these declared roles. This is the default approach — zero configuration, everything is declared in the annotation. - DB-based: The developer creates a custom
DBSecuredResourceScanner(extendingAbstractSecuredResourceScanner) that writes secured resources to a database table, ignoringallowedRoles. Access rules are managed through an Admin UI. A pairedDBAccessCheckInterceptorreads allowed roles from the database at runtime.
Default:
false(tab is not protected)- Default:
false
- Declarative (InMemory): Specify
-
securedResourceDisplayName
String securedResourceDisplayNameHuman-readable display name for this secured resource.Used in admin UIs for security management. Can be a literal string or a resource bundle key for i18n. Only meaningful when
securedResource()istrue.- Default:
""
-
allowedRoles
String[] allowedRolesRoles allowed to access this tab (declarative access control).Used by the
InMemorySecuredResourceScanner/InMemoryAccessCheckInterceptorpair. Only meaningful whensecuredResource()istrue.Example:
@DynTab(name = "AllDocsDynTab", uniqueIdentifier = "AllDocs", title = "All Documents", securedResource = true, allowedRoles = {"ADMIN", "MANAGER"}, includePage = "/WEB-INF/include/docs/docs.xhtml")Ignored by DB-based implementations, where access rules are managed through an Admin UI and stored in the database.
- Default:
{}
-
parameters
String[] parametersTab parameters in "key=value" format.Examples:
{"listAll=false", "mode=edit"}{"maxResults=50"}- For EL expressions:
{"dynamicParam=#{someBean.value}"}
Parameters are accessible in the bean via:
getParameters().get("key")getDynTab().getParameters().get("key")
- Default:
{}
-
trackActivity
boolean trackActivityWhether opening this tab should record aNAVIGATIONentry on the ambient activity timeline, so an AI assistant wired with.withActivityContext(...)knows the user just navigated here.This is the declarative, navigation-flavoured counterpart to placing
@ActivityTracked(type = NAVIGATION)on the tab's entry method: whentrue, the framework emits aUserActivityEventof typeUserActivityEvent.Type.NAVIGATION(tagged with the tab'suniqueIdentifier()andtitle()) as the tab is opened. Captured activity is read back by aActivityContextto make the assistant context-aware.Default:
false(opening the tab records nothing).- See Also:
- Default:
false
-