Showing posts with label wsrp. Show all posts
Showing posts with label wsrp. Show all posts

WSRP - Open a JSP/Servlet in dialog box from portlet

In the Open a JSP/Servlet in dialog box from portlet entry i talked about how you can open a JSP in dialog box from portlet. I wanted to see if that code will work in WSRP and how it will work so i tried consuming the sample portlet as WSRP portlet and tried clicking on the dialog box and it worked also it was able to pass query parameters.

This is the code in index.jsp that i use for creating URL pointing to popup.jsp

<input type="button" onclick="openPopup('<%=renderResponse.encodeURL(
renderRequest.getContextPath() + "/popup.jsp?userName=poup.jsp") %>')" value="Popup.jsp" />


When i look the HTML generated by this code in the local version of portlet this is what i see

<input type="button" value="Popup.jsp" onclick="openPopup('
/wpcert/PA_ServletPopup/popup.jsp?userName=poup.jsp')">


In my local the portal the ServletPopup is installed at /wpcert/PA_ServletPopup context so that's what get appended to the URL and the url goes unchanged in renderResponse.encodeURL()

THis markup is generated when i see same portlet in the WSRP world

<input type="button" value="Popup.jsp" onclick="openPopup(
'/wps/WsrpProxyPortlet/ResourceProxy/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48dT48Yj5odHRwOi8vbG9jYWxob3N0OjEwMDQwPC9iPjxwP
jxuPndzcnAtc2VjdXJlVVJMPC9uPjx2PmZhbHNlPC92PjwvcD48cD48bj53c3JwLXVybFR5cGU8L24-PHY-cmVzb3VyY2U8L3Y-
PC9wPjxwPjxuPnA8L24-PHY-MTJfVlZJTE1LRzEwODVGOTBJUzQ0SlJRNTMwMDc8L3Y-PC9wPjxwPjxuPmc8L24-
PHY-MV9WVklMTUtHMTAwTjA4MElBMEc3NTdDMDAwMDwvdj48L3A-PC91Pg!!/4UXoYMjvvzfhLvelKL9fiEIl5fs!/wpcert
/PA_ServletPopup/popup.jsp?userName=poup.jsp')">


As you can see the renderResponse.encodeURL() method generates a big string starting with /wps/WsrpProxyPortlet/ResourceProxy in the URL, so when you request a JSP the request will first go the consumer portal, there the ResourceProxy portlet will tunnel the request to producer and return the results back

Collecting performance data for WSRP producer web service

I wanted to see if there is a way to get performance data related to WSRP Producer portlet one way is to use the Portlet Level PMI on the producer portlet. And there is one more thing that we can do which is to collect the PMI information for WSRP related web service

You will have to follow these steps to collect the WSRP web service, PMI related data

  • First enable the PMI metrics collection for all the modules

  • Then inside the Performance Viewer -< Current Activity page go to Web Services -< wps.war related services and select WSRPBaseService_V1 and WSRPBaseService_V2 like this



  • Then once both the services are selected click on View MOdules and hit few pages with WSRP portlets on it. Now you should start seeing the data related to all the WSRP web service calls your server is getting and the time it is taking to service the calls like this

    In my case the WSRP producer service got 5 calls and it took 294 ms on average to respond to the calls

Passing Complex Events in WSRP

In the Passing complex objects in portlet events entry i talked about how you can pass complex/custom objects as event payload.

You can download the sample code for this project from here

  1. Contact

  2. EventSource

  3. EventTarget



But you will have to make some additional changes to your portlet if you want to pass these object between portlets installed on different severs using WSRP. In case when objects are hosted on different server then portal server will serialize the complex object using JAXB and then send it to consumer. I changed my existing Contact object like this to make it work in WSRP


