| |||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
Binding | Tagging interface for bindings during the resolution process |
Constants | Multi purpose constants that support the POC framework |
Lookup | Constructs an XML source document that represents an individual ATOM entry. |
LookupService | Service that allows to map between the URI to a resource and an ATOM feed that describes this resource, including its entry URL. |
PocURL | The PocURL is a URL that addresses a piece of content (POC). |
PortletContext | Extension of the COR Context for use in a JSR168 portlet. |
ResolutionService | Service that allows to resolve a URI to navigational state in the context of WebSphere Portal. |
Resolved | Identification of the result of the resolution process. |
ServletContext | Extension of the COR context for use in a servlet. |
Contains the main interfaces that extenders of the URI resolution infrastructure must implement.
Content providers need to provider a resolver implementation that resolves URIs and locates the target page and the target portlet window ID that contains a viewer. In addition there needs to be a viewer portlet implementation. Both pieces are decoupled and can reside in different bundles.
The viewer needs to be a portlet packaged in a WAR file. The implementation of
the portlet is arbitrary. In addition to fulfilling the portlet specification
the portlet.xml
needs to specific a special init-param
to link from the portlet to its resolver.
<init-param> <name>com.ibm.portal.resolver.ResolutionService</name> <value>%YOUR_UNIQUE_SERVICE_ID%</value> </init-param>
The parameter name com.ibm.portal.resolver.ResolutionService
is
predefined by the resolver infrastructure, the value references a valid location
service handler for a COR service that extends the com.ibm.portal.resolver.portlet
location type (defined again by the resolver infrastructure).
The actual service handler implementation may be implemented by any bundle,
however it is advised to include the handler in the same WAR file that also
contains the portlet. So the WAR file needs to contain a valid plugin.xml
in the META-INF
directory of the WAR file. This plugin has as a
minimum to define the extension.
<?xml version="1.0" encoding="UTF-8"?> <plugin provider-name="%YOUR_PROVIDER_NAME%" version="1.0.0" name="%YOUR_PLUGIN_NAME%" id="%YOUR_PLUGIN_ID%"> <extension point="com.ibm.content.operations.registry. locationServiceHandler"> <serviceHandler class="%YOUR_HANDLER_IMPLEMENTATION_CLASS%" locationTypeId="com.ibm.portal.resolver.portlet" id="% YOUR_UNIQUE_SERVICE_ID%"/> </extension> </plugin>
The implementation class of the viewer resolver needs to implement the com.ibm.portal.resolver.ResolutionService
interface. The
purpose of the implementation is to initialize the state with portlet specific
information that the portlet requires to get initialized. The URI that is passed
to the resolver is of the format portlet:<portletWindowID>:<pageID>:<pocURI>
,
so the portlet can use the portletWindowID
in conjunction with
the pocURI
and the state handling API in WebSphere Portal to modify the state.
In the simplest case the portlet is implemented as a JSR168 portlet and accepts
the pocURI
as a JSR168 render parameter. For this case the
resolver can be implemented as follows:
/* * (non-Javadoc) * * @see com.ibm.portal.resolver.ResolutionService#resolve(com.ibm.portal.resolver. Resolved, * java.net.URI, java.util.Set, java.util.Map, * com.ibm.portal.resolver.ResolutionContext) */ public void resolve(final Resolved res, final URI uri, final Set acceptedBindings, final Map params, final Context ctx) throws ResolutionException, StateException { // lookup the required services first final Identification idSvc = services.getIdentification(ctx); final StateManagerService stateSvc = services.getStateManager(ctx); // decode the URI final PortletURI portletURI = new PortletURI(uri, idSvc); final ObjectID portletWindowID = portletURI.getPortletWindowID(); final URI pocURI = portletURI.getPocURI(); /* * This is the critical piece of code that knows how to pass parameters * to the target portlet. There is a tight coupling between this code * and the code in the portlet that reads the parameters. That's why the * ViewerResolver and the portlet code should reside in the same bundle * (WAR file) and the extra indirection is required. * * This implementation makes use of a JSR168 render parameter to * communicate state between the resolver and the portlet. As both the * portlet code and the resolver have access to the same java classes, * they can use a java constant for the parameter name. This in turn * makes long parameter names unnecessary (the parameter is already * scoped to the portlet instance by the state handling API). Short * parameter names in turn help to reduce the URL lengths. */ final PortletAccessorFactory portletFct = (PortletAccessorFactory) stateSvc .getAccessorFactory(PortletAccessorFactory.class); final PortletAccessorController portletCtrl = portletFct .getPortletAccessorController(portletWndId, stateCtrl); try { // current set of render parameters that can be modified final Map renderParams = portletCtrl.getParameters(); /* * It's critical to remember that the values for the render * parameter map are of type String[] per JSR168 spec (not just * plain strings!). */ renderParams.put(PARAM_URI, new String[] { pocURI.toString() }); } finally { // done portletCtrl.dispose(); } }
The constants PARAM_URI
that appears in the code represents
shared, internal knowledge between this resolver and the portlet implementation.
As both are implemented in the same bundle however, this dependency is not
fragile.
The portlet needs to be aware of the way it receives its initialization
parameters. In the simplest case the portlet is a JSR168 portlet and uses a
JSR168 render parameter to receive the pocURI
. In this case the
portlet can just read the parameter via the standard JSR168 APIs and only needs
to share the parameter name with the resolver (ideally via a java constant that
represents a very short parameter name).
<%@ page import="com.ibm.wps.resolver.viewer.ViewerConstants" language="java" pageEncoding="UTF-8"%> <div class="portlet-section-body"> <p>The portlet displays the render parameter <b>PARAM_URI</b> that has been initialized by the <b>ViewerResolver</b>. </p> <p> URI = <%= request.getParameter(ViewerConstants.PARAM_URI) %> </p> </div>
The portlet does not need to implement any action semantics in this example, because the render parameter is just navigational state that can be transfered in render requests. A real portlet with more logic would now generate markup containing (render-)links that modify or enhance these render parameters.
In general providers need to implement the com.ibm.portal.resolver.ResolutionService
interface by defining a service handler in the Content Operations Registry
infrastructure
with the ID com.ibm.portal.resolver.ResolutionService
. This
service handler needs to be associated (via the locationTypeId
with a content location factory that in turn is associated with a URI scheme.
The responsibility for the resolver implementation is to modify the navigational state such that it points to a page with a portlet that contains properly initialized initialization parameters.
The CAI infrastructure greatly supports content providers in correctly
implementing a resolver by maintaining mappings from business components to page/portlets.
The CAI infrastructure provides a resolver that is associated width the cai
URI scheme and that handles already many details of the state manipulation. CAI
URIs have the format cai:<pocURI>
. The CAI resolver has no
dependency on the actual provider of the pocURI
other than it
needs to do a callback to pocURI specific resolution service to locate the page
and portletWindowID based on the POC ID. The CAI resolver will then use these
IDs to do the appropriate state manipulations automatically.
In order to do the page resolution CAI looks via the COR
infrastructure for a service handler for the pocURI
with the
service id com.ibm.portal.resolver.cai.BusinessComponentService
.
The resulting service needs to implement the com.ibm.portal.resolver.cai.BusinessComponentService
interface.
For most CAI based providers it will be simpler to determine the hosting
business component ID than to find the target page and target portlet. So
providers can implement he BusinessComponentService
interface by
first doing a lookup for the hosting business component ID and then dispatching
to CAI's implementation of the BusinessComponentService
interface
that finds page and portlet based on the business component ID.
In this prototype code the business component lookup does not use any CAI APIs,
yet. Instead it uses the pocURI
scheme and just searches all
deployed pages and all portlet windows until it finds a portlet window that has
a title that matches the pocURI
scheme. For the example
implementation this means that in order to find the correct viewer portlet for
the URI SampleProvider:test
there needs to be a portlet installed
on a page with a portlet title of SampleProvider
.
This is how a simple business component lookup can be implemented
public DomainObjectRef resolve(final URI uri, final Map params, final Context ctx) throws ResolutionException { LOGGER.info("finding the page: uri = " + uri); try { /* * just chose a dummy type/id for the business component in this demo. * * This is the line of code that real components needs to override. These * components need to do a lookup based on the uri to the type and the * URI of a business component. Then they can use the same * mechanism to dispatch to the business component lookup * */ final URI bcURI = BusinessComponentURI.newInstance("dummyType", " dummyID", uri); LOGGER.info("dispatching: bcURI = " + bcURI); // dispatch to the resolver for the BC URI final ContentIntrospector ci = ctx.getContentIntrospector(); final ServiceHandler handler = ci.getServiceHandler(bcURI, BusinessComponentService.class.getName(), null, ctx); LOGGER.info("handler = " + handler); if (handler != null) { // get the actual operation final BusinessComponentService bizSvc = (BusinessComponentService) handler. getService(bcURI, ctx); LOGGER.info("bizSvc = " + bizSvc); // dispatch return bizSvc.resolve(bcURI, params, ctx); } else { // TODO throw the correct exception throw new ServiceNotFoundException("service not found"); } } catch (ResolutionException ex) { throw ex; } catch (Exception ex) { // TODO throw the correct exception throw new ResolutionProxyException(null, ex); } }
In addition there needs to be a plugin.xml
that is bundled with
the lookup class that registers the business component lookup with the
appropriate URI scheme (see the COR documentation for details).
<?xml version="1.0" encoding="UTF-8"?> <plugin provider-name="%YOUR_PROVIDER_NAME%" version="1.0.0" name="%YOUR_PLUGIN_NAME%" id="%YOUR_PLUGIN_ID%"> <extension point="com.ibm.content.operations.registry. locationTypeContribution"> <contentLocationType title="%YOUR_TITLE%" match.uri.scheme="%YOUR_URI_SCHEME%" class="%YOUR_CONTENT_LOCATION_FACTORY%" id="%YOUR_LOCATION_TYPE_ID%"/> </extension> <extension point="com.ibm.content.operations.registry. locationServiceHandler"> <serviceHandler class="%YOUR_HANDLER_IMPLEMENTATION_CLASS%" locationTypeId="%YOUR_LOCATION_TYPE_ID%" id="com.ibm.portal.resolver.cai.BusinessComponentService"/> </extension> </plugin>
Writing a browser portlet is fortunately very simple. The portlet needs to be a standard conformant portlet that can use a resolver specific tag library to easily generate its URLs.
In this prototype the portlet needs to ship the tag library on its own, but it can reference the tag implementation in the basic resolver infrastructure.
<tag> <name>url</name> <tag-class>com.ibm.wps.resolver.tags.ResolvedUrlTag</tag-class> <body-content>JSP</body-content> <attribute> <name>uri</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> </tag>
Currently the tag only supports the generation of late binding URLs.
The portlet would then just use this tag to create links to the pocURI
s.
<%@ taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v60/ resolver/browser" prefix="res" %> <%@ page language="java" pageEncoding="UTF-8"%> <div class="portlet-section-body"> <p> Demo of late binding to the following URLs </p> <ul> <li><a href='<res:url uri='cai:SampleProvider:test1'/>'> SampleProvider:test1</a></li> <li><a href='<res:url uri='cai:SampleProvider:test2'/>'> SampleProvider:test2</a></li> </ul> </div>
http://www.ibm.com/xmlns/prod/websphere/portal/v6.0.1/resolver
.
Tag | resolvedURL | |
required | uri | URI of the piece of content to be addressed |
optional | allowRelativeURL | If set to "true", the generation of relative URLs is explicitly allowed (though not enforced). If set to "false", no relative URLs will be generated. If missing, the server default setting for the generation of relative URLs will be used. |
optional | keepNavigationalState | If set to "true" the URLs contain the current navigational state. If set to "false" the URLs will be generated without navigational state. If missing the URLs will contain navigational state if possible. |
optional | mode | Specification of the way the system should interact with the URI. Default modes are VIEW ,
DOWNLOAD and LOOKUP . |
optional | escapeXml | If set to "true" the URLs will be markup escaped. Per default this value is set to "true". |
optional | protected | If set to "true" the URLs will point to the protection version of the target servlet, if set to "false" they point to the unprotected version, if missing the URLs point to the same flavor of the target servlet as the current request. |
optional | secure | If set to "true" the URLs will use HTTPS as the protocol, if set to "false" they use HTTP, if missing the URLs point to the same flavor of the target servlet as the current request. |
Tag | urlParam | To be used in the body of the resolvedURL tag. |
required | name | Name of the parameter to attach to the URL. If there was already a parameter with the given name, the values will be merged. |
required | value | Value of the parameter to attach to the URL. If the value is of type Object[] the array entries will be converted to String and appended to the list of parameters for the given key. In all other cases the value is converted to a String and appended. |
| |||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |