You can use the Portal Framework provided with the Stardust Portal to modify and extend the content of the Stardust Portal and add your own application components.
Two basic elements are required to develop Portal Add-ons:
This chapter explains the necessary steps in detail using the example of a Support Case Management Application. You need to adjust file names and the like for your own projects accordingly.
As the concept of Utility JARs also allow for the development of persistence-capable Business Objects and transactional Business Services, we will be showing the implementation accordingly in the last section of this chapter.
Application components developed with the concepts described below can be very easily deployed via Stardust On Demand, SunGard's Platform as a Service (PaaS) offering.
Java Server Faces (JSF) are a technology to develop browser-based UI components by separating the presentation and behavior into XML markup and Java code. For more details consider the following Overview Web Page.
ICEfaces is an AJAX-based Open Source implementation of JSF with a rich set of components (trees, tables, RTF editors, drag & drop etc.). Download links, demos, documentation, tutorials and community forums are provided on www.icefaces.org.
You don't need to download ICEfaces for the following as Stardust is shipping the complete ICEfaces library set in the Stardust distribution.
The development of Stardust Portal Add-ons relies on Spring concepts such as Dependency Injection.
For more information about Spring consult www.springsource.com.
Stardust Portal Add-ons are deployed as Utility JARs containing
The easiest way to provide these components is to create a Utility Project in Eclipse and set up a source folder structure like
src/
com/
bpm/
framework/
support/
META-INF/
spring/
support-perspective-context.xml
support-perspectiveUI-context.xml
webapp/
launchpanels/
supportLaunchPanel.xhtml
views/
supportCaseManagementPanel.xhtml
Additionally a file support-perspective.portal-plugin and a directory config/
are created which may contain other resources to be loaded from the classpath such as .properties
files for localization, e.g.:
The content of this file structure is explained in subsequent sections.
The file support-perspective.portal-plugin contains the following
/META-INF/webapp/
The directory com/ contains the source code of JSF backing beans and
possibly further business logic.
The Spring Configuration e.g. META-INF/spring/support-perspective-context.xml
contains the definition of all backing beans and their dependency injection
relationships, e.g.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean name="supportPerspectiveMessages" class="com.bpm.framework.support.portal.messages.Messages" scope="session">
</bean>
<bean name="supportService" class="com.bpm.framework.support.SupportServiceBean" scope="session">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
...
<bean name="supportSession" class="com.bpm.framework.support.portal.SupportSession" scope="session">
<property name="supportService" ref="supportService"/>
</bean>
<bean name="supportCaseManagementPanel" class="com.bpm.framework.support.portal.SupportCaseManagementPanel" scope="session">
<property name="supportService" ref="supportService"/>
</bean>
</beans>
Settings for the Portal Framework are specified in a XML UI configuration file,
e.g. support-perspectiveUI-context.xml which contains the definition
of Perspectives, Views and Launch Panels (see below), e.g.the following
for the definition of a Support Perspective
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ippui="http://infinity.com/bpm/portal/common/uiDefinition"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://infinity.com/bpm/portal/common/uiDefinition http://infinity.com/bpm/portal/common/uiDefinition.xsd">
<ippui:perspective id="supportPerspective" messageBundles="support-perspective-messages">
<ippui:launchPanel name="supportLaunchPanel" include="/plugins/support-perspective/launchpanels/supportLaunchPanel.xhtml" />
<ippui:launchPanel name="extensions"/>
<ippui:view name="supportCaseManagementPanel" include="/plugins/support-perspective/views/supportCaseManagementPanel.xhtml" />
</ippui:perspective>
</beans
Note, that - as opposed to META-INF/spring/support-perspective-context.xml
- the format of this configuration file is an Stardust proprietary format.
For details of the UI Spring Configuration file format consider the following XSD file.
All Web content (JSF markup, CSS files, images) are contained under META-INF/webapp.
The structure
/launchpanels /views
is used for convenience. You may decide for a different structure in your projects.
To use all artefacts implemented in the Utility Project described above, you just need to embed this project in a Stardust RAD Project by defining

in the Properties Dialog of the RAD Project.
This section explains how to develop and configure UI components to be injected into the Stardust Portal.
The Stardust Portal has the following structure
For more details of the Portal Functionality consult the corresponding chapters in the Stardust End User Documentation.
Perspectives are the rubber bands to define additional UI components. A Perspective may define
Views are defined in a perspective but can be used independently of the Perspective. All aspects of a Perspective are defined in the Spring UI Configuration File, e.g.
e.g. support-perspectiveUI-context.xml which contains the definition
of Perspectives, Views and Launch Panels (see below), e.g.the following
for the definition of a Support Perspective
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ippui="http://infinity.com/bpm/portal/common/uiDefinition"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://infinity.com/bpm/portal/common/uiDefinition http://infinity.com/bpm/portal/common/uiDefinition.xsd">
<ippui:perspective id="supportPerspective" messageBundles="support-messages">
...
</ippui:perspective>
</beans>
For details of the UI Spring Configuration file format consider the following
XSD file.
Launch Panels are defined in the Spring UI configuration, e.g. support-perspectiveUI-context.xml,
e.g. via
... <ippui:launchPanel name="supportLaunchPanel" include="/plugins/support-perspective/launchpanels/supportLaunchPanel.xhtml" /> ...
and implemented as
<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<ice:panelGrid columns="1" style="margin-top: 10px;">
<ice:commandLink action="#{supportCasePanel.createSupportCase}" styleClass="action-link">
<ice:outputText value="#{supportMessages['launchPanel.createSupportCaseLink.label']} &raquo;"
escape="false" styleClass="action-link"/>
</ice:commandLink>
<ice:commandLink action="#{ippPortalApp.openView}" styleClass="action-link">
<f:param name="viewId" value="supportCaseManagementPanel" />
<f:param name="msgBean"
value="#{supportMessages}" />
<ice:outputText value="#{supportMessages['launchPanel.supportCaseManagementLink.label']} &raquo;"
escape="false" styleClass="action-link"/>
</ice:commandLink>
</ice:panelGrid>
</f:view>
The result looks like the following