package com.webspherenotes.portlet.events;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Contact implements Serializable{
private static final long serialVersionUID = -1637774642655976822L;
private String firstName;
private String lastName;
private String email;
public Contact(){
}
public Contact(String firstName, String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}


I had to annotate the Contact object by adding @XmlRootElement this. You will have to copy the contact.jar in shared library of both producer and consumer. Also make sure that Contact class has no-arg constructor.


When my Contact.java class did not had constructor i was getting error like this.


[5/19/10 9:48:13:456 PDT] 00000071 PropertyDispa E com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl dispatchSourceEvents EJPKB1002E: The propertybroker encountered an error while dispatching the source event {http://wpcertification.blogspot.com}hello from portlet window Control@1598316356 (SourcePortlet, [ObjectIDImpl '7_VVILMKG1009800I2DO701500G7', NAVIGATION_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00240480140D1F100A00F0], [ObjectIDImpl '6_VVILMKG10G4K30I2A4E1UM2007', CONTENT_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00123A80148AB8E0AD00E0], 100 with value com.webspherenotes.portlet.events.Contact@212c212c.
com.ibm.portal.propertybroker.exceptions.CommunicationTargetDispatchException: EJPKB1001E: An Error occurred while dispatching to the communication target

process.{http://wpcertification.blogspot.com}hello
11_VVILMKG1009800I2DO701500O3

{http://wpcertification.blogspot.com}hello
com.ibm.wps.pe.pc.util.JAXBEventPayloadWrapper
{http://wpcertification.blogspot.com}hello


for window Control@1605918648 (TargetPortlet, [ObjectIDImpl '7_VVILMKG1009800I2DO70150040', NAVIGATION_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00240480140D1F100A0004], [ObjectIDImpl '6_VVILMKG10G4K30I2A4E1UM2007', CONTENT_NODE, VP: 0, [Domain: rel], DB: 0000-FFCB6A290C00123A80148AB8E0AD00E0], 200.
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.buildTargetJsrEventInformation(JsrEventActionDispatcherPluginImpl.java:263)
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.dispatchCommunicationTarget(JsrEventActionDispatcherPluginImpl.java:106)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchCommunicationTarget(PropertyDispatcherImpl.java:658)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchCommunicationTargets(PropertyDispatcherImpl.java:611)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchPropertyValues(PropertyDispatcherImpl.java:256)
at com.ibm.wps.propertybroker.dispatch.PropertyDispatcherImpl.dispatchSourceEvent(PropertyDispatcherImpl.java:138)
at com.ibm.wps.pe.pc.waspc.services.information.WaspcInformationProviderImpl$PortletEventProviderImpl.add(WaspcInformationProviderImpl.java:373)
at com.ibm.ws.portletcontainer.PortletContainerImpl.publishEventsToEventProvider(PortletContainerImpl.java:431)
at com.ibm.ws.portletcontainer.PortletContainerImpl.doAction(PortletContainerImpl.java:215)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:78)
at com.ibm.ws.portletcontainer.ext.ExtCollaborator.doAction(ExtCollaborator.java:55)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:65)
at com.ibm.ws.portletcontainer.cache.CacheInvokerCollaborator.doAction(CacheInvokerCollaborator.java:76)
at com.ibm.ws.portletcontainer.PortletContainerInvokerCollaboratorChainImpl.doCollaborator(PortletContainerInvokerCollaboratorChainImpl.java:65)
at com.ibm.ws.portletcontainer.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:152)
at com.ibm.ws.portletcontainer.pcinvoker.PortletInvokerImpl$1.run(PortletInvokerImpl.java:59)
at java.security.AccessController.doPrivileged(AccessController.java:246)
at com.ibm.ws.portletcontainer.pcinvoker.PortletInvokerImpl.invokeProcessAction(PortletInvokerImpl.java:55)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl$3.invoke(PortletInvokerImpl.java:115)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:175)
at com.ibm.wps.pe.pc.waspc.core.impl.PortletInvokerImpl.invokeProcessAction(PortletInvokerImpl.java:113)
at com.ibm.wps.pe.pc.waspc.event.ActionEvent.execute(ActionEvent.java:78)
at com.ibm.wps.pe.pc.waspc.event.EventQueueManager.processEventLoop(EventQueueManager.java:112)
at com.ibm.wps.pe.pc.waspc.PortletContainerImpl.performEvents(PortletContainerImpl.java:206)
at com.ibm.wps.pe.pc.PortletContainerImpl.performEvents(PortletContainerImpl.java:298)
at com.ibm.wps.engine.phases.WPActionPhase.processPortlets(WPActionPhase.java:2644)
at com.ibm.wps.engine.phases.WPActionPhase.execute(WPActionPhase.java:668)
at com.ibm.wps.state.phases.AbstractActionPhase.next(AbstractActionPhase.java:130)
at com.ibm.wps.engine.Servlet.callPortal(Servlet.java:855)
at com.ibm.wps.engine.Servlet.doGet(Servlet.java:617)
at com.ibm.wps.engine.Servlet.doPost(Servlet.java:888)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
at com.ibm.wps.engine.Servlet.doFilter(Servlet.java:1257)
at com.ibm.wps.resolver.servlet.ContentHandlerCleanup.doFilter(ContentHandlerCleanup.java:648)
at com.ibm.wps.resolver.servlet.AbstractFilter.doFilter(AbstractFilter.java:93)
at com.ibm.wps.engine.Servlet.service(Servlet.java:1248)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1146)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1087)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:145)
at com.ibm.wps.engine.ExtendedLocaleFilter.doFilter(ExtendedLocaleFilter.java:113)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.resolver.friendly.servlet.FriendlySelectionFilter.doFilter(FriendlySelectionFilter.java:191)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.mappingurl.impl.URLAnalyzer.doFilter(URLAnalyzer.java:352)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.engine.VirtualPortalFilter.doFilter(VirtualPortalFilter.java:88)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.wps.state.filter.StateCleanup.doFilter(StateCleanup.java:94)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:837)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:680)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:588)
at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:524)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3517)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:269)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:818)
at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1478)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:125)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture$1.run(AsyncChannelFuture.java:205)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.webspherenotes.portlet.events.Contact does not have a no-arg default constructor.
this problem is related to the following location:
at com.webspherenotes.portlet.events.Contact

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:389)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:236)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:76)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:381)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
at com.ibm.wsspi.portletcontainer.util.EventFactory.serializeJAXB(EventFactory.java:285)
at com.ibm.wsspi.portletcontainer.util.EventFactory.serializeJAXB(EventFactory.java:166)
at com.ibm.wps.propertybroker.standard.filter.JsrEventActionDispatcherPluginImpl.buildTargetJsrEventInformation(JsrEventActionDispatcherPluginImpl.java:226)
... 72 more

