Streamezzo S.A. - All rights reserved
Copyright 2001-2010
Components - Introduction
Abstract - Among their diversity, the available components share some similar concepts. This article describes the different concepts that you will find across components and that you have to know before creating your own ones.
Table of Content
This article assumes you already have working knowledge of RSP.
Introduction
As a component programmer or user, it is important to meet the same general concepts through the different kind of components. Indeed, whatever their behaviors, all of them are aimed to be included, called, customized and handle or provide interactions. And when implementing or using components, it is important that the same function implies the same way to deal with it.
This article describes the concepts shared by all components. We will first introduce the way a component should be designed, included, and how parameters can be passed to it. Then we will describe some specific parameters that can be found in all (or most of) the components: the insert target, the global node management, the callbacks interface and the way to enable and disable it.
View and Content
Components can be divided in two groups: the static ones (like carousels and loading wheels) and the ones that handle dynamic values that come from a content provider (like lists and search results). For this latter group, the design leads to a component developed in two parts:
- the View: this part contains the graphics, the layout and all elements free from dynamic values. The scene including the View part of a component can often be stored in cache for a long time.
- the Content: this part handles the dynamic content. Basically, it should consist of multiple Replace that will update the scene graph elements set by the View (e.g. Text nodes strings...), and never create brand new scene graph nodes. It should be the most lightweight possible, reduced to its strictness expression and should contain only RSP elements that cannot be in the View. For faster browsing, scenes including the Content part of a component are often cached, but for a shortest time.
- Note that both parts of a View-Content component can be included in a single RSP. You will meet that in some samples, but this is probably not a good practice when developing a genuine rich media service.
Include
A component is designed to be inserted into a RSP file using the tag. The unit allows including the result of the processing of another RSP (included) within the current RSP (including). This concept is similar to the JSP one, for instance.
You can call the tag with the name of the targeted RSP as if it was in your source folder.
You will read in the documentation that is only available for server-side scenes. But thanks to their ".jar" packaging, it is entirely possible to include components in client-side scenes processing too.
When using in order to use a component, an important point is to forget the shareLocalID parameter and to let it take its default value "false": this will avoid unexpected behaviors due to potential conflicts between ids (DEF).
Parameters
Including a component is designed to "almost" look like a function call. As components are customizable, we use parameters to configure them. More precisely, the component can be customized by passing request attributes to the included page.
In order to make things easier for the developer, 2 tools are provided to make the inclusion of a component as easy as pie:
- The Parameters API: each component proposes Java constant classes that define all the parameters used by the component. Goodbye typing mistakes and hello content assist!
- The RequestParameterContext object: this object acts as an abstraction layer over the
stzRequestobject and handles request attributes in a straightforward way. All you have to do is:
- Create the context
- Add the parameters
- Set up the context
- Include the component
- Clean the context
- Therefore a typical component call will look like this:
<% RequestParameterContext params = new RequestParameterContext(); params.addParameter(MyComponentParameters.MY_PARAMETER_1,"Value_1"); params.addParameter(MyComponentParameters.MY_PARAMETER_2,"Value_2"); params.setup(stzRequest); %><% params.clean(stzRequest); %>
Insert target
Among all kinds of component parameters you can meet, there is one that you will meet with all components (or at least nearly all). That is the "insert target" parameter.
Basically, a component consists of rich media scene elements that you insert in your code. Well, those elements need a place where to be inserted in. The aim of this parameter is to provide a Transform DEF where the component code will be inserted. This Transform node has to be created by the developer. Like all DEF values provided as parameter, it has to be set with a Global scope.
The constant spelling is: MyComponentParameters.INSERT_TARGET.
Albeit being present in all components, this parameter is optional. Its default value is the empty string (""), so by default it will be inserted at the root of the scene graph.
Here is a sample code using this parameter:
<%
RequestParameterContext params = new RequestParameterContext();
params.addParameter(MyComponentParameters.INSERT_TARGET,"Global:Root");
params.setup(stzRequest);
%>
<%
params.clean(stzRequest);
%>
Global DEF prefix
When including a component, we already said that the shareLocalID parameter has to be let to its default value "false". This specifies that the scope for all Local nodes is not shared between the including RSP and the included component.
But what about Global nodes? By definition, those nodes are shared and we take advantage of that through our parameters mechanism. But the problem is that internally components often need to create their own Global nodes. And that might lead to conflicts if:
- a node with the same DEF has been created by the developer in the including RSP,
- the same component is included more than once.
This is why many components provide the parameter DEF_PREFIX. This string is used by the component to prefix all its Global DEF in order to ensure their uniqueness.
Callbacks
Some components provide interactions: item selection, list browsing, buttons, etc. Such components are implemented so that they allow the developer to set and customize the side-effects of the user's interactions.
This is why we talk about a callback mechanism: the component handles the user interaction, but the developer is in charge of the side-effect of this interaction.
To enable this, the component offers parameters that are used to provide startable nodes DEF values. We call "startable nodes" all nodes that have a startTime attribute: Conditional, Action, AnimateTransform, etc.
At runtime, when the end-user will trigger a given interaction, the startable node will be started and the expected side-effect will have to be defined there.
Here is a dummy sample code that illustrates this mechanism. We suppose that "MyComponent.rsp" handles the user press on keys "FIRE" and "1". Here the developer will have decided that the "FIRE" interaction will change the background color and that key "1" will leave the application.
<%
RequestParameterContext params = new RequestParameterContext();
params.addParameter(MyComponentParameters.CALLBACK_PRESS_FIRE,"Global:OnFire");
params.addParameter(MyComponentParameters.CALLBACK_PRESS_KEY_1,"Global:OnKey1");
params.setup(stzRequest);
%>
<%
params.clean(stzRequest);
%>
Callbacks DEF have to be specified with Global scope.
Those parameters may be passed as string in case of simple interaction, or in arrays in case of dynamic items generation.
Enabling and disabling
This topic is, in a way, the opposite of the previous one. As some components provide interaction, it is sometimes required to disable this interaction (for example: if the focus changes, if a popup is raised, if an option menu is opened...). This is why those components have 2 parameters that allow the developer to set the DEF names of startable nodes that once triggered, will either lock or unlock the component. These are startable nodes, and of course their DEF values have to be specified with Global scope.
The developer has nothing to declare, he can directly use those DEF as if they were 2 existing startable nodes. Obviously, the DEF_PREFIX parameter has no incidence on those values.
<%
RequestParameterContext params = new RequestParameterContext();
params.addParameter(MyComponentParameters.ENABLE_NAVIGATION,"Global:Enable");
params.addParameter(MyComponentParameters.DISABLE_NAVIGATION,"Global:Disable");
params.setup(stzRequest);
%>
<%
params.clean(stzRequest);
%>
At the end of the day
Here we have described some general concepts shared by components. As a developer, those will help you to capitalize your knowledge and to concentrate on the specificities when switching to a new component you never used before. As a component developer, they bring you common foundations to build your own, and they will ease the communication with other developers.