The following two events are fired for perspectives:
To use perspective events, perform the following steps:
*Ui-context.xml, e.g.:
<ippui:perspective
id="myPerspective"
messageBundles="my-perspective-messages"
controller="myPerspectiveEventHandler">
...
</ippui:perspective>session or globalSession as applicable, e.g.:
<bean name="myPerspectiveEventHandler" class="com.MyPerspectiveEventHandler" scope="session"> </bean>
org.eclipse.stardust.ui.web.common.event.PerspectiveEventHandler.
public class MyPerspectiveEventHandler implements PerspectiveEventHandler
{
private boolean initialized;
/* (non-Javadoc)
* @see org.eclipse.stardust.ui.web.common.event.PerspectiveEventHandler#handleEvent(org.eclipse.stardust.ui.web.common.event.PerspectiveEvent)
*/
public void handleEvent(PerspectiveEvent event)
{
switch (event.getType())
{
case ACTIVATED:
if (!initialized)
{
// **********
// TODO: Initialize Perspective Here
// **********
initialized = true;
}
break;
}
}
}You can create messages like in the example below to change perspectives.
{
"type":"ChangePerspective",
"data": {"perspectiveId": "ippBccPerspective"}
}
{
"type":"ChangePerspective",
"data": {"perspectiveId": "WorkflowExecution"}
}
{
"type":"ChangePerspective",
"data": {"perspectiveId": "ippAdminPerspective"}
}
These messages can be added as JavaScript to your custom Web applications and
then be posted via parent.postMessage(message, "*");.
A view is an arbitrary ICEfaces Facelet which is intended to be opened in the View Area of the Portal Framework, e.g.
<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<ice:outputDeclaration doctypeRoot="HTML"
doctypePublic="-//W3C//DTD HTML 4.01 Transitional//EN"
doctypeSystem="http://www.w3.org/TR/html4/loose.dtd" />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
<ice:outputStyle href="/plugins/common/css/ipp-portal.css" />
</head>
<body>
<ice:form id="supportCaseForm">
<ice:panelGroup style="margin: 10px;">
<ice:panelGrid columns="2">
<ice:outputLabel for="oidText" value="ID:" style="line-height:200%" />
<ice:outputText id="oidText"
value="#{supportCasePanel.supportCase.oid}">
</ice:outputText>
<ice:outputLabel for="creationDateText" value="Creation Date:"
style="line-height:200%" />
<ice:outputText id="creationDateText"
value="#{supportCasePanel.supportCase.creationDate}">
</ice:outputText>
<ice:outputLabel for="customerNameEntry" value="Customer Name:"
style="line-height:200%" />
<ice:inputText id="customerNameEntry" size="30" maxlength="30"
value="#{supportCasePanel.supportCase.customerName}">
</ice:inputText>
<ice:outputLabel for="customerIdEntry" value="Customer Id:"
style="line-height:200%" />
<ice:inputText id="customerIdEntry" size="20" maxlength="20"
value="#{supportCasePanel.supportCase.customerId}">
</ice:inputText>
<ice:outputLabel for="synopsisEntry" value="Synopsis:"
style="line-height:200%" />
<ice:inputText id="synopsisEntry" size="80" maxlength="80"
value="#{supportCasePanel.supportCase.synopsis}">
</ice:inputText>
<ice:outputLabel value="Type:" style="line-height:200%" />
<ice:selectOneMenu size="1"
valueChangeListener="#{supportCasePanel.selectionChange}"
style="overflow: auto; width: 250px; margin: 5px; vertical-align: top;">
<f:selectItems
value="#{supportConfigurationPanel.supportCaseTypes}" />
</ice:selectOneMenu>
<ice:outputLabel value="Product Component:" style="line-height:200%" />
<ice:selectOneMenu size="1"
valueChangeListener="#{supportCasePanel.selectionChange}"
style="overflow: auto; width: 250px; margin: 5px; vertical-align: top;">
<f:selectItems
value="#{supportConfigurationPanel.productComponents}" />
</ice:selectOneMenu>
<ice:outputLabel value="State:" style="line-height:200%" />
<ice:selectOneMenu size="1"
valueChangeListener="#{supportCasePanel.selectionChange}"
style="overflow: auto; width: 250px; margin: 5px; vertical-align: top;">
<f:selectItems
value="#{supportConfigurationPanel.supportCaseStates}" />
</ice:selectOneMenu>
<ice:outputLabel for="descriptionEntry" value="Description:"
style="line-height:200%" />
<ice:inputTextarea id="descriptionEntry" cols="80" rows="8"
style="width:280px;height:80px;overflow: auto;"
value="#{supportCasePanel.supportCase.description}">
</ice:inputTextarea>
</ice:panelGrid>
</ice:panelGroup>
</ice:form>
</body>
</html>
</f:view>
Views are defined in the Spring UI Configuration File , e.g. support-perspectiveUI-context.xml,
e.g. via
... <ippui:view name="supportCaseManagementPanel" include="/plugins/support-perspective/views/supportCaseManagementPanel.xhtml"/> ...
Views are defined in a perspective but can be used independently of the Perspective.
To explicitly open a View, e.g. from a Perspective Launch Panel use the following markup
<ice:commandLink action="#{ippPortalApp.openView}" styleClass="action-link">
<f:param name="viewId" value="supportCaseManagementPanel" />
<f:param name="viewParams" value="guid=#{row.oid}"/>
<f:param name="msgBean" value="#{supportPerspectiveMessages}" />
<ice:outputText value="Support Case Administration &raquo;" escape="false" styleClass="action-link"/>
</ice:commandLink>
Hereby
See the screenshot below for an example of two Views displayed in the View
Area.

