Extending Edit Pages with ObjectPageExtensionPoint
Edit pages can now be extended by an Extension Point. There are several options for extending the page:
- The first tab of an edit page can be replaced
- become the only tab on the page
- be an additional tab
- become the whole page
- provide the syntax highlighter to use on JobDefinition pages.
Configuration for this functionality is done via the deployment descriptor. extends
accepts the ObjectPage
element. The DTD describes the various options that can be used for configuring how the Extension Point should be embedded in the object page.
There are some special cases:
- If there are multiple Extension Points for the same page, it will first use the Extension Point with type whole, and ignore the rest, then it will look at single. After that, it will combine all Extension Points.
- When there is a conflict (for example there are 2 Extension Points that want to replace the first tab) then the one with the highest priority will be used.
- JobDefinition Related Object edit pages (Script, JobChain, etc.) will search for
ExtensionPoint
's that either match theJobDefinitionRelatedObject
type orJobDefinitionType
. This means that to add a tab to allJobDefinition
's, one can set the object type of theObjectPage
element to JobDefinition, even though the edit page is for a Script or Chain object.
Extension Points Extending ObjectPageEdit(single|first|add).
The life-cycle for an ObjectPageExtensionPoint
is as follows:
- The server calls the
ExtensionPoint
with theRequestType
parameter set toExtensionParameters.REQUESTTYPE_INIT
. The purpose of this method is to initialize everything required by the extension point. - Once the tab that contain the
ExtensionPoint
is made visible in the UI for the first time, theExtensionPoint
will be called with theRequestType
parameter set toExtensionParameters.REQUESTTYPE_RETRIEVEPAGE
. TheExtensionPoint
is required to return the HTML page that will be displayed in the browser. - If the user moves away from the tab (either by selecting another tab or pressing save), the JavaScript method
redwood.ep.hideTab(ID)
will be called. The JavaScript must then callredwood.epl.hideDone(invocationid: string)
once it has synced its information with the server. - If the page gets shown again, instead of the URL being reloaded, causing the page to be reloaded, it will call
redwood.ep.showTab(ID)
via JavaScript, so the client code can determine how to update the page. - Once the page needs saving, the server will call the
ExtensionPoint
with theRequestType
parameter set toExtensionParameters.REQUESTTYPE_PERSIST
. TheExtensionPoint
can then verify the data before the persist and abort it if requirements are not met.
The life-cycle can go between showTab()
- hideTab()
many times, depending on how the user selects the tabs.
However, in some cases, like the JobChain
editor, it can also go from hideTab()
to the RetrievePage
call. It is therefore important to make sure to sync the client state tot he server on the hideTab()
call, since the page might get removed the client.
Init call
The init call is made so the ExtensionPoint
can setup the SchedulerEntity
's it needs. The ExtensionParamters contain the information about the SchedulerEntity
that is being edited. Access to modified/created SchedulerEntity
's is via the SharedSchedulerSession
, explained in this document.
The init call does get a jcsResponse
, but everything except for the OutputStream
gets ignored. The OutputStream
can be used to return a JSON array of messages that should be displayed to user. The format of these messages is detailed later in this document. These message can be used to inform the user, since they will be displayed in the edit window.
Even though the jcsRequest
is not a real request coming from the browser, it is fully usable, including the session related methods to store/retrieve data.
RetrievePage call
The retrieve page call is to call to the ExtensionPoint
to render the tab on the edit page. This request is sent from the browser, and its output will directly go to the browser. This is also the call that must provide that page with the two JavaScript methods redwood.ep.showTab(ID)
, and redwood.ep.hideTab(ID)
.
Once the page is setup, either after this request or subsequent requests, the page must call redwood.epl.showDone(invocationid: string)
on window.parent
, to indicate that it is done. This will remove the busy indicator and allows the user to interact with the page.
After the redwood.epl.showDone(invocationid: string)
call, the Extension Point will still be in control of the shared SchedulerSession
, so if the user interacts with the page, and the ExtensionPoint
decides to communicate back to the server (make sure to add the invocationID
to the URL), the shared scheduler session can still be used.
redwood.ep.showTab(invocationid: string)
Like the init call, this is to indicate that the tab is about to be shown, but will be done after RetrievePage
has already been done. This is to allow for faster turn around, since the page can determine on the client if it needs re-rendering or not.
Like the RetrievePage
call, the page must call redwood.epl.showDone(invocationid: string)
to remove the busy indicator.
redwood.ep.hideTab(invocationid: string)
If the user selects a different tab or selects save, this method will called via JavaScript. This gives the page the opportunity to send changes back to the server, since the actual page might disappear as well (depending on where the page is being used).
Once the page has finished, it must call redwood.epl.hideDone(invocationid: string)
on window.parent. After this call, the shared SchedulerSession
on the server is on longer available/valid!
Persist call
Just before the persist to the database is done, the server will call the Extension Point so it can validate/clean up. The shared SchedulerSession
is available and will contain all changes. The jcsResponse
is not a real response object and like the init call, only the OutputStream
will be used to retrieve a JSON list of messages.
To prevent eh persist from happening, the ExtensionPoint
must throw an ExtensionPointValidationException
. This exception has a Message and Additional, that will be shown to the user as to why the persist failed.
After this method returns, either with or without an error, the shared SchedulerSession
will no longer be available.
The shared SchedulerSession
To have access to modified Scheduler Entities, jcsExtensionPointContext.getSharedSchedulerSession()
returns a shared SchedulerSession that contains all modifications. This SchedulerSession
, and the SchedulerEntity
's it returns, do have some restrictions.
The session must only be used when the ExtensionPoint
is in control of it. Once the ExtensionPoint
is no longer in control, the SchedulerSession
and the SchedulerEntity
's are non functional, even if control is given back. If access is needed in later requests, or outside of the control block, copy the uniqueId
and refetch the object from a new/updated SchedulerSession
.
Because of this, do not store these objects in sessions etc.
The SchedulerSession
does not allow reset()/persist().
The SchedulerSession
and SchedulerEntity
's must not be cast to other implementations of SchedulerSession
and SchedulerEntity
, since that will throw a ClassCastExceptions
.
The JSON message list.
The Init call and Persist call allow the ExtensionPoint
to return a JSON list of messages to be shown to the user. This is a normal JSON array with 0 or more elements.
A Message object has 3 fields, message (String), additional (String), and severity (integer). Additional is optional, the other 2 fields must be present.
Severities 1
(success), 2
(warning) and 3
(error) will be displayed accordingly in the UI.
[{"message": "Some Message Text", "additional": "Additional text available when user clicks on message", "severity": 2}, {"message": "Only message", "severity": 1}]
The ExtensionPoint JavaScript API
Redwood Server provides the following methods (available via window.parent):
redwood.epl.showDone(invocationid: string)
- must be called once the page is done with the showing of the page, and is ready to interact with the user. Expected after aRetrievePage
call orredwood.ep.showTab()
callredwood.epl.hideDone(invocationid: string)
- must be called once the page is done with the syncing of the page with the server, and could therefore potentially be removed from the client. Expected after aredwood.ep.hideTab()
callredwood.epl.showMessage(message: Message)
- called to show a message in the UI of the edit page. The JSON message list describes the format of theMessage
object.redwood.epl.setChanged(changed: boolean)
- called when theExtensionPoint
has made changes, so the UI can indicate that the screen has unsaved changes.
Extension points