If you are on wsrp@lists.oasis-open.org list for committee members, send comments there. If you are not on that list, subscribe to wsrp-comment@lists.oasis-open.org list and send comments there. To subscribe, send an email message to wsrp-comment-request@lists.oasis-open.org with the word "subscribe" as the body of the message.
Copyright © 2004 OASIS Open, Inc. All Rights Reserved.
Web Services for Remote Portlets (WSRP) is a web services protocol for aggregating content and interactive web applications from remote sources. Web Services for Remote Portlets 1.0 Primer is a non-normative document intended to help interpret the WSRP 1.0 Specification [1] with usage scenarios and typical interactions that must happen to achieve such aggregation. There are numerous sources of high-level introductory information about WSRP 1.0, including the introductory section of the specification itself, and the WSRP White Paper [2]. If you are reading about WSRP for the first time, we encourage you to explore these resources before proceeding with the extended examples and explanations contained in this primer.
The guiding perspective on which WSRP specification was built should be of primary interest to potential implementers. This perspective is framed by the question of what problems WSRP is intended to solve. The specification's procedural approach addresses the following main areas:
WSRP builds on a few fundamental standards, most notably XML, SOAP and WSDL, while allowing for the implementation of evolving standards, to deliver a protocol rich in abstractions and operations that web service implementers and portlet Consumers require.
The WSRP specification uses the terms Producer and Consumer to describe parties implementing the specification.
The Producer is a web service that offers one or more portlets and implements various WSRP interfaces/operations. Depending on the implementation, a producer may offer just one portlet, or may provide a runtime (or a container) for deploying and managing several portlets.
The Consumer is a web service client that invokes producer-offered WSRP web services and provides an environment for users to interact with portlets offered by one or more such Producers.
You can use WSRP to implement a very broad range of portlet Producers and Consumers. However, in this primer, for the sake of simplicity, we use simpler examples. It is not our intention to address the entire range of problems that WSRP can solve, or to replace the material already in the specification. Therefore, when you uncover your own questions, and discover that any particular question is not discussed here, we suggest that you have a copy of the specification available for quick reference.
In this Primer, we use interactions between two parties, viz., P Inc (a WSRP Producer), and C Inc (a WSRP Consumer) to discuss various WSRP interfaces.
In the examples we will use, P Inc is a financial services company, providing services online to their customers and partners. C Inc is on online portal company, providing personalized collaboration, banking, and financial services. C Inc offers these services to end-users by subscription.
P Inc would like to host a number of applications including a web based portfolio management application. C Inc would like to offer this application to its end users via its portal pages.
In order to offer this portfolio management application to end users, C Inc and P Inc agree on the following:
This scenario captures some of the essentials of the WSRP 1.0 Specification. Instead of developing a proprietary application protocol to accomplish the above steps, P Inc and C Inc can agree to use WSRP as the protocol. In this scenario, P Inc is a WSRP Producer offering portlets, and C Inc is a WSRP Consumer consuming portlets and aggregating portlets for users to access aggregated portlet pages. The portfolio management application is a Portlet offered by the Producer.
Note: This version of the Primer will not address how C Inc may discover the web service end-point offered by P Inc.
To implement this scenario, P Inc and C Inc can use WSRP to define various interactions, with P Inc implementing the following required WSRP interfaces and operations:
getServiceDescription
operation of this interface
to obtain this metadata in step (a) of the above scenario. getMarkup
operation of this interface to obtain
the portlet's markup in steps (c) and (i), and invokes the performBlockingInteraction
operation to
propagate user's interactions to P Inc in step (g). By implementing these interfaces, and agreeing to conform to WSRP, both P Inc and C Inc can use a standard mechanism to offer and consume portlets. In addition, P Inc can offer the same portlet to X Inc as long as X Inc adheres to WSRP, and C Inc can consume portlets offered by Y Inc provided Y Inc also implements WSRP interfaces.
The Service Description and Markup interfaces are the two required interfaces that any WSRP Producer must implement. In addition, WSRP specifies the following optional interfaces:
In the following sections, we will discuss these interfaces in detail by considering each aspect of the above scenario. To keep the discussions focused on the purpose and usage of these interfaces, we postpone any discussion on faults to Section 8.1. Refer to the WSRP specification for the list of faults that various operations in each of the interfaces may return. Also, note that the data structures used in the messages through out this Primer do not necessarily include all optional elements.
You can find the normative WSDL of all WSRP interfaces in [3], and the data types in [4]. We encourage you to refer to these documents for more complete descriptions of various messages presented in this Primer.
If you have questions about implementing WSRP, post your questions to the wsrp-dev@lists.oasis-open.org mailing list.
During the development of WSRP, the WSRP technical committee experimented with various well-known web services stacks such as .NET, JAX-RPC reference implementation, Apache Axis etc. For a discussion of stack related issues considered during the development of WSRL WSDL and data types, refer to [5].
To verify that your implementation conforms to the WSRP Specification, you can use the conformance test kit [6]. You can also review the conformance requirements at [7].
Throughout this Primer, we use illustrative scenarios, sample SOAP message fragments, and highlight implementation choices that Producers and Consumers could make. We use the following formatting conventions to aide readability:
fixed-width
font to indicate XML elements and
attributes used in running text. In order to set up a Consumer to aggregate portlets offered by a Producer, the Consumer must first obtain a description of the Producer, and the list of portlets that the Producer offers. Based this information, the Consumer will be able determine if it can successfully aggregate those portlets, and setup its environment (for example, a page aggregating portlets) for such aggregation.
The getServiceDescription
operation of the service description interface provides the Producer’s
metadata including the list of offered portlets and their properties.
All portlet Producers are required to implement this operation. Usually, the first request a Consumer ever sends to
a Producer is the getServiceDescription
request. This operation returns the following:
Consider the following scenario.
Scenario 1: Discover Portlets
In order to get P Inc's service description, C Inc must first send a getServiceDescription
request to P
Inc. Here is the most basic form of a getServiceDescription
request that a consumer could send to a
producer.
Message 1: Service Description Request
To this request, P Inc responds with a getServiceDescriptionResponse
document that includes the
following:
en
and en-US
locales. This does not necessarily mean
that portlets offered by this Producer are limited to generating markup in these locales, but simply that the
Producer's metadata is available in these locales. portletHandle
"portfolioManager". The portletHandle
is an opaque reference assigned by the Producer, and both the
Consumer and the Producer use this handle to refer to this portlet in all interactions text/html
. As with
locales, this portlet is not limited to generating markup in this MIME type. wsrp:view
mode, and wsrp:normal
,
wsrp:minimized
, and wsrp:maximized
window states. Here is the response message from P Inc. containing the above data:
Message 2: Service Description Response
C Inc can now use this response to setup a page to aggregate this portlet, and offer that page to its users.
The portlets described in the getServiceDescriptionResponse
are &qout;producer-offered" portlets. In
Section 5.2.3 and 6.2.4, we will see how
Consumers can cause cloning of these portlets to create consumer-configured portlets. This distinction is important
because all Consumers are allowed to access/use producer-offered portlets and therefore no Consumer is allowed to
customize them.
Producers’ capabilities as well as the metadata of portlets offered by a Producer may change over time. When such changes happen, it is very likely that Consumers/portlets may not function correctly. To prevent such failures, and since WSRP does not provide a mechanism for Producers to notify Consumers of such changes automatically, we recommend that Producers keep such metadata unchanged, or notify Consumers of changes. In general, the guiding principle is that Producers must treat service descriptions and portlet descriptions as a published contract with all the Consumers.
Secondly, a Producer offering a fixed set of portlets with the same behavior to all Consumers without requiring any knowledge of the Consumer may follow the style of service description response described in this section. However, in most cases, Producers and Consumers may find it necessary to customize their behavior based on certain properties of the other party. For example, P Inc may want to offer the portfolio manager portlet only to those Consumers that enter into a service contract. Another Producer may want to customize its responses depending on the capabilities of the Consumer. As discussed in Section 4, Consumers and Producers may use the notion of registration to deal with such scenarios.
The purpose of the registration interface is to provide a means within the WSRP protocol for a Consumer to register with a Producer. Registration allows the Producer to associate portlets and any portlet customization data with the Consumer that is interacting with it. The Producer can also use the registration context to scope the artifacts offered/created during interactions to Consumers that caused those interactions. Note that the purpose of registration is not to uniquely identify a Consumer, but to establish a scope for a Consumer’s use of a Producer.
The WSRP specification does not specify/restrict any possible application of registration. Here are some possible applications:
Depending on the nature of services offered by the Producer and the nature of the business, the registration process may be as simple as sending a registration request to a Producer using the Registration interface, or may be as complex as fulfilling legal, billing and other contractual obligations to establish registration. Keeping this in mind, the WSRP 1.0 specification considers two forms of registration:
By following one of these forms of registration, the Consumer obtains a registrationContext
from the
Producer. The registrationContext
includes a registrationHandle
, and optionally some
registrationState
. Of these, the registrationHandle
is a unique handle assigned by the Producer
to the Consumer and remains unchanged during the lifetime of a Consumer’s registration with a Producer. The optional
registrationState
contains any persistent state for the registration which the Producer requires the
Consumer to store and resupply on future invocations.
The registration interface specifies the following operations:
register
: This operation lets a Consumer register with a Producer. The Consumer may have to supply
certain producer-specified registration properties for registration. Upon registration, the Producer assigns a
unique registrationContext
for the Consumer. The Consumer must then supply this
registrationContext
with each request it makes to the Producer. modifyRegistration
: This operation lets a Consumer modify an existing registration. If required,
the Consumer may supply registration properties with this request. The Producer may not assign a new
registrationHandle
to the Consumer, but may return new registrationState
. deregister
: This operation lets a Consumer terminate a registration.
A Producer indicates that registration is required and that certain data is required for registration via its
response to a getServiceDescription
request.
Let us now consider the following variation to Scenario 1 to see some of the details of registration.
Scenario 2: Registration
Since P Inc now requires registration, P Inc sends the following response to the previous simple
getServiceDescription
request from C Inc.
Message 3: Service Description Response from Producer Requiring Registration
The first point to note from this response is that P Inc now requires registration, and that it requires Consumers to supply two registration properties for registration.
stringValue
in the
urn:oasis:names:tc:wsrp:v1:types
namespace. Producers can use either the stringValue
type or
any arbitrary schema type (other than those defined in the urn:oasis:names:tc:wsrp:v1:types
namespace) to describe a registration property.
Other than these requirements, this service description response does not provide much information about P Inc. Specifically P Inc chose to omit portlet metadata in its response.
C Inc then sends the following request to P Inc supplying the DUNS number and service ID that P Inc. assigned.
Message 4: Registration Request
In addition to the registration properties, the Consumer sends some additional metadata of itself:
However, as any web developer would be familiar with, HTML forms using GET as the method type cannot include
query parameters in action URLs. To support such forms, Consumers will have to use hidden parameters or cookies,
or some other technique to embed implementation-specific data. If a given Consumer is not capable of supporting
such forms, it can indicate so to the Producer by supplying false for the methodGetSupported
element. The Producer can then avoid offering portlets that generate forms with method GET to the Consumer.
Refer to the WSRP specification for a list of other optional data that the Consumer can supply during registration.
The Producer P Inc validates this request for registration, creates a registration context, and returns the following response:
Message 5: Registration Response
In this response, the registrationContext
represents a registration relationship between the P Inc
and C Inc, and contains a registrationHandle
assigned to C Inc by P Inc. Once a Consumer obtains a
registrationContext
, the Consumer must supply the registrationContext
with all
subsequent requests to the Producer. For this reason, the Consumer must persistently maintain the
registrationContext
for all future invocations.
registrationHandle
and returns this handle via a RegistrationContext
.
If the Producer is not capable of managing persistent storage of registration data, the Producer can choose to
return all such data to be persisted as registrationState
to the Consumer. The Consumer would then
be responsible for storing the registrationState
along with the registrationHandle
and
return these to the Producer in future invocations.
Having completed the registration process, C Inc can now send another service description request to P Inc, this
time supplying the registrationContext
.
Message 6: Service Description Request after Registration
The registrationContext
in this request helps P Inc to tailor its response. Upon validating the
registrationContext
, P Inc sends a response that includes portlets it offers.
Message 7: Service Description Response after Registration
Note that this message is similar to the response shown in Message 2, but has only been received after C Inc fulfilled P Inc’s registration requirements.
Once a Consumer establishes a registration relationship with a Producer, in some conditions, Consumers may have to modify an existing registration relationship either to be able to continue to use a Producer or alter certain properties of the registration. Here are some possible situations that may warrant such an operation:
Consider the following scenario.
Scenario 3: Modify Registration
To implement this scenario, P Inc has the following options:
OperationFailed
faults until C Inc. supplies the new property (email address).
In the former case, C Inc will have to send getServiceDescription
request (without the
registrationContext
) to discover the current set of registration properties. Upon discovering the new
registration property, C Inc sends the following modifyRegistration
request to P Inc.
Message 8: Request to Modify Registration with an Additional Registration Property
This request is similar to the registration request in Message 4 except for a new value for a registration property.
P Inc validates the new values for registration properties, modifies registration, and responds with the following message:
Message 9: Modify Registration Response
The response simply indicates that P Inc. has accepted the request for modification of registration.
registrationState
in the modifyRegistrationResponse
.
After modifying the registration relationship, C Inc can continue to use the registrationHandle
.
Registration relationships are not permanent. Either the Consumer or the Producer may terminate a registration relationship. Here are some scenarios that could prompt for a termination:
In cases (a) and (c) above, the Consumer can send a deregister
request to the Producer to terminate
the current registration relationship. Note that, Consumer is not required to deregister
always.
However, by formally deregistering, Consumer lets the Producer cleanup any persistent data maintained for that
registration.
Consider that C Inc now wants to terminate its registration with P Inc. In order to do so, C Inc sends a
deregister
request with its registrationHandle
to P Inc as shown below.
Message 10: Deregister Request
P Inc then deregisters C Inc and cleans up any resources/state created (including any cloned portlets) for C Inc, and returns the following response.
Message 11: Deregister Response
After this step, C Inc can no longer use the registrationHandle
“CIncRegnHandle” for its requests
to P Inc.
Terminating a registration has some consequences for both the Producer and the Consumer:
Figure 2 shows possible interactions between C Inc and P Inc and the registration life cycle.
Once you establish a registration between a Producer and a Consumer, the registration becomes long lasting. This is because the registration relationship is tied to any persistent data stored on both the Producer and Consumer. Deregistering a Consumer from a Producer will invalidate such persistent data, and your users will not be able to use their portlet settings.
Due to the reasons discussed in Section 4.2.2, if a Consumer modifies an existing registration, we recommend that the Consumer obtain the service description from the Producer again. This is because Producers may use registration data to tailor service description to each Consumer.
Note that registration does not address the question of Consumer identity in the security sense. You may need other means of trust to address the question of Consumer identity.
In order for a Consumer to generate a page that aggregates portlets offered by one or more Producers, the Consumer must first obtain the markup of each portlet from each Producer. As users interact with the portlet (e.g. by submitting a form from the portlet’s markup), the Consumer must be able to send such interaction requests to the Producer, and then receive markup reflecting the user interaction. The Markup interface specifies operations for achieving these tasks. All Producers are required to support this interface.
The markup interface includes the following operations:
getMarkup
: The purpose of this operation is let the Consumer collect markup fragment for for a
given portlet. performBlockingInteraction
: Consumers use this operation to dispatch each user interaction to
the Producer hosting the portlet that sourced the markup the user is interacting with. initCookie
: The purpose of this operation is to let the Producer initialize any cookies, and
set those cookies to the Consumer. As we shall discuss shortly, using this operation Producers may return
cookies to Consumers for load-balancing or other implementation specific purposes. releaseSessions
: As we shall see shortly, during a getMarkup
or a
performBlockingInteraction
, portlets can initialize sessions. When a portlet creates a session, the
Producer returns a sessionID
for the session to the Consumer in its response to the getMarkup
or performBlockingInteraction
response. Consumers can use the releaseSessions
operation to let the Producer release those sessions. Collecting markup and aggregating it into a page poses several challenges such as creating correct links in the markup, managing transient state, propagating user interactions etc. In this section, before reviewing the operations in this interface, let us discuss some of the most important issues that the markup interface addresses.
One of the primary goals of WSRP 1.0 was to allow the aggregation of multiple content units, portlets, from different sources on the same web page. HTML 4.01 and XHTML 1.1 treat pages as separate documents and disallow multiple BODY Elements, represented as <body> tags, in a single document. Therefore, the Consumer cannot aggregate individual documents with individual BODY elements from individual portlets into a single page. Portlets are therefore required to generate markup fragments.
The Consumer is most likely to aggregate the portlet’s markup fragment (such as HTML or XHTML) into a page that also includes markup from other portlets. For rules on what differentiates full markup from markup fragments, refer to Section 10.5 of the WSRP 1.0 specification. Along with the markup fragment, the Producer also returns certain properties of the markup fragment, such as the content type, character encoding, locale etc.
With WSRP, the Consumer aggregates markup from different portlets hosted on Producers, and users interact with those portlets via the Consumer. The Consumer is therefore responsible for presenting portlets’ markup as well as receiving user interactions from portlets. Moreover, a user’s interaction with one portlet may affect the markup for another portlet due to any shared state between portlets.
When a user interacts with a web page, you can process the input and generate new markup (e.g., by forwarding to a new page) in a single step. However, such a single step process is not adequate for processing interactions with a page aggregating multiple portlets. During such an interaction, it is most likely that only one portlet processes the request, while all the portlets (including the one that processed the request) on the page regenerate their markup taking into account any state shared between those portlets. In an aggregated page, each portlet should be able to generate markup without any user interaction. This will allow the user to interact with one portlet, and yet see markup of all portlets on the aggregated page.
When a user interacts with a portlet’s markup (e.g. by submitting a form), the Consumer forwards the interaction to the Producer identifying the portlet that generated the markup. This allows the portlet to process the user interaction (e.g. by performing queries/updates in some backend system, or updating some persistent state). During this process, the portlet processing the interaction can also update some shared state that other portlets rely on. Once this process is complete, the Consumer can get markup for each portlet from each Producer, and regenerate the aggregated page. In order to approach this sequence, WSRP specifies a two-step protocol.
The first step of the protocol is to process user interactions, as specified by the
performBlockingInteraction
operation of the WSRP protocol. The purpose of this operation is to let a
portlet process the user interaction, update any transient and persistent state, and possibly return the new
state to the Consumer.
The second step of the protocol is to get markup from the Producer, as specified by the getMarkup
operation of the WSRP protocol. This operation returns the portlet’s markup (a fragment), and properties of the
markup (such as a preferred title, character encoding, locale and content type of the markup).
The Consumer can get markup for each portlet from each Producer even in the absence of a user interaction. This can happen, e.g. when a user visits the aggregated page for the first time, or when the user refreshes the page. The two-step protocol allows for such interaction-free rendering and using this protocol, Producers can generate markup for portlets with their current state even in the absence of any interaction for any given portlet.
As the name implies, the performBlockingInteraction
operation is a blocking operation. That is, the
Consumer waits for this operation to complete before sending getMarkup
requests. Due to the
blocking nature of this operation, Producers can allow changes made to a portlet’s state during a blocking
interaction visible to other portlets during their markup generation. For example, the portlet processing the
blocking interaction can store some data in a relational database, and other portlets can read that data during
markup generation.
During various getMarkup
and performBlockingInteraction
requests, Producers and/or
portlets can return state to Consumers. Consumers are required to supply such state in future interactions for
the portlet to the Producer. The markup interface accounts for the following kinds of state:
performBlockingInteraction
requests. Portlets can also embed navigational state in each URL in the
markup. In either case, Consumer returns this navigational state to the Producer with subsequent
getMarkup
requests. Navigational state typically encapsulates data required by Producers to generate
markup for a given portlet several times without having to keep track of the interaction that caused the
current state of the portlet. sessionID
for the session, and returns it to the Consumer.
Consumers return this sessionID
in future requests to that portlet. This mechanism is similar to
HTTP state management as specified in RFC 2965 [8]. The difference between navigational state and session state is that navigational state allows the Producer to free itself from holding transient state locally and makes that state of the portlet bookmarkable by the user.
With WSRP, the Consumer is the intermediary between the Producer and the end user. Here are some advantages of the Consumer being the intermediary:
URLs in the markup presented to the end user should therefore refer to the Consumer and not to the Producer. Either the Producer or the Consumer must take the responsibility of creating or converting URLs in the markup to refer to the Consumer. The markup interface accounts for such URL generation.
WSRP specifies two kinds of URL generation, viz. Consumer URL rewriting and Producer URL writing. Of these, the former approach requires the Consumer to rewrite URLs in the markup to refer to the Consumer. On the other hand, the latter approach lets the Producer generate URLs using Consumer supplied URL templates. We shall discuss these techniques briefly in Section 5.2.1.
Although the performBlockingInteraction
operation is the first step in the two-step protocol, let
us first discuss the getMarkup
operation as it lets us probe the issues in a more natural order.
The purpose of the getMarkup
operation is to obtain a portlet’s markup. In order to discuss the
semantics of this operation, consider the following scenario.
Scenario 4: Get Initial Markup
In addition to the information about the Consumer and the portlet, the Producer needs some more data about the
user (for personalizing the markup), user’s device (e.g. browser), type of connection (e.g. secure or normal),
and what kind of markup is acceptable to the Consumer and to the end user. The getMarkup
request
encapsulates all such information.
For the current scenario, C Inc. sends a getMarkup
request the producer, P Inc. with the
following data:
RegistrationContext
: This element carries the registrationHandle
assigned by P
Inc during registration. PortletContext
: This element includes the portletHandle
, which the Consumer uses
to identify the portlet to the Producer. RuntimeContext
: This element includes the authentication mechanism (represented by
userAuthetication) C Inc used to authenticate the user along with optional elements such as the
sessionID
, URL templates, etc. UserContext
: This element carries a userContextKey
the Consumer assigns to the
user. In the current scenario, C Inc sends a nil
UserContext
as C Inc has not
assigned any userContextKey
to the user. MarkupParams
: This element carries information about the request from the user to C Inc, such
as whether the user used a secure communication channel (represented as boolean value for
secureClientCommunication
), an array for accepted locales for the markup (represented as locale
elements), an array of accepted MIME types (represented as mimeTypes
elements), the mode and
window state for the portlet markup, accepted character sets for the markup (represented with
markupCharacterSets
elements). Here is the request from C Inc to P Inc.
Message 12: Get Markup Request
Note the following from this request:
RegistrationContext
: The registrationHandle
is CIncRegnHandle assigned by P Inc
during registration. PortletContext
: The portletHandle
is portfolioManager. RuntimeContext
: The userAuthentication
is wsrp:password
. This value
indicates the user supplied a username and password to authenticate with C Inc. UserContext
: The userContext is nil
. When supplied, the UserContext
includes a userContextKey
. This key is an arbitrary reference assigned by C Inc for the user.
Producers typically use this key for personalizing the portlets markup and behavior. In addition to this key,
C Inc can also include a profile of the user (such as the name, gender, home/work information etc) and an
array of userCategories with the UserContext
. The purpose of these items is to allow the Producer
to personalize the behavior and/or markup of the portlet. Refer to Section 6.17 and 6.10 of the WSRP 1.0
Specification for more details. MarkupParams
: The Boolean for secureClientCommunication
is false indicating that
the user did not user a secure connection (such as SSL) to C Inc. This element also specifies that the
accepted locale is en, the accepted MIME type for markup is “text/html”, the accepted character set for the
markup is UTF-8, the mode is wsrp:view
, the windowState is wsrp:normal
(modes and
window states to be discussed later in this section). This element also includes the clientData
element with a value for userAgent
identifying the browser and operating system of the user.
This is a basic form of a getMarkup
request that a Consumer could send to a Producer. To this
request, P Inc responds with a getMarkupResponse
that includes:
MarkupContext
, which contains the markup for the portlet, a title, locale and MIME type of
the markup. SessionContext
(optional) with a sessionID
, and an expiry time interval (in
seconds) for the sessionID
. The Producer returns the SessionContext
element when it
establishes new session. The Consumer should supply this sessionID
on future invocations in order
to not lose state the Producer is storing for the user’s interactions. If a Consumer does not invoke this
portlet before this interval, the Producer may terminate the session associated with the sessionID
.
Here is the response from P Inc.
Message 13: Get Markup Response
Note in our example:
markupContext
with a markup fragment, a preferred title “Portfolio Manager”,
locale “en-US” and MIME type “text/html; charset=UTF-8”. C Inc can use the preferred title to render a title
bar with the portlet’s markup. getMarkup
and performBlockingInteraction
requests for this portlet.
In this response, P Inc returned the markup as a markupString
. This is an XML-escaped string with
XML entities such as <
individually escaped as <
or escaped in bulk by the use of
a CDATA block as per this example.
Producers can also return the markup as Base64-encoded binary data via a markupBinary
element in
the markupContext
.
wsrp_rewrite
token and suffixed
with a /wsrp_rewrite
token. The URL itself between these tokens is not a complete URL. When C Inc
encounters these tokens, C Inc rewrites the URL to a string that refers to C Inc. The tokens contained between
these markers are instructions on what the Consumer is to do to invoke the Producer when an end-user activates
the resulting URL. wsrp-urlType
: This is the first parameter in the URL and indicates the type of
the URL. WSRP specifies three kinds of URL types – blockingAction
, render
, and
resource
. When the value of this parameter is blockingAction
, C Inc converts the URL into
a URL that when activated, causes a user interaction (i.e., a performBlockingInteraction
request). When the URL type is render
, C Inc simply needs the URL to request that it invoke
getMarkup
without an additional performBlockingInteraction
invocation. The URL type
resource
is used for generating links to resources such as images, files etc. Refer to Section 10.2.1
of the WSRP 1.0 Specification for more details. wsrp_rewrite_
token. This
is an indication to C Inc that it must rewrite the value stockForm
such that it is unique within
the generated page. Since the portlet is not aware whether names such as this are unique within an aggregated
page, portlets use this token to let the Consumer generate a unique name. In this example, the Consumer rewrote the action URL to refer to a finance page containing the portfolio manager portlet. The actual values of the URL and names in the above markup depend on the Consumer’s implementation. Another Consumer interacting with P Inc may rewrite the URLs and names differently.
The WSRP specification specifies an alternative form of URL generation called as “producer-writing”. Producer writing involves URL templates and a namespace prefix that the Consumer sends to the Producer. Instead of using tokens, Producer uses the templates and the namespace prefix to create URLs and names in the markup. For more details of this approach, refer to Section 10.2.2 of the WSRP 1.0 Specification.
Consumers can use the performBlockingInteraction operation to send user interactions to the Producer. During this operation, portlets can process user interactions while letting the Producer affect their state. Note that the scope of the getMarkup operation is limited to generating markup for a portlet without affecting the current state of the portlet.
When a user interacts with a portlet (e.g. by submitting a form), the Consumer uses the performBlockingInteraction to send the submitted data to the Producer. During the course of this operation, any/all of the following may happen.
performBlockingInteraction
operation to send user interactions to the
Producer. During this operation, portlets can process user interactions while letting the Producer affect
their state. Note that the scope of the getMarkup
operation is limited to generating markup for a
portlet without affecting the current state of the portlet.
performBlockingInteraction
to send the submitted data to the Producer. During the course of this
operation, any/all of the following may happen. performBlockingInteraction
request.
Let us extend Scenario 4 to let the user cause an interaction affecting the portlet’s state.
Scenario 5: Blocking Interaction
After the user submits the form, C Inc sends a performBlockingInteraction
request to P Inc so
that the portfolio manager portlet can process the user interaction. The performBlockingInteraction
request contains all the data elements contained in the earlier getMarkup
request, plus an
additional InteractionParams
element. This element includes the form data submitted by the
user.
In this example, this portlet is capable of processing only one user interaction. However, if this portlet
is capable of processing more interactions, it may add an interactionState
parameter to the
action URL. This parameter can describe the kind of user interaction associated with the request. For
example, if this portlet can also delete a stock symbol from the list of symbols, it could add an
interactionState
parameter such as “deleteSymbol”. The actual value of the state is opaque and is
implementation specific.
Producers or portlets can embed arbitrary state within URLs as interaction state. When a user activates a
URL with interaction state, Consumers extract the interaction state from the HTTP request, and include it in
the performBlockingInteraction
request to process the interaction. Interaction state is similar
to form parameters except for the difference that Producers or portlets pre-populate interaction state in
URLs.
The following message shows a performBlockingInteraction
request message as it would be
generated if the form from our preceding getMarkup
is submitted by the user to the Consumer
requesting the PINC stock symbol. Note that the portletStateChange
field has been set to
readOnly
to indicate that a state change is not acceptable to the Consumer. We will discuss the
purpose of this field later in this section.
The runtimeContext
element of this request also includes the sessionID
previously
returned by C Inc.
Message 14: Blocking Interaction Request
To this request, P Inc responds with the message shown below.
Message 15: Blocking Interaction Response
The UpdateResponse
element of this response contains new navigationalState
created
by P Inc. This navigational state represents state that P Inc expects C Inc to return with subsequent
getMarkup
requests. In this specific example, P Inc created a string that contains the name of the
stock symbol and returned it as the navigational state. When C Inc returns this state with a future
getMarkup
request, P Inc extracts the name of the stock symbol from the navigational state, looks up
for the value of the stock symbol, and generates a markup fragment that shows the name and value of the
stock symbol. As far as the Consumer is concerned, the navigationalState
is completely opaque.
Navigational state is similar to a query string on a standard URL. Producers can express the result of
processing the interaction as the navigationalState
and use this state to generate markup as
many times as requested by the Consumer. For instance, if a Consumer sends a
performBlockingInteraction
request with the data necessary to create a purchase order in a database,
the Producer could return a reference to the primary key of the purchase order created as navigational
state, and use that state in subsequent getMarkup
requests to show pertinent information of the
purchase order created.
navigationalState
(or a reference to the navigationalState
)
in portlet URLs so that users can bookmark pages including the navigational state of each portlet. When a
user activates such a bookmarked URL, the Consumer extracts the navigationalState
and sends it
to the Producer to get similar markup as was obtained at the time of book marking.
Depending on the results of processing the performBlockingInteraction
request, the
performBlockingInteractionResponse
could include the following:
portletContext
with a portletHandle
and/or portletState
element. In this case, the Consumer prevented this by setting the portletStateChange
element to
a value of readOnly
. sessionID
. Consumer is required to send this sessionID
with future getMarkup
or performBlockingInteraction
requests. updateResponse
element. The value of this element is an
absolute URL that the Consumer is required to direct the user to. markupContext
element with the portlet markup. Note that to let the Producer generate
this, the performBlockingInteraction
includes the full MarkupParams
structure.
When a Producer returns markupContext
in the performBlockingInteractionResponse
,
Consumers can avoid calling getMarkup
and use this markup instead, presuming it honored any
requested changes in mode or window state. Consumers can also discard this markupContext
, and
send a usual getMarkup
request for the markup.
The following figure shows the overall sequence of getMarkup
and
performBlockingInteraction
requests.
In this two-step protocol, the following key differences between getMarkup
and
performBlockingInteraction
are worth noting.
performBlockingInteraction
requests only when a user interacts with a
portlet URL specifying a value for url-type of blockingAction
or secureBlockingAction. On the
other hand, Consumers send getMarkup
requests only whenever the portlet’s markup is required or
when the url-type is render or secureRender. For example, a simple browser reload of a Consumer’s aggregated
page or user interactions with other portlets on aggregated page may cause getMarkup
invocations without any performBlockingInteraction
invocation.
getMarkup
request. However, in the case of performBlockingInteraction
requests,
Producers can return such changes to the Consumer. getMarkup
requests without negative effects. In particular, a portlet making transient and/or
persistent changes to its state during markup generation must be prepared to generate markup any number of
times.
While processing a performBlockingInteraction
request, if allowed by the Consumer, the Producer
can clone the portlet, and return a portletContext
with a new portletHandle
and/or
portletState
. This is often called implicit cloning because the Consumer did not directly ask
the Producer to clone the portlet, rather the Consumer indicated that under certain circumstances the
Producer was to generate a clone and return it. For the Consumer, the new portletContext
replaces the current portletContext
for this user.
To illustrate how such implicit cloning may occur, consider the following variation to Scenario 5.
Scenario 6: Perform Interaction with Implicit Cloning
The portlet can use its portletHandle
as a primary key for storing the list of symbols.
However, before letting the portlet add the stock symbol to the list of preferred symbols, P Inc should
ensure that the portletHandle
of this portlet is specific to the current user and is not
shared with other users accessing the same portlet. Since P Inc offered this portlet with a
portletHandle
portfolioManager via its service description, there may be several Consumers (or
several users from the same Consumer) using this portlet with the same portletHandle
. In
order to avoid sharing the list with other users, P Inc must first create a new portletHandle
and let the portlet store the list against the new portletHandle
.
However, P Inc does not know whether C Inc allows several users to access the same portlet or not. That is, without the Consumer supplying additional information, P Inc cannot determine if it must clone the portlet before letting the portlet store the list of symbols. C Inc must therefore inform P Inc that, in case the portlet is trying to make state changes, P Inc must first clone the portlet.
This scenario illustrates one of the ways implicit cloning may occur. Other possibilities depend on how a Producer associates persistent state with portlets.
When a Producer implicitly clones a portlet, it returns the new portletHandle
(along with
portletState
, if it is not capable of storing state persistently) to the Consumer. However,
Consumers may not always be ready to accept a new a portletHandle
or portletState
.
For instance, the Consumer may not have persistent storage capabilities. Or, the Consumer may not want to
allow a given user affect the persistent state of a portlet as the user lacks adequate privileges. To
account for these situations, WSRP specifies a portletStateChange
element in the
performBlockingInteraction
request. Consumer can supply one of the following values for this
element:
readOnly
: This value indicates that the Producer is not allowed to return a new
portletHandle
and/or portletState
. If the portlet tries to update persistent state
that may cause a new portletHandle
or portletState
, the Producer will return a
PortletStateChangeRequired
fault to the Consumer. cloneBeforeWrite
: This value indicates that the Producer must first clone the portlet
before attempting to make persistent state changes. readWrite
: This value indicates that the Producer can make persistent state changes
without cloning the portlet.
Typically, Consumers capable of accepting implicit cloning initially send a value of
cloneBeforeWrite
, and replace it with readWrite
once implicit cloning occurs.
Producers are required to depend on the Consumer to properly indicate whether or not the user is allowed
to update the persistent state for the current portletHandle
.
The following figure illustrates the persistent lifecycle of a portlet caused by implicit cloning.
In this figure, rounded rectangles show two of the states in the persistent lifecycle of a portlet. The arrows between these states show transitions between states.
getServiceDescriptionResponse
(e.g. as in Message 2).
In our sample scenario, the portfolio manager portlet with portfolioManager as the portletHandle
is a producer-offered portlet. cloneBeforeWrite
for portletStateChange
with the
performBlockingInteraction
request. In Section 6, we will discuss an explicit method of cloning and destroying portlets.
Between typical browser-server interactions, web servers use cookies to set state to the browser, which the browser returns with subsequent requests. RFC 2965 [8] describes the rules governing cookies.
In the case of WSRP, Producers may set cookies on responses to Consumers, requiring the Consumers to
return those cookies with future getMarkup
and performBlockingInteraction
requests. Here is a sample scenario that motivates the use of cookies.
Scenario 7: Initializing Cookies
P Inc can use the requiresInitCookie
element in its service description (refer to Section
5.1.18 of the WSRP 1.0 Specification for the allowed values) to inform Consumers of this need and C Inc
then uses the initCookie
operation of the markup interface to implement the scenario.
When C Inc sends an initCookie
request, P Inc can set HTTP cookies with the response, and
require C Inc return those cookies with getMarkup
and performBlockingInteraction
requests.
For example, consider that P Inc sets the value of requiresInitCookie
to any value other
than none
in its service description. C Inc then sends the following initCookie
request to P Inc.
Message 16: Init Cookie Request
In return, P Inc sends the following response along with Set-Cookie
headers (at the HTTP
transport level). In the current scenario, the value of the cookie may contain some information to let
the load-balancing mechanism identity the Producer instance in the cluster.
Message 17: Init Cookie Response
C Inc collects these cookies, and resends them with subsequent getMarkup
and
performBlockingInteraction
requests.
In Message 13, we saw that the Producer, P Inc. initialized a
session for the portfolio manager portlet, and returned a reference to that session as a sessionID
in its response. The Producer and/or the portlet may also be managing in-memory state in those sessions.
As a Consumer interacts with a Producer for different portlets on behalf of a given user, the Producer
may initialize sessions for these portlets, and return session IDs of those sessions. Since the Consumer
is required to supply these IDs to the Producer on subsequent invocations, the Consumer will have to
store those temporarily, for example, in the user’s session on the Consumer itself.
What happens if the user stops interacting with the Consumer, or the user’s session on the Consumer has
timed out? In these cases, the sessions on the Producer will remain alive until they timeout naturally.
To let the Producer reclaim storage consumed by such sessions in a timely manner, the Consumer can send
a releaseSessions
request to the Producer to inform it that those sessions will not be
referenced by future invocations.
In our scenario, C Inc can send the following request to P Inc to release the session created for the portfolio manager portlet.
Message 18: Release Sessions Request
The Consumer can add several session IDs in this request. To this request, P Inc terminates the session, and returns the following response. The response merely indicates that the Producer has released the session, and the Consumer can no longer use those session IDs.
Message 19: Release Sessions Response
While Producers are required to support the releaseSessions
operation, Consumers may or may
not send a releaseSessions
request to the Producer. Therefore, we recommend that Producers
expire sessions after meaningful time interval or inactivity interval, and not depend on the
releaseSessions
operation alone.
Consumers can use modes and window states to influence the behavior and markup of a portlet.
Portlets can expose their functionality with different modes, with each mode catering to a particular
function. For example, a portlet can provide its default functionality in one mode (e.g. wsrp:view
mode) and provide customization functionality under a different mode (e.g. wsrp:edit
mode).
WSRP 1.0 Specification specifies wsrp:view
, wsrp:edit
, wsrp:help
, and wsrp:preview
modes as standard modes that portlets can support.
Window states, on the other hand, let Consumers indicate how much markup a portlet should generate. WSRP
1.0 Specification specifies wsrp:normal
, wsrp:minimized
,
wsrp:maximized
, and wsrp:solo
as standard window states. Portlets could generate
different length/style of markup in each of these window states. For example, a portlet could generate
its complete view (with more markup, images etc) in wsrp:maximized
window state, while
generating no displayable markup in wsrp:minimized
state.
In addition to these standard modes and window states, portlets could offer markup in additional modes
(known as custom modes) and window states (known as custom window states). Producers advertise the modes
supported by a portlet in the description of the portlet. Consumers typically provide decorations (such
as a title bar with buttons) to let users request portlet markup in various modes and window states.
WSRP 1.0 Specification requires that portlets support wsrp:view
mode and wsrp:normal
window state so that Consumers are able to obtain markup in at least one mode and window state they
support.
Portlets could request a change to the current mode and/or window state while processing a
performBlockingInteraction
by returning the requested new values within the
performBlockingInteractionResponse
. Consumers are expected (although, not required) to honor
such mode and window state changes. If a Consumer does not understand a portlet’s mode or window state
(including custom modes and custom window states), the Consumer is unlikely to request markup using that
mode or window state. In such cases, the Consumer can request for markup in one of the known modes and
window states.
A Consumer could have its own set of custom modes and window states, and attempt to request a portlet render in one of these. If the portlet does not comprehend the requested mode or window state, the Producer returns an appropriate fault message.
HTML 4.01 states: “Since style sheets are now the preferred way to specify a document's presentation, the presentational attributes of BODY have been deprecated.” Accordingly, WSRP 1.0 has adopted an initial basic set of CSS classes designed to provide a standard set of display options for portlets. For a list with tables of these portlet classes, see Section 10.6 of WSRP 1.0 specification. Use of CSS portlet classes are optional and only appropriate for those markup types supporting CSS.
WSRP allows the Consumer to cache markup fragments returned by the Producer. This enables the Consumer
to avoid calling getMarkup
again to obtain the same markup fragments that the Producer had
returned previously and had indicated as cacheable. In addition to improved performance at the Consumer,
caching makes the Producer more efficient since the Producer does not have to regenerate identical
markup fragments across a series of requests. Note that the Consumer must take into account the
MarkupParams
structure that the Consumer sent to compute any key used to locate cached markup
fragments in the Consumer’s caching mechanism.
The presence of a valid (i.e., non-null) CacheControl
in the MarkupContext
sent by the Producer when returning markup is the hint given by the Producer to the Consumer that it may
choose to cache the returned markup for subsequent invocations. The CacheControl
structure
includes information such as the duration that the cached markup is valid for, the user scope of the
markup (e.g. whether the Consumer can share the markup for other users as well), as well as a tag that
the Consumer can use to send to the Producer to validate if the cached markup can still be used by the
Consumer even after the expiry of the cache.
To illustrate how caching works, let us revisit Scenario 4, wherein C Inc made a request to P Inc for the initial markup of the portfolio manager portlet.
Here is the response from P Inc.
Message 20: Get Markup response that includes caching information
This message is similar to Message 13, except for the parts shown
in bold. In this response, P Inc returned a CacheControl
element as part of the
MarkupContext
that indicates to C Inc that the markup fragment returned is cacheable.
In this particular response, the CacheControl
structure includes the following elements:
expires
: This field indicates that the markup fragment referenced by this cache control
is valid for 60 seconds (counting from point in time when the markup was returned). userScope
: A value of wsrp:perUser
specifies that the markup is specific
to the userContext
for which it was generated. validateTag
: The value portfolioManagerPValidateTag
is for the purpose of
the Consumer to verify with the Producer if this particular cached markup fragment is still valid even
after it has expired (i.e. in the situation whereby, even though the cache had expired, calling
getMarkup
would result in the same markup fragment being returned).
Next, let us suppose that the user at C Inc refreshed the page in the browser. In the absence of any
caching, this would have caused the Consumer to get the markup for the portlet from the Producer again.
However, since the markup that was just returned did contain a valid CacheControl
, the
Consumer can use the cached markup.
Now let us explore the scenario whereby the user refreshed the page after the expiry of the cached
markup (i.e., after 60 seconds). Since the Producer returned a validateTag element as part of the
CacheControl
, the Consumer has the option of sending the value of that element back to the
Producer to determine if it can still reuse that cached markup.
Here is the new getMarkup
request from C Inc to P Inc.
Message 21: Get Markup Request with a validate tag
The above request from the C Inc to P Inc is similar to Message 12
except for the line shown in bold. The MarkupParams
structure now also contains a
validateTag element with the value portfolioManagerPValidateTag
that P Inc returned earlier
as part of the CacheControl
structure. The Consumer is supplying this as a means for the
portfolio manager portlet to avoid generating new markup if it can valid this tag.
Let us assume that the markup is indeed still valid. P Inc responds to the getMarkup
request as shown below.
Message 22: Get Markup Response that includes a CacheControl
structure
In the response above, the Producer indicates that the cached markup fragment is still valid for this
request by setting the useCachedMarkup
to true
. Note that the Producer
intentionally omits the markupString
field from the response. Also, note that it is
mandatory for the Producer to send back a new cacheControl
structure to the Consumer to
indicate a new expiry field for the given markup fragment. The Consumer should replace this with any
other value it had stored earlier.
Lastly, with respect to caching invalidation, we recommend Consumers discard any cached markup for the
given portlet once they invoke performBlockingInteraction
since the operation may result in
the cached markup becoming invalid. Future versions of WSRP may provide a means for a portlet to
indicate that the markup cached by the Consumer is no longer valid.
The markup interface deals with markup, user interactions, and the state associated. Due to the complexities associated with these, Producer and Consumer implementers must take into account a variety of issues and choices. During the lifetime of a portlet, the markup interface gets more heavily used than other interfaces, and hence implementers must take into account performance and scalability issues as well. In addition, Producers invoke portlet(s) during this interface, portlet developers must also be aware of certain intricacies. In this section, we present some guidelines for implementers and portlet developers.
The first thing to note about the markup interface is the two-phase protocol. Producers must capture the result of an interaction as navigational state or some other form transient/persistent state and be prepared to generate markup any number of times with the help of that state.
Producers can use navigationalState
or sessions (or both) to manage transient state.
However, navigationalState
has some advantages over using sessions. In particular,
Producers/Consumers can embed navigationalState
in URLs in markup returned to end users.
Users can therefore bookmark URLs and be able to view the same/similar content at a future time. Since
sessions usually have limited lifetime, after the Producer terminates a session, users may not be able
to view same/similar content at a future time.
Use of navigationalState
to represent transient state also improves cacheability of markup
by Consumers. Consumers can use the navigationalState
as part of the cache key for caching
the markup, and serve cached markup whenever the same navigationalState
is found for a
given getMarkup
request.
Another point to consider is the network traffic. In order to reduce network overhead, we recommend the following practices:
performBlockingInteraction
,
Consumers can avoid invoking the getMarkup
request for the same portlet on the same
Producer, saving one network roundtrip. getMarkup
requests concurrently instead of serially. Provided the Consumer has
sufficient network bandwidth, this approach will help improve responsiveness of the Consumer as far as
end users are concerned. Another issue for consideration is URL generation. Producers must carefully evaluate their portlets and usage to support one of the forms of URL generation. In general, URL template based URL generation offers better performance when the markup is personalized for each user and the Consumer is able to supply URL templates and not post-process the markup returned from the Producer. On the other hand, Consumer URL rewriting has the advantage of cacheability. With Consumer URL rewriting, the markup returned by the Producer does not include references to the Consumer, and therefore the Producer can cache the markup and serve the cached markup to several Consumers.
Although Producers can choose to support either Producer writing or Consumer rewriting, Consumers must be prepared to support both so that the Consumer can easily work with diverse Producer implementations.
The purpose of the portlet management interface is to let Consumers manage the persistent state and lifecycle of portlets explicitly.
In addition to the transient state (such as navigational state) of portlets we discussed in the previous section, portlets can have persistent state as well. WSRP allows Producers to expose a transparent view on such persistent state as properties. Portlet properties are data associated with a portlet. Using the portlet management interface, Consumers can access and change those properties.
An example of a portlet property is the list of stock symbols for the portfolio manager portlet. While this portlet encapsulates the functionality necessary to manage portfolios, the portlet may declare the list of the stock symbols as a property. Each Consumer can use the portlet management interface to clone this portlet for each user, and set the values of the stock symbol property for each user.
Note that the persistent state of producer-offered portlets is not explicitly modifiable by Consumers. However, when a Producer exposes such persistent state via properties, Consumers can use the portlet management interface to create a consumer-configured portlet, and modify the exposed portion of its persistent state explicitly.
The Portlet Management interface provides for the following persistent lifecycle of portlets.
The lifecycle of portlets consists of three states (shown in rounded rectangles). The arrows between these states indicate transitions between these states. The bold arrows show the transitions that a Consumer can cause explicitly using the portlet management interface.
getServiceDescriptionResponse
(e.g. as in Message 2).
Consumers cannot explicitly modify the persistent state of such portlets. performBlockingInteraction
operation when the
Consumer sends a value of cloneBeforeWrite
for the portletStateChange
flag. A Consumer can explicitly create such a portlet by sending a request to clone the portlet to the
Producer. Consumers can change the properties of consumer-configured portlets. Consumers can also clone
Consumer-configured portlets. In addition to the operations to manage this lifecycle explicitly, the portlet management interface offers methods to get the descriptions of producer-offered or consumer-configured portlets, and to get/set properties of a portlet.
The portlet Management Interface offers the following operations:
getPortletDescription
: Consumers can invoke this operation to get a description of a
producer-offered or consumer-configured portlet. getPortletPropertyDescription
: Consumers can invoke this operation to obtain a
description of properties (if any) of a portlet. This operation returns the metadata (such as names, and
schema types) of properties. getPortletProperties
: Consumers can invoke this operation to obtain the properties
(including their current values) of a producer-offered or a consumer-configured portlet. clonePortlet
: Consumers can invoke this operation to explicitly clone a portlet, such
that any properties associated with the cloned portlet may be modified without affecting the properties
of the portlet that it is cloned from. Consumers can clone both producer-offered and consumer-configured
portlets. setPortletProperties
: Consumers can invoke this operation to modify the values of
properties of a consumer-configured portlet. destroyPortlets
: Consumers can explicitly destroy consumer-configured portlets using
this operation.
While the getServiceDescription
operation of the service description interface returns
descriptions of all portlets offered to a given Consumer, the getPortletDescription
operation returns the description of a single portlet. This operation serves two purposes:
portletHandle
of a portlet, the Producer returns the description of a
producer-offered or a consumer-configured portlet.
For producer-offered portlets, in response to a getPortletDescription
request, Producers
are free to return the same portlet description as is returned in the
getServiceDescriptionResponse
.
Let us consider the following scenario, and discuss the semantics of this operation.
Scenario 8: Get Portlet Description
To get the description of the portfolio manager portlet, C Inc has two options. If the
portletHandle
of the portlet is producer-offered, C Inc can send a getServiceDescription
request and search the response for a description of the portfolio manager portlet. Alternatively, it
can send a getPortletDescription
request to get a description of the portlet. Some
advantages of the later option is that C Inc can use the same operation for producer-offered as well
as consumer-configured portlets and that the returned data is likely to represent any filtering that P
Inc does for the user.
C Inc. sends the following message to obtain the description of the portfolio manager portlet.
Message 23: Get Portlet Description Request
In response, P Inc sends the following message with the description of the portlet:
Message 24: Get Portlet Description Response
The portletDescription
returned in this message is the same as the one returned by the
getServiceDescription
operation of the service description interface shown in
Message 7. Some advanced Producer implementations may
tailor (for example, not advertise certain window states or modes) the returned description based on
the registrationContext
and userContext supplied by the Consumer.
The getPortletPropertyDescription
operation returns a description and metadata of
properties of a given portlet. Consumers can use this metadata to design user interfaces or
applications to view/modify portlet properties. Note that this method does not return the values of
properties.
Let us consider the following scenario.
Scenario 9: Get Portlet Property Description
In order to implement this scenario, C Inc sends a getPortletPropertyDescription
request to P Inc. Using the returned descriptions and data types of these properties, C Inc designs
a page to view/modify the properties.
Message 25: Get Portlet Property Description Request
The portfolio manager portlet has two properties viz., stockSymbolList
and
refreshInterval
. P Inc therefore returns the following response:
Message 26: Portlet Property Description Response
This response includes two properties – a stockSymbolList
property of type
xs:string
, and a refreshInterval
property of type xs:int
. The
names, descriptions, and data types of these properties help C Inc. design a user interface for
displaying and entering new values for the properties. In addition to the standard schema types,
Producers can use any arbitrary schema types (other than those defined in the
urn:oasis:names:tc:wsrp:v1:types
namespace) to describe portlet properties.
In addition to the type, a Producer may optionally supply a label and a hint. In the above message, labels provide a short description of each property.
The purpose of getPortletProperties
operation of the portlet management interface is to
return all or some properties of a given portlet. Consumers can use this operation in conjunction
with the getPortletPropertyDescription
operation to show portlet properties to users.
Let us consider the following scenario.
Scenario 10: Get Portlet Properties
To implement this scenario, C Inc sends the following message to get the current values of properties of the portfolio manager portlet.
Message 27: Get Portlet Properties Request
In this request, the value of the portlet handle is the same that of the portfolio manager portlet offered in the service description of P Inc.
With the getPortletProperties
request, the Consumer can optionally indicate if it
wants the values of all properties, or only for specific properties. When the names element is set
to nil
, this request implies that the Producer must return values for all properties
of this portlet. In case the Consumer is interested only in the values of certain properties, it
can specify the names for which it needs values. This option is particularly useful when the
portlet has a large number of properties. In the following request, C Inc specifies the
stockSymbolList
property.
Message 28: Get Portlet Properties Request (For Specific Properties)
The default value of the stockSymbolList
property is “AMZN” and the default value of
the refreshInterval
field is 180 seconds. For the request in
Message 27, P Inc returns the following response with
these values.
Message 29: Get Portlet Properties Response
C Inc can now populate the user interface with these values filled in. Note that, as the first
property is of type stringValue
, P Inc returned a stringValue
element,
and for the second property, P Inc returned a namespaced xs:int
element.
As we discussed above, Consumers cannot modify persistent state of producer-offered portlets. In
order to be able to change persistent state, Consumers must first let the Producer clone a
portlet. In WSRP, Consumers use the portletHandle
to uniquely refer to a portlet.
After cloning, Producers associate a new portletHandle to the portlet. As long as the Consumer or
the Producer makes no changes to the cloned portlet, the cloned portlet and the portlet it is
cloned from have identical persistent state, and should behave the same.
Once a Consumer clones a portlet, the Consumer can modify its persistent state without affecting the portlet it is cloned from.
Note that cloning does not imply any hierarchical relationship between the cloned portlet and the portlet it is cloned from.
Let us consider the following scenario.
Scenario 11: Clone the Portlet
In order to implement this scenario, C Inc must first clone the portfolio manager portlet because it cannot directly modify the properties of a producer-offered portlet.
C Inc sends the following clonePortlet
request to P Inc.
Message 30: Clone Portlet Request
P Inc creates a clone of this portlet, and returns the following response with a new portlet handle.
Message 31: Clone Portlet Response
The returned portlet handle corresponds to a consumer-configured portlet created explicitly by cloning a producer-offered portlet, and is valid for the duration of the Consumer’s registration.
If the Producer is capable of storing state of cloned portlet, the Producer may just return a
portletHandle
.
However, if the Producer is not capable of storing the state of the cloned portlet persistently,
the Producer may choose to return such state as portletState
to the Consumer. In
such cases, the Consumer would be responsible for persistently storing the portletState
along with the portletHandle
and return these to the Producer in future
invocations.
C Inc now uses the new portlet handle during all subsequent requests for the portfolio manager
portlet for that user. Note that C Inc may also use the new portlet handle with a
getPortletDescription
request to get a description of the portlet.
Consumers can use the setPortletProperties
operation of the portlet management
interface to modify the properties of consumer-configured portlets. Note that it is an error to
use this operation to attempt to modify the properties of producer-offered portlets.
Referring to our scenario, having cloned the portfolio manager portlet, C Inc can change the
persistent state of the cloned portlet. When a user fills in new values for the values of these
properties, and submits a form, C Inc uses the setPortletProperties
operation to
let P Inc change properties.
Scenario 12: Setting Portlet Properties
C Inc sends the following request to P Inc. This request includes a cloned portletHandle
obtained via the clonePortlet
request in the previous section, and the new values
of the properties.
Message 32: Set Portlet Properties Request
P Inc. updates the values of the properties, and returns the following response. Note that the
WSRP specification does not allow the Producer to change the portletHandle
in this
response. The purpose of the portletContext
structure in this response is only to
allow the Producer to return any portletState
.
Message 33: Set Portlet Properties Response
portletState
in the
setPortletPropertiesResponse
.
When a Consumer receives such portletState
, it is required to supply the same
with PortletContext
in all future invocations for that portlet.
The following sequence shows the sequence of interactions for setting portlet properties with cloning.
In the above scenarios, the Consumer cloned a producer-offered portlet, so that it can update the persistent state of the portlet. In most cases, Producer implementations will have to store some state in a persistent store such as a relational database. Once the Consumer determines that a consumer-configured portlet is no longer in use, the Consumer should request the Producer to destroy that portlet as this will allow the Producer to clean or archive any stored state.
The destroyPortlets
operation serves this purpose. It allows a Consumer to request
a Producer to destroy one or more consumer-configured portlets. Consider the following scenario.
Scenario 13: Destroy Portlets
In order to destroy portlets, C Inc sends the following request to P Inc.
Message 34: Destroy Portlets Request
Note that C Inc may send more than one portlet handle in this request, so that the Producer can destroy several portlets in a single request.
Upon verifying that the portlet handle refers to a consumer–configured portlet, P Inc can delete or archive any persistent state, and return the following response.
Message 35: Destroy Portlets Response
However, if the Consumer attempts to destroy a producer-offered portlet, or if the Producer
fails to destroy a portlet due to some internal failure, the Producer may include the portlets
that it failed to destroy and a reason for the failure in the destroyPortletsResponse
.
The following message shows the response from P Inc when it fails to destroy a portlet.
Message 36: Destroy Portlets Response When Failed
This response indicates the P Inc failed to destroy the portlet with handle portfolioManager.1.
After the Producer destroys a consumer–configured portlet, it can no longer use the portlet with that handle.
The following sequence illustrates a Consumer aggregating cloned portlets for several users, and destroying the cloned portlets when such portlets are no longer required.
The portlet management interface is an optional interface, and the WSRP specification does not require Producers to implement this interface. If you are implementing a Producer, consider implementing the portlet management interface to allow users/Consumers of your portlets to explicitly manage the lifecycle and customize the properties of portlets. You can thus allow each usage to behave differently while sharing the same implementation (i.e., code) of portlets. To take full advantage of this interface, your portlets must be able to expose some/all of their persistent state as properties. If none of your portlets is capable of doing so, you may not find much value in implementing this interface. Note that the WSRP specification requires support for this interface if portlet clones are ever created.
One of the common choices faced by Producers implementing this interface is whether to expose portlet properties as simple types (such as strings, integers etc) or as complex types. Exposing properties as complex types has the advantage of granularity and typing. However, for Consumers, it may prove to be complex to generate a generic user interface to show/modify complex portlet properties. If a Producer exposes properties as complex types, Consumers may have to generate special purpose user interfaces for each complex type. In order to let Consumers generate a generic user interface, we recommend using simple types.
The purpose of use profiles is to provide a well-defined palette of functionality for Producers and Consumers. By qualifying a Producer or a Consumer implementation with a use profile palette, implementers can indicate the level of functionality supported. WSRP use profiles are non-normative, and should be regarded as general guidelines. Implementers will likely compose their implementations by selecting from a “palette” of functionality, and this section provides some guidance on how to map these use profiles across several functional axes. Refer to [9] for a complete description of use profiles.
WSRP use profiles declare following levels for Producers:
The following are the use profiles for Consumers:
The use profiles are intended to simplify the possible combinations of support for optional areas of the WSRP specification. Each profile specifies a certain set of functionality as supported. While an implementation may also support other optional functions, specifying the supported use profile helps customers to compare the support offered by implementations.
A Consumer and Producer have different motivations in achieving higher levels. A Producer need only implement the functionality required by the portlets it is offering. Unless a Consumer knows that it will only be consuming portlets from a Producer of a given level, it should provide all levels so that any portlet can function properly. The Consumer should not assume that there is graceful degradation of functionality if it does not implement certain functionality. For example, if a Consumer does not provide, say, registration, a portlet from a Producer requiring registration will not function at all.
Also note that there is not a one-to one correspondence with Producer Levels and Consumer
levels; e.g. the base consumer level is expected to handle the initCookie
operation, while the base Producer level does not require this operation.
The following table illustrates some common scenarios that Producers and Consumers implement, and provides a mapping of those implementations to user profiles.
Functionality/Use Case | Notes | Consumer Level | Producer Level |
Implements all required interfaces | The required interfaces are markup and service description interfaces. These interfaces are required so that the Producer and Consumer can offer some minimal level of portlet aggregation. | Base | Base |
Markup Interface | |||
Producer requires cookie initialization for markup operations | Base level Consumer must honor the requiresInitCookie element of the service description of a Producer. | Base | Simple |
Support Consumer-rewriting of URLs | Consumers should at least support consumer rewriting of URLs. In our sample scenario, P Inc and C In rely consumer-rewriting for generating URLs and rewriting names in markup fragments. | Base | Base |
Producer URL Writing | For Producer to be able to create URLs, Consumer submits URL templates. In our sample scenario, P Inc does not support producer-writing of URLs | Complex | Complex |
Support wsrp:normal window state and wsrp:view mode |
Producers must be able to support at least one mode and window state. Normal window state
(wsrp:normal ) and view mode (wsrp:view ) are the values that
Producers and Consumers must support. In our sample scenario, P Inc supports wsrp:view
mode and wsrp:normal window state. |
Base | Base |
Support markup types markup | Portlets must be able to support at least one type of markup. In our sample scenario, the portfolio manager portlet offers text/html markup. | Base | Base |
Support Navigational State | Navigational state is one of the basic form of representing transient state of a portlet.
In our sample scenario, P Inc includes the user supplied stock symbol and its value as the
navigational state for C Inc to return with getMarkup requests. |
Base | Simple |
Session State | For Producers, managing session state is optional. However, Consumers must support sessions to guarantee a basic level of aggregation of portlets. In our sample scenario, P Inc manages session state. | Base | Simple |
Markup Caching | Producer supplies a cacheControl element to indicate Consumer whether it can
cache the markup. |
Simple | Simple |
Supports Standard Modes | wsrp:edit , wsrp:help , and wsrp:preview modes. P Inc
uses standard modes. |
Simple | Simple |
Supports Standard Window States | wsrp:maximized , wsrp:minimized and wsrp:solo window
states. P Inc uses standard window states |
Simple | Simple |
Caching validation | Use the validateTag field of MarkupParams |
Complex | Complex |
Multiple Markup Types | Portlets could support multiple markup types (e.g. text/html and text/wml). This would allow Consumers to provide portlet aggregation for various devices and non-browser environments. | Complex | Simple |
Supports Custom Modes | e.g. a print mode | Complex | Complex |
Supports Custom Window States | e.g. a half-page mode | Complex | Complex |
Registration Interface | |||
In-band Registration | Base level Consumers cannot display portlets that require registration. P Inc uses in-band registration. | Simple | Simple |
Out-of-band Registration | Complex level producers could allow out-of-band registration by creating a
registrationHandle by other means than the register operation. |
Complex | Complex |
Portlet Management Interface | |||
Implicit or explicit cloning of portlets | Base level Consumer and Producer do not support cloning. | Simple | Simple |
Grouping of Portlets | Producers could group portlets to allow portlets in a group share transient/persistent state. Refer to Section 3.8 of the WSRP 1.0 Specification for details. | Complex | Complex |
Persistent local state | Producers could manage persistent state locally and not return portletState
or registrationState . In our sample scenario, P Inc is capable of managing
persistent state locally. |
Simple | Complex |
Advanced | |||
Portlet Management Interface | Consumers can use the portlet management interface to manage persistent lifecycle of portlets explicitly. Consumer may create a user interface for property management using this interface. | Complex | Simple |
Localization | Producers may be able to supply localized values for resources such as names, descriptions etc. In our scenario, P Inc supports en and en-US locales. A complex Consumer would support multiple locales. | Complex | Complex |
User Categories | Producers may be able to personalize portlet markup/behavior based on user categorization. Producers and Consumer typically agree on (out-of-band) the semantics of user categories. | Complex | Complex |
WSRP specifies a number of faults that a Producer may return in response to various requests from a Consumer. If you are setting up a Consumer to aggregate portlets from a Producer, knowledge of the implication of these faults would help debug any problems. Note that Producers may return additional faults as dictated by underlying web service stack.
Each WSRP fault has an associated faultcode. Here is an example message from a Producer that
requires registration in response to a request from a Consumer without the
registrationContext
.
Message 37: Fault Response
The faultstring in this message explains that the Consumer must supply registrationContext
with the request. Also, note the detail element. This element contains the name of the faultcode
qualified by oasis:names:tc:wsrp:v1:types namespace
.
A Producer may return this fault when the Producer is unable to provide access to a portlet for a given operation due to security policy reasons.
Action: Since such security policy restrictions are implementation specific, consult the entity hosting the Producer to determine an appropriate action.
A Producer may return the InconsistentParameters
fault when a Consumer supplies
inconsistent data. For example, a Producer returns this fault when a Consumer tries to access a
portlet with a portletHandle
that was created during a different
registrationContext
than the one the Consumer supplied.
Action: This fault may occur because of implementation errors in the Consumer.
Make sure that the portletHandle
included in the request corresponds to either a
portletHandle
returned in the service description response, or one returned during
performBlockingInteraction
or clonePortlet
operations invoked using
the same registrationContext
. If not, use the correct registrationContext
or reset the
This fault indicates that the Consumer did not supply a registrationContext
when
registration is required, or the supplied registrationContext
is invalid.
Action: This fault may occur because of implementation errors in the Consumer.
Check the Producer’s service description to see if the Producer requires registration. If so,
register the Consumer with the Producer and resend the request with a valid
registrationContext
. If you have already registered your Consumer with the Producer, make
sure that the registrationContext
is included in the request. Also make sure that
the registrationContext
is the same as the one returned by the Producer. If the
Producer still returns the same fault, check the message to see if you need to reregister the
Consumer as the Producer may have invalidated previous registration.
HTTP cookies are transient and may become invalid. A Producer returns this fault when the Consumer supplied cookie is no longer valid.
Action: The fault may occur due to Producer imposed timeout of cookies. Invoke
the initCookie
operation again and then invoke the operation that caused this fault
with the new cookie. Since cookies returned by the Producer may be related to the session IDs
returned in an implementation-specific manner, resend any data stored that the Producer stores
in the session. For example, if the Producer indicated that it stores URL templates and/or user
context data in sessions, resend URL templates and user context data with the request.
A Producer returns this fault when the Consumer supplied portletHandle
or
registrationHandle
is invalid.
Action: This fault may occur because of implementation errors in the Consumer.
Make sure that the portletHandle
included in the request corresponds to either a
portletHandle
returned in the Service Description response, or one returned by
either performBlockingInteraction
or clonePortlet
operations invoked
using the same registrationContext
.
A Producer returns this fault when a Consumer-supplied session ID is invalid.
Action: This fault may occur due to Producer imposed timeout of sessions.
Invoke the same operation without the sessionID
and with any data that the Producer
has indicated that it stores in the session. For example, if the Producer stores URL templates
and/or user context data in sessions, resend URL templates and user context data with the
request.
A Producer returns this fault when a Consumer supplied userCategory
name is not
valid. Note that Consumer should not supply user categories not recognized by Producers.
Action: This fault may occur as a result of implementation errors in the
Consumer. Make sure that the userCategory
is one of those supplied by the Producer
in its service description response.
A Producer returns this fault when some required data is missing in the request.
Action: This fault may occur because of implementation errors in the Consumer. Since the set of parameters required are specific to each operation, refer to the description of the operation and make sure that all the required parameters are included in the request.
This is the most generic fault that a Producer can return for any request from a Consumer. In general, well-behaving Producers return this fault only when the condition that caused the fault cannot be described with any other WSRP fault.
Action: If you encounter this fault, look into the faultstring for any clues, and if no meaningful explanation is found, contact the entity hosting the Producer for help.
A Producer throws this fault when the portlet needs to update its persistent state during a
performBlockingInteraction
but the Producer cannot allow it since the Consumer is
not ready for state changes.
During performBlockingInteraction
, the portletStateChange
flag in the
request dictates persistent state changes. When the value of this flag is set to readWrite
or cloneBeforeWrite
, the producer can allow the portlet to make persistent state
changes. A persistent state change may cause the Producer to return a new portletContext
.
In case the Consumer is not capable of accepting the new portletContext
, it may
instead set the value of the portletStateChange
flag to readOnly
,
which would cause this fault.
Action: If possible, configure the Consumer to allow state changes. Note that portlets may not function correctly when prevented from making persistent state changes. If you find that the portlet is not usable without persistent state changes and if you are unable to configure the Consumer to allow state changes, consider not using the portlet.
A Producer may throw this fault when a portlet is unable to generate markup in the requested locale.
Action: This fault may occur because of implementation errors in the Consumer. Since the portlet is not capable of generating markup in the requested locale, restrict the Consumer to supply one of the locales indicated as supported by the portlet’s metadata.
This is similar to the UnsupportedLocale
fault, and a Producer throws this fault
when a portlet cannot generate markup in the requested MIME type.
Action: This fault may occur because of implementation errors in the Consumer. Since the portlet is not capable of generating markup in the requested MIME type, restrict the Consumer to supply one of the MIME types indicated as supported by the portlet’s metadata.
A Producer throws this fault when it cannot invoke a portlet in a given mode.
Action: This fault may occur because of implementation errors in the Consumer. Restrict the Consumer to supply a mode indicated as supported by the portlet’s metadata.
A Producer throws this fault when a portlet cannot be invoked in a given window state.
Action: This fault may occur because of implementation errors in the Consumer. Restrict the Consumer to supply a window state supported by the portlet
Most of the responses from a Producer include string values, such as names, descriptions, hints, etc. For example, the description of a portlet includes description, title, short-title, keywords etc expressed each with a string value and a locale. By default, Producers often use a fixed locale (usually the Producer’s default locale) for these values. In order to let Consumers obtain such values in some other locale (or more than one locale), WSRP allows Consumers to supply a list of preferred locales. Here are the operations that allow Consumers to pass locales:
getServiceDescription
: Consumer can send a desiredLocales array with a
getServiceDescription
request. If supported, the Producer will return all strings in the
given locales. getPortletDescription
: Consumer can send a desiredLocales array with a
getPortletDescription
request. If supported, the Producer will return all strings in the
given locales. getPortletPropertyDescription
: Consumer can send a desiredLocales array with a
getPortletPropertyDescription
request. If supported, the Producer will describe the
portlet’s properties in the given locales. getMarkup
: With a getMarkup
request, the Consumer can send an
array of locales to request the Producer to return the markup and the preferredTitle in one of
the given locales. In all these cases, the Producer has the following options to send a localized string value:
LocalizedString
, with a string value and a locale. For
example, in Message 2, P Inc returned the
description and title with a string value and an xml:lang
attribute for the locale.
LocalizedString
with a string value, an xml:lang
attribute for the locale of the string value, and a resourceName attribute. The purpose of the
resourceName attribute is to return string values in multiple locales with
getServiceDescriptionResponse
, getPortletDescriptionResponse
and
getPortletPropertyDescriptionResponse
messages. Each of the messages can include a
resourceList
array. The resourceList
array can contain several
Resource
elements. Each Resource
element includes the resourceName, and a
ResourceValue
with string values expressed in the locale indicated by an
xml:lang
attribute. To illustrate how a Producer can localize its response with resources, let us revisit Scenario 1, and consider that C Inc requested for strings in “en” and “de” locales. To such a request, P Inc may return the following response.
Message 38: Get Service Description Response with Resources
This message is similar to Message 2, except for the parts shown in bold. In this response, both the description and title include resourceName attributes and corresponding resources. For each resourceName, the response includes a resources element with the resource value in “de” locale.
Although the WSRP 1.0 Specification accounts for the most common scenarios, implementers may find a need to extend WSRP to deal with more advanced scenarios or scenarios not addressed by the specification. To account for such scenarios, WSRP Specification allows implementations to extend most of the WSRP data structures to include additional data as extensions.
Extensions are implementation-specific. A Producer and Consumer must agree to the purpose and semantics of the extension before extending any WSRP data structure. Note that Producers using extensions are not guaranteed to function correctly if a Consumer does not supply extended data required by the Producer. If you are implementing a Producer, consider making any extensions optional so that the Producer can interoperate with Consumers that do not supply extensions.
The WSRP specification requires that Producers and Consumers declare extensions in namespaces other than the one used by the WSRP specification to avoid conflicts with future versions of the WSRP specification.
If you find that WSRP specification does not represent some specific use case and you are relying on extensions to address the use case, please email your use case to wsrp-comment@lists.oasis-open.org.
When a Consumer sends a performBlockingInteraction
request, Producers reconstruct
the input from the supplied InteractionParams. The InteractionParams can include form parameters
as well as uploaded data. For example, when a HTML markup includes a form with an enctype
attribute with value multipart/form-data
, and one or more input controls of type
file
, the Consumer must extract the uploaded data from the incoming HTTP request,
and send the same to the Producer. The Consumer has the following options of passing such data
via InteractionParams to the Producer:
uploadContexts
element, or one uploadContexts
element per part in the incoming multiple request. formParameters
element, or as an
uploadContexts
element.
The uploadContexts
element includes the uploaded data (as uploadData
),
its MIME type (as mimeType
), and any MIME headers sent by the browser to the
Consumer (as mimeAttributes
). Since browsers may send a variety of headers while
uploading files, we recommend Consumer implementations to include all those attributes to let
the Producer reconstruct the request.
The editors/contributors of this Primer would like to acknowledge the ideas, material, and feedback provided by Polina Alber, Olin Atkinson, Christopher Coco, William Cox, Howard Crow, Michael Freedman, Ricky Frost, Simon Godik, Scott Goldstein, Lars Hofhansl, Richard Jacob, Andre Kramer, Avi Klein, Jon Klein, Carsten Leue, Khurram Mahmood, Farrukh Najmi, Fubini Ross, Yossi Tamari, and Rich Thompson,
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © The Organization for the Advancement of Structured Information Standards [OASIS] 2001. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwe explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an “AS IS” basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.