Arbitrary parameters for View initialization can be defined in viewParams
in the format
parameter1=value1?parameter2=value2?...
To evaluate the parameters define a Controller Bean for the View in the
Spring UI Configuration e.g.
<ippui:view name="supportCaseView" include="..." controller="supportCaseView">
whereby the latter Bean name supportCaseView refers to a Bean defined
in the Spring Configuration.
The Controller Bean Needs to implement org.eclipse.stardust.ui.web.common.event.ViewEventHandler.
In the corresponding handleEvent(ViewEvent event) method it can
initialize itself for the CREATED event, by reading view parameters,
e.g.
public void handleEvent(ViewEvent event)
{
if (ViewEventType.CREATED == event.getType())
{
Map<String, Object> viewParams = event.getView().getViewParams();
long oid = viewParams.get("oid");
setSupportCase(getSupportService().findSupportCaseByOid());
}
}
Other view events are
TO_BE_ACTIVATEDACTIVATEDTO_BE_DEACTIVATEDDEACTIVATED, TO_BE_CLOSEDCLOSEDTO_BE_FULL_SCREENEDFULL_SCREENEDTO_BE_RESTORED_TO_NORMALRESTORED_TO_NORMALTO_BE_PINNEDPINNEDLAUNCH_PANELS_ACTIVATEDLAUNCH_PANELS_DEACTIVATEDPOST_OPEN_LIFECYCLETo define a View-specific toolbar, e.g. to refresh the view against database content define
<ippui:toolbarSection name="supportCaseManagementToolbar" include="/plugins/support-perspective/toolbars/supportCaseManagementToolbar.xhtml" requiredView="supportCaseManagementPanel" />
and the markup
<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<ice:panelGrid columns="1">
<ice:commandLink title="Update"
action="#{supportCaseManagementPanel.update}" partialSubmit="true">
<ice:graphicImage value="/plugins/support-perspective/css/images/update.png"
styleClass="toolbar-button" />
</ice:commandLink>
</ice:panelGrid>
</f:view>
to obtain