The PortletResponse.encodeUrl() in WSRP portlet

In the How the PortletResponse.encodeUrl() method works method i mentioned that the PortletResponse.encodeUrl() method does not have any effect on the URL generated.But you must use it if you want your static resource serving to work in the WSRP Portlet.

I do have this sample ResourceServing.war portlet, which is very simple only thing that the Portlet does is forward control to the resource.jsp. And the resource.jsp includes a sampleimg.gif file in the markup like this


<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model" prefix="portlet-client-model"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portletx"%>

<portlet:defineObjects />
<b><img src='<%= renderResponse.encodeURL("renderRequest.getContextPath() + "/sampleimg.gif") %>' /></b>


As i mentioned in the previous post the renderRequest.getContextPath() returns the context root where your portlet application is installed. Which is sufficient to get URL to resource. But in case of WSRP that is not sufficient. In case of WSRP the request for /sampleimg.gif should first go to the consumer portal which will do the tunneling to get the request from the producer portal (If your producer portal is directly available to the user then you can also create hard-coded URL pointing to the producer portlet in the markup but its not recommended practice)

In case when the ResourceServing portlet is served through WSRP the above JSP will generate this HTML Markup

<img src="/wps/WsrpProxyPortlet/ResourceProxy/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48dT48Yj5odHRwOi8vbG9jYWxob3N0OjEwMDQwPC9iPjxwPjxuPndzcnAtc2VjdXJlVVJMPC9uPjx2PmZhbHNlPC92PjwvcD48cD48bj53c3JwLXVybFR5cGU8L24-PHY-cmVzb3VyY2U8L3Y-PC9wPjxwPjxuPnA8L24-PHY-MTJfVlZJTE1LRzEwODVGOTBJUzQ0SlJRNTMwMDc8L3Y-PC9wPjxwPjxuPmc8L24-PHY-MV9WVklMTUtHMTA4NUY5MElTNDRKUlE1MzAwMDwvdj48L3A-PC91Pg!!/SjPAEvQqcAICDYyb-sViNKWZad0!/wps/PA_ResourceServing/sampleimg.gif">