If you like to open your perspective with a worklist pre-filtered by descriptors, the open view call
has to be passed with filters attributes in the f:param section.
An easy way to find the filter JSON to be passed is to manually apply the filters and refer the filters
attributes in the POST request in your custom xhtml file.
Pass additional key value pair in the viewParams section, for example:
<ice:commandLink action="#{ippPortalApp.openView}" onclick="Event.stop(event);" value="Test Descriptor Filter">
<f:param name="viewId" value="worklistPanel" />
<f:param name="viewParams" value='id=allActivities&name=Of the Universe, Master (motu)&url=services/rest/portal/worklist/allAssigned&
filters={"EmpNumber":{"from":120,"to":125}}' />
</ice:commandLink>
Another option to achieve this is to use Java code as shown below:
<ice:commandLink action="#{activitySearchPanel.filterByDescriptor}" value="Test Descriptor Filter">
</ice:commandLink>
public void filterByDescriptor()
{
Map<String, Object> params = CollectionUtils.newTreeMap();
String name = this.getMessages().getString("allActivities");
String id = "allActivityInstances";
params.put("id", id);
params.put("name", name);
params.put("url", "services/rest/portal/worklist/allActivable");
String filterJSON = "{\"Account\" : {\"textSearch\":\"Test*\"}}";
params.put("filters", filterJSON);
PPUtils.openWorklistViewHTML5("id=" + id, params);
}
Find below example filters for various types of descriptors:
| Type | Filter |
|---|---|
Number |
{"descName": { "from" : <number>,"to":<number>}} |
Date |
{"descName": { "from" : <long>,"to":<long>}} |
Sring/Text |
{"descName": {"textSearch":"<string>"}} |
Boolean |
{"descName": {"equals":"<boolean>"}} |
To componentize internally used Process and Activity tables, you need to:
org.eclipse.stardust.ui.web.api.utils.ProcessTableorg.eclipse.stardust.ui.web.api.utils.ActivityTablehttp://www.eclipse.org/stardust/ui/web/api<portal:processTable ... /> <portal:activityTable ... />
Create a custom bean, e.g. org.test.MyUseCaseBean and define it in
carnot-spring-context.xml:
<bean name="myUseCaseBean" class="org.test.MyUseCaseBean"
scope="portalTab">
</bean>
Define a custom view, e.g. myUseCaseView.xhtml using the tags for Process table and
Activity table:
<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:portal="http://www.eclipse.org/stardust/ui/web/api">
<portal:processTable
bean="#{myUseCaseBean.processTable}"
id="MyProcessList"
title="My Process Table" />
<portal:activityTable
bean="#{myUseCaseBean.activityTable}"
id="MyActivityList"
title="My Activity Table" />
...
Define the custom view in the Perspective Context:
<ippui:view name="myUseCaseView" include="/plugins/<myPlugin>/myusecase/myUseCaseView.xhtml" controller="myUseCaseBean"/>
To test your custom view, define a Launch Panel link to open this view.
<ice:commandLink action="#{ippPortalApp.openView}">
<f:param name="viewId" value="myUseCaseView" />
<ice:outputText value="MY USE CASE" styleClass="action-link" escape="false"/>
</ice:commandLink>
Instead of defining new perspectives, you can modify existing perspectives regarding
e.g. via
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ippui="http://infinity.com/bpm/portal/common/uiDefinition"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://infinity.com/bpm/portal/common/uiDefinition http://infinity.com/bpm/portal/common/uiDefinition.xsd">
<ippui:perspectiveExtension targetPerspective="ippBccPerspective" id="ippPortalFrameworkPerspective" messageBundles="portal-common-messages">
<ippui:toolbarExtension>
<ippui:toolbarSection name="configurationPanelToolbar" include="/plugins/common/views/toolbar/configurationPanelToolbar.xhtml" requiredView="configurationPanel" />
</ippui:toolbarExtension>
<ippui:viewsExtension>
<ippui:view name="configurationTreeView" include="/plugins/common/views/configurationTree.xhtml"/>
<ippui:view name="configurationPanel" include="/plugins/common/views/configurationPanel.xhtml"/>
</ippui:viewsExtension>
</ippui:perspectiveExtension>
</beans>
or via
PortalUiController uiController = PortalUiController.getInstance();
Map<String, IPerspectiveDefinition> perspectives = uiController.getPerspectives();
for (IPerspectiveDefinition pd : perspectives.values())
{
// Get list of Views and Launch Panels
pd.getLaunchPanels());
pd.getViews());
// To check whether a View or a Launch Panel is global, call method - isGlobal() on that instance
}
Note that using multiple values for the attribute targetPerspective,
specified either as a comma-separated list or *, e.g. for a global
perspective extension, is deprecated. In case you provide an extension for multiple
perspectives, the following warning appears:
Multiple values for attribute 'targetPerspective' is now deprecated. But it's used in 'ippViewsCommonPerspective'.
This section describes basic concepts and utilities you may use for your Stardust Portal Add-ons.
You can open simple message dialogs by adding push code to your Backing Bean code, for example:
MessageDialog.addMessage(MessageType.ERROR, "Support Case Creation", "Support Case cannot be created. Customer order has expired and was not renewed.");
Note that this code is sufficient in case you create your custom worklist and like to show the message dialog from there. If you want to open the message dialog from a JSF activity panel, additionally you need to add the following server push:
public void complete()
{
if (executeFormValidation())
{
MessageDialog.addMessage(MessageType.ERROR,
"Support Case Creation",
"Support Case cannot be created. Customer order has expired and was not renewed.");
PortalApplication.getInstance().renderPortalSession();
throw new RuntimeException("Support Case cannot be created. Customer order has expired and was not renewed.");
}
}

Valid values for the dialog type are
MessageType.ERRORMessageType.WARNINGMessageType.INFOSelection will change the displayed icon.
The Stardust Portal Framework provides an implementation of a Generic Table which allows
Excel and CSV export.
To use a Generic Table, define
<pc:genericDataTable bean="#{supportCaseManagementPanel}" id="supportCaseTable" title="#{supportMessages['supportCaseManagementPanel.supportCaseTable.title']}"
table="#{supportCaseManagementPanel.supportCaseTable}" sortSupported="true" selectColumn="Select"
toolbarUrl="/plugins/support/toolbars/supportCaseTableToolbar.xhtml" />
in your JSF markup.
The value of the table should be a property of a Backing Bean which
returns a list of implementations of org.eclipse.stardust.ui.web.common.table.DefaultRowModel,
e.g.
public class SupportCaseTableEntry extends DefaultRowModel {
private SupportCase supportCase;
private boolean selectedRow;
/**
*
*/
public SupportCaseTableEntry() {
}
/**
* @param supportCase
* @param id
* @param name
* @param description
*/
public SupportCaseTableEntry(SupportCase supportCase, boolean selectedRow) {
super();
this.supportCase = supportCase;
this.selectedRow = selectedRow;
}
public SupportCase getSupportCase() {
return supportCase;
}
public String getId() {
return "" + getSupportCase().getOid();
}
public Date getCreationDate() {
return getSupportCase().getCreationDate();
}
public String getSynopsis() {
return getSupportCase().getSynopsis();
}
public String getSynopsisShortcut() {
if (getSupportCase().getSynopsis() != null && getSupportCase().getSynopsis().length() >= 30)
{
return getSupportCase().getSynopsis().substring(0, 30) + " ...";
}
else
{
return getSupportCase().getSynopsis();
}
}
public String getDescription() {
return getSupportCase().getDescription();
}
public String getDescriptionShortcut() {
if (getSupportCase().getDescription() != null && getSupportCase().getDescription().length() >= 30)
{
return getSupportCase().getDescription().substring(0, 30) + " ...";
}
else
{
return getSupportCase().getDescription();
}
}
public String getState() {
return "supportCase.state." + getSupportCase().getState();
}
public String getType() {
return "supportCase.type." + getSupportCase().getType();
}
public String getProductComponent() {
return "supportCase.productComponent." + getSupportCase().getComponent();
}
public String getCustomerName() {
return getSupportCase().getCustomerName();
}
public boolean isSelectedRow() {
return selectedRow;
}
public void setSelectedRow(boolean selectedRow) {
this.selectedRow = selectedRow;
}
}
This table object can be initialized via
List<ColumnPreference> fixedColumns = new ArrayList<ColumnPreference>();
ColumnPreference selectColumn = new ColumnPreference("Select",
"selectedRow", ColumnDataType.BOOLEAN, "Select", true, false);
selectColumn.setColumnRenderType(ColumnRenderType.READ_WRITE);
selectColumn.setColumnAlignment(ColumnAlignment.CENTER);
fixedColumns.add(selectColumn);
ColumnPreference idColumn = new ColumnPreference(
"Id",
"id",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.id.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml",
new TableDataFilterPopup(new TableDataFilterSearch()), true,
true);
ColumnPreference creationDateColumn = new ColumnPreference(
"CreationDate",
"creationDate",
ColumnDataType.DATE,
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.creationDate.header"),
new TableDataFilterPopup(new TableDataFilterBetween(
DataType.DATE)), true, true);
ColumnPreference nameColumn = new ColumnPreference(
"Synopsis",
"synopsis",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.synopsis.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml",
new TableDataFilterPopup(new TableDataFilterSearch()), true,
true);
ColumnPreference customerColumn = new ColumnPreference(
"Customer",
"customerName",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.customer.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml",
new TableDataFilterPopup(new TableDataFilterSearch()), true,
true);
ColumnPreference descrCol = new ColumnPreference(
"Description",
"description",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.description.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml",
new TableDataFilterPopup(new TableDataFilterSearch()), true,
true);
ColumnPreference typeColumn = new ColumnPreference(
"Type",
"type",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.type.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml", true,
true);
ColumnPreference stateColumn = new ColumnPreference(
"State",
"state",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.state.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml", true,
true);
ColumnPreference componentColumn = new ColumnPreference(
"ProductComponent",
"productComponent",
getSupportMessages()
.getString(
"supportCaseManagementPanel.supportCaseTable.productComponent.header"),
"/plugins/support/views/supportCaseTableColumns.xhtml", true,
true);
List<ColumnPreference> columns = new ArrayList<ColumnPreference>();
columns.add(idColumn);
columns.add(creationDateColumn);
columns.add(nameColumn);
columns.add(customerColumn);
columns.add(descrCol);
columns.add(stateColumn);
columns.add(typeColumn);
columns.add(componentColumn);
IColumnModel columnModel = new DefaultColumnModel(columns,
fixedColumns, null, "admin", "realm");
TableColumnSelectorPopup columnSelecPopup = new TableColumnSelectorPopup(
columnModel);
supportCaseTable = new SortableTable<SupportCaseTableEntry>(null,
columnSelecPopup, null,
new SortableTableComparator<SupportCaseTableEntry>("synopsis",true));
To set the content of the table you may invoke
List<SupportCaseTableEntry> supportCaseTableEntries = new ArrayList<SupportCaseTableEntry>();
List<SupportCase> supportCases = getSupportService()
.findAllSupportCases();
for (Iterator<SupportCase> iterator = supportCases.iterator(); iterator
.hasNext();) {
supportCaseTableEntries.add(new SupportCaseTableEntry(iterator
.next(), false));
}
supportCaseTable.setList(supportCaseTableEntries);
supportCaseTable.initialize();
/plugins/admin-portal/views/supportCaseTableToolbar.xhtml allows you
to add table-specific toolbar entries into the toolbar above the table, e.g
f:view xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ice="http://www.icesoft.com/icefaces/component" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"> <ice:panelGrid columns="1"> <ice:commandLink title="Update" action="#{supportCaseManagementPanel.update}" partialSubmit="true"> <ice:graphicImage value="/plugins/support/css/images/update.png" styleClass="toolbar-button" /> </ice:commandLink> </ice:panelGrid> </f:view>
This way, you can e.g. add buttons to add items to the table.
The layout of every table column can be specified in a separate JSF file, e.g.
f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:pc="http://www.sungard.de/carnot/web/portal-plugin/portalcommon">
<ice:panelGroup>
<ice:panelGroup rendered="#{col.columnName == 'Synopsis'}"
panelTooltip="synopsisToolTip">
<ice:outputText value="#{row.synopsisShortcut}" />
</ice:panelGroup>
<ice:panelGroup rendered="#{col.columnName == 'Description'}"
panelTooltip="descriptionToolTip">
<ice:outputText value="#{row.descriptionShortcut}" />
</ice:panelGroup>
<ice:panelGroup rendered="#{col.columnName == 'Id'}">
<ice:commandLink title="Open Details"
action="#{supportCasePanel.open}" partialSubmit="true">
<ice:panelGroup menuPopup="menuSupportCase">
<ice:outputText value="#{row.supportCase.oid}" />
</ice:panelGroup>
<f:param name="supportCaseOid" value="#{row.supportCase.oid}" />
</ice:commandLink>
</ice:panelGroup>
<ice:menuPopup id="menuSupportCase"
style="z-index:999; background-color: white;">
<ice:menuItem value="Reopen"
action="#{supportSession.reopenSupportCase}">
<f:param name="supportCaseOid" value="#{row.supportCase.oid}" />
</ice:menuItem>
</ice:menuPopup>
<ice:panelGroup rendered="#{col.columnName == 'Customer'}">
<ice:outputLink title="Open Customer Details"
value="http://www.salesforce.com/#{row.supportCase.customerId}">
<ice:outputText value="#{row.supportCase.customerName}" />
</ice:outputLink>
</ice:panelGroup>
<ice:panelTooltip id="synopsisToolTip"
style="width: 200px; text-align: left;" styleClass="notesTooltip">
<f:facet name="header">
</f:facet>
<f:facet name="body">
<ice:panelGroup styleClass="notesTooltipContent">
<ice:outputText value="#{row.synopsis}" />
</ice:panelGroup>
</f:facet>
</ice:panelTooltip>
<ice:panelTooltip id="descriptionToolTip"
style="width: 200px; text-align: left;" styleClass="notesTooltip">
<f:facet name="header">
</f:facet>
<f:facet name="body">
<ice:panelGroup styleClass="notesTooltipContent">
<ice:outputText value="#{row.description}" />
</ice:panelGroup>
</f:facet>
</ice:panelTooltip>
<ice:panelGroup rendered="#{col.columnName == 'State'}">
<ice:outputText value="#{supportMessages[row.state]}" />
</ice:panelGroup>
<ice:panelGroup rendered="#{col.columnName == 'ProductComponent'}">
<ice:outputText value="#{supportMessages[row.productComponent]}" />
</ice:panelGroup>
<ice:panelGroup rendered="#{col.columnName == 'Type'}">
<ice:outputText value="#{supportMessages[row.type]}" />
</ice:panelGroup>
</f:view>
The following style classes can be used to customize Generic Data Tables:
<styleClass> is the attribute passed to the
<genericDataTable> tag. Default is genericTable.
These style classes have an effect on the following parts of a data table:
A way to add custom styles is using custom skins. The usage of custom skins is described in chapter Creating and Using Custom Skins in the End User Handbook.
The Icefaces panelPopup opened with autoCenter="true"
does not correctly center itself when inside an IFRAME.
It is placed at the center of the content instead of being placed at the center of
the visible area of the IFRAME.
To place the popup at the center of the visible area of the browser, we provide a custom script and perform the following steps:
<ice:panelPopup id="#{bean.beanId}" ...>autoPosition="manual"instead of
autoCenter="true"
"InfinityBpm.Core.positionMessageDialog('" + <idAssignedToThePopup> + "');"The following utility method is provided for this:
org.eclipse.stardust.portal.common.util.PopupUtils#addPopupCenteringScript(String popupId)
It places the popup at the center of the visible area of the browser.
Resource Bundles according to the Java localization mechanism need to be defined in the classpath of the Uitility JAR Project, e.g. under
config/
support-messages.properties
support-messages_de.properties
whereby config is added to the build path. These bundles may contain lables for Pespectives and Tab Headers respectively
perspectives.supportPerspective.label=Support Management views.supportCaseManagementPanel.label=Support Case Management views.supportCaseManagementPanel.description=Allows to manage support Cases
To use these resource bundles for Perspectives and Views, these Resource Bundles
have to be listed in the Spring UI Configuration, e.g. support-perspectiveUI-context.xml,
e.g. via
<ippui:perspective id="supportPerspective" messageBundles="support-perspective-messages">
In case you like to build your custom table independent of any of the tables provided
by Stardust, you must implement the IQuery interface.
The following is an example implementation, creating a copy based on the current instance:
public class MyQuery implements IQuery, Serializable
{
/* (non-Javadoc)
* @see org.eclipse.stardust.ui.web.common.table.IQuery#getClone()
*/
public IQuery getClone()
{
IQuery clone = null;
try
{
byte[] serializedQuery = Serialization.serializeObject(this);
clone = (IQuery) Serialization.deserializeObject(serializedQuery);
}
catch (IOException e)
{
// Log / Handle Error
}
catch (ClassNotFoundException e)
{
// Log / Handle Error
}
return clone;
}
}
You can easily combine functionality of your application in the Portal Framework with Stardust functionality exposed via the Portal Framework.
If you intend to open a specific worklist for your application, e.g. filtered by
The code
import org.eclipse.stardust.common.CollectionUtils;
import org.eclipse.stardust.ui.web.processportal.common.PPUtils;
... public void openSupportOperatorWorklist() { Map<String, Object> params = CollectionUtils.newTreeMap(); PortalApplication.getInstance().openViewById("worklistPanel", "id=" + "bla", params, null, false); PPUtils.selectWorklist(null); }
This way you can restrict or focus workflow participation to specific use cases.
To start processes and retrieve the first activity matching to the entitlements of the logged in user
try
{
long oid = workflowService.startProcess("SupportCaseCreation",
null, true).getOID();
ActivityInstance activityInstance = workflowService.activateNextActivityInstanceForProcessInstance(oid);
Map<String, Object> params = CollectionUtils.newTreeMap();
params.put(ActivityInstance.class.getName(), activityInstance);
params.put("oid", Long.toString(activityInstance.getOID()));
params.put("activityName", activityInstance.getActivity().getName());
PortalApplication.getInstance().openViewById("activityPanel",
"oid=" + activityInstance.getOID(), params, null, true);
}
catch (Exception e)
{
...
}
To open Document Views from Java
Map<String, Object> params = CollectionUtils.newTreeMap();
params.put("documentOID", documentId);
PortalApplication.getInstance().openViewById("documentView", "documentOID=" + documentId, params, null, true);
and from JSF markup
<ice:commandLink action="#{ippPortalApp.openView}">
<f:param name="viewId" value="documentView" />
<f:param name="viewParams" value="documentOID={jcrUuid}2ffa5c75-23a8-4705-902b-ac1479114847"/>
<ice:outputText value="Document A &raquo;" styleClass="action-link" escape="false"/>
</ice:commandLink>
The Java Persistence API, sometimes referred to as JPA, is a Java programming language framework managing relational data in applications using Java Platform, Standard Edition and Java Platform, Enterprise Edition. JPA can be used to easily achieve persistence to Business Objects in a Utility JAR deployment. For more details on JPA consult the corresponding J2EE Tutorial.
Business objects can be defined as simple Java classes with annotations for JPA-based persistence.
@Entity(name = "SPTCAS")
public class SupportCase { public static final String SUBMITTED_STATE = "SUBMITTED_STATE"; public static final String ANALYZED_STATE = "ANALYZED_STATE"; public static final String BUG_TYPE = "BUG_TYPE"; public static final String ENHANCEMENT_REQUEST_TYPE = "ENHANCEMENT_REQUEST_TYPE"; public static final String CHANGE_REQUEST_TYPE = "CHANGE_REQUEST_TYPE"; public static final String ENGINE_COMPONENT = "ENGINE_COMPONENT"; public static final String PORTAL_COMPONENT = "PORTAL_COMPONENT"; public static final String MODELER_COMPONENT = "MODELER_COMPONENT"; @Id @GeneratedValue(strategy = GenerationType.AUTO) long oid; @Column(name = "STAT") private String state; @Column(name = "TYP") private String type; @Column(name = "COMP") private String component; @Column(name = "SYNPS") private String synopsis; @Column(name = "DESCR") private String description; @Column(name = "CUSTNAM") private String customerName; @Column(name = "CUSTID") private String customerId; @Column(name = "CRTDAT") @Temporal(TemporalType.TIMESTAMP) private Date creationDate; public SupportCase() { super(); oid = 0; creationDate = new Date(System.currentTimeMillis()); state = SUBMITTED_STATE; } public SupportCase(String synopsis, String description, String customerName, String customerId) { this(); oid = 0; creationDate = new Date(System.currentTimeMillis()); this.synopsis = synopsis; this.description = description; this.customerName = customerName; this.customerId = customerId; } ...
The deployment unit also requires a persistence.xml file with the
following content
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="SupportJPAConfiguration">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>SupportJtaDs</jta-data-source>
<class>com.bpm.framework.support.SupportCase</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
</persistence>
Access to CRUD and other business operations can be provided with a Spring bean with the interface
public interface SupportService
{
public List<SupportCase> findAllSupportCases();
public SupportCase findSupportCaseByOid(long oid);
public SupportCase createSupportCase(SupportCase supportCase);
}
and the implementation
public class SupportServiceBean extends JpaDaoSupport implements SupportService {
private SupportServiceBean()
{
super();
}
public List<SupportCase> findAllSupportCases()
{
List<SupportCase> supportCases = getJpaTemplate().find(
"SELECT e FROM SPTCAS e");
return supportCases;
}
public SupportCase findSupportCaseByOid(long oid)
{
return getJpaTemplate().find(SupportCase.class, oid);
}
public SupportCase createSupportCase(SupportCase supportCase)
{
getJpaTemplate().persist(supportCase);
return supportCase;
}
}
SupportServiceBean inherits its persistence management capabilities
from JpaDaoSupport. The corresponding mm is injected via a runtime
dependency
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="carnotXaAuditTrailDataSource" />
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.transactionType" value="JTA" />
<entry key="eclipselink.target-server" value="com.bpm.framework.jpa.SpringJtaTxController" />
</map>
</property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform"
value="org.eclipse.persistence.platform.database.DerbyPlatform" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="dataSources">
<map>
<entry key="SupportJtaDs" value-ref="carnotXaAuditTrailDataSource" />
</map>
</property>
</bean>
</property>
</bean>
The transactional behavior is provided with Aspect-oriented Programming via
the following declarations in the support-context.xml Spring configuration.
<tx:advice id="txAdvice" transaction-manager="jtaTxManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="supportServiceOperation"
expression="execution(* com.bpm.framework.support.SupportService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="supportServiceOperation" />
</aop:config>
In some cases you might like to invoke Portal pages without a required login. For example, in case you have a project that implements a custom portal-plugin JAR. You like to have some XHTML (*.iface) pages in the plugin to be viewable without requiring a login. These could, for instance, be utility Web forms that are used for data-entry but do not necessarily need a login.
To by-pass a necessary login, Stardust provides support for publicly
accessible URIs. A filter init parameter to control public URI patterns
publicUriPatterns exists, which can be added to your
web.xml file. The value is a comma-separated list of
patterns having an absolute path.
Each pattern can have at most one wildcard and this must be either at the
first or last position.
The default value is /plugins/<anyId>/public/, which means
any page coming from a /public/ sub-folder of arbitrary plugins.
There is special support for specifying plugin-relative patterns, targeting
any portal plugin. Such patterns should use a prefix of /plugins/<anyId>.
In the following example, two folders have been added to the
ipp-views-common.jar:
with a file openSecret.xhtml.
This xhtml file has the following content:
<f:view>
<html>
<f:view xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:pc="http://www.sungard.de/carnot/web/portal-plugin/portalcommon">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></meta>
<title>Secret</title>
</head>
<body>
This is an Open Secret!
</body>
</html>
</f:view>
</html>
</f:view>
The following URL will be allowed without a login:
http://localhost:8080/DemoProject/plugins/views-common/public/openSecret.iface

Whereby the following URL entry is not allowed and will redirect to the login page:
http://localhost:8080/DemoProject/plugins/views-common/login.iface?returnUrl=/DemoProject/plugins/views-common/private/openSecret.iface
Note that in case you already have an active session, navigation to the private URL does work.
By default, the pattern used to identify public URLs is
/public/*. This is the same as the following in
web.xml, but is optional by default:
<filter>
<filter-name>IppPortalLoginFilter</filter-name>
<filter-class>org.eclipse.stardust.ui.web.viewscommon.filter.LoginFilter</filter-class>
<init-param>
<param-name>publicUriPatterns</param-name>
</init-param>
</filter>
Multiple filters can be specified in a comma-separated list, e.g.:
<param-value>/public/*,/global*</param-value>
You can write a custom login filter for Single sign-on. To write a custom login filter, perform the following steps:
protected void includeCustomJS(FacesContext facesContext)
{
try
{
if (null != facesContext)
{
String jsFile = "/plugins/processportal/integration/iframe/iframe-panel-server-support.js";
if (!asList(JavascriptContext.getIncludedLibs(facesContext)).contains(jsFile))
{
JavascriptContext.includeLib(jsFile, facesContext);
}
}
}
catch (Exception e)
{
// Log Error
}
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
...
...
FacesContext facesContext = org.eclipse.stardust.ui.web.common.util.FacesUtils.getFacesContext(servletContext, request, response);
includeCustomJS(facesContext);
...
...
}Without above JS inclusion, the JSF activities won't work properly.
Custom skins can be provided in the Portal configuration via a specific plugin jar. The plugin contains skin stylessheets and images that define one or more skins. The following rules apply to such a plugin:
/<plugin-id>/public/skins.css files that will be considered while
applying that particular skin./<plugin-id>/public are by default
accessible without required authentication.In case conflicts of skin names occur, they are handled in the following way:
The only css file included at the login page is login.css or
as configured via the property Carnot.Login.Skin.StyleSheet. For details
on skinning the login page, refer to section
Applying a Customizable Branding to the Login Page
of chapter
Creating and Using Custom Skins.
The following shows an example plugin structure to be used for providing
the skins design-grey and design-red:
META-INF/
spring/
plugin-project-context.xml
plugin-projectUi-context.xml
xhtml/
public/
skins/
design-grey/
images/
grey.css
design-red/
images/
banner.jpg
Red.css
login.css
Provide this structure as jar file and embed it in your runtime, e.g. in a RAD environment as described in section Embedding in a Stardust Rapid Application Development (RAD) Project. The defined skins are then available in the Portal and can be selected in the Configuration view:
You can mark a skin as default without requiring to set it via the Configuration Page in the Portal. Perform the following steps to do so:
META-INF<name-of-the-skin>-skin-context.xml<bean id="skinDefaultPreference" class="java.lang.String"> <constructor-arg value="<plugin-id>/public/skins/<name of stylesheet>" /> </bean>
design-gray:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--Bean definitions -->
<bean id="skinDefaultPreference" class="java.lang.String">
<constructor-arg value="<plugin-id>/public/skins/design-gray" />
</bean>
</beans>design-gray skin as default skin.
Note
This is expected to work only if no skin preference is saved using configuration page. If a skin is set using the
configuration page then that takes precedence.