As you can see the image URL is pointing to the consumer portal server at /wps/WsrpProxyPortlet/ResourceProxy then there is a big token with session information,.. And at the end of the URL is the actual URL of the sampleimg.gif on the producer portlet.

I thought i should take a closer look at /wps/WsrpProxyPortlet/ResourceProxy URL. THe /wps/WsrpProxyPortlet points to the PA_PortalWSRPProxy.ear file. The application.xml for that file is like this

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
<application id="Application_ID">
<display-name>wsrpproxy_war</display-name>
<module>
<web>
<web-uri>wsrpproxy.war</web-uri>
<context-root>/wps/WsrpProxyPortlet</context-root>
</web>
</module>
</application>


The PA_PortalWSRPProxy.ear has wsrpproxy.war file which includes the com.ibm.wps.wsrp.consumer.std.impl.ProxyPortlet portlet, which is proxy portlet for consuming WSRP portlet. WHen i looked at the web.xml for that portlet it has a com.ibm.wps.wsrp.consumer.std.impl.ResourceProxy Servlet which is supposed to handle the /ResourceProxy URL.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="com.ibm.wps.wsrp.proxyportletapp">
<display-name>PortalWSRPProxyPortlet</display-name>
<servlet>
<servlet-name>resourceproxy</servlet-name>
<servlet-class>com.ibm.wps.wsrp.consumer.std.impl.ResourceProxy</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resourceproxy</servlet-name>
<url-pattern>/ResourceProxy/*</url-pattern>
</servlet-mapping>
</web-app>



In case of WSRP portlet, when it comes to serving a static request, it will first go to the the ResourceProxy servlet on the consumer portal and then ResourceProxy servlet will forward it to the producer portal for getting response and then return that response to the browser

Security Considerations for WSRP Service

When you use WSRP with your portal, you can configure security and provide authentication by using different authentication mechanisms.
You can choose between using Web services security (WS-Security) or Secure Socket Layer (SSL):

  • Authentication of the end user by using WS-Security (Web services security). For example, this can be by using Lightweight Third-Party Authentication (LTPA) token forwarding. In this case the Consumer portal passes requests from individual users on to the Producer portal under separate user IDs.
    Note: With the portal you can use all security tokens that IBM® WebSphere® Application Server supports. For most tokens the Consumer and Producer portals need to share the same user registry, for example, LTPA.

  • Authentication of the Consumer portal by using Secure Socket Layer Client Certificate Authentication: In this case the Consumer portal channels all requests by its users under the same preset shared user ID and passes them on to the Producer portal. For this option the Consumer and Producer portal can have shared or separate user registries.



When you configure security between your WSRP portals by one of these options, you also need to configure Portal Access Control and assign access rights for the Consumer portal users on the Producer portal. If you do not use either of these two authentication methods, the Producer portal assumes the anonymous user.
Assigning access rights: The Producer needs to assign access rights on the Producer portal based on the authentication information as follows:


  • If you use WS-Security, assign access rights on the Producer portal to the actual Consumer portal users.

  • If you use SSL client certificate authentication, assign access rights to the shared user ID that the Consumer uses and that is specified in the client certificate.

  • If you use none of these two authentication methods, assign access rights to the anonymous user. This is necessary because the Producer portal assumes the anonymous user, if no authentication is performed.

WSRP markup caching

The WSRP implementation uses a expiry-based markup caching for remote portlet. The way it works is consumer caches remote portlet content in the dynamic fragment cache and returns that to client instead of making new request to producer

In order for the caching to work following conditions must be met

  • The producer portlet must be developed using Standard Portlet API. The Portlet developed using IBM Portlet API wont return caching structure

  • The value of wsrp.caching.enabled property must be set to true in Configuration Service on both producer and consumer portal server. If it is set to true the producer portal will return cache-control structure in response. And the consumer portlet will cache markup in fragment based on the values of cache control in the response it received from the producer



The cache settings are defined in the portlet.xml, they set two things first what should be duration of cache and second is if this cache is user specific or can be shared in multiple users.