Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
siarhei_pisarenka3
Active Contributor
0 Kudos

The blog is a continuation of my previous blog: HTTP Cookies in Portal WebDynpro application, [part1]: Overview. Here I'll provide more or less generic solution for reading/writing Cookies...

I've realized the approach in one Portal based WebDynpro application which used Cookies for storing user preferences on a client side. It allows to overcome limitations and risks of the two approaches shown previously.

Approach 3: Using additional hidden iView with client JavaScript

The idea of the method is based on a small JavaScript code which is responsible for reading/writing Cookies. The JavaScript is located inside hidden Portal iView which is transferred to a client browser while user is working with WebDynpro application. The JavaScript itself is very simple and safe. The main challenge here is to organize a communication between the hidden iView with JavaScript and the WebDynpro iView with your application.

The communication between the two Portal iViews can be organized with help of Portal client-side eventing realized by Enterprise Portal Client Framework (EPCF) which is available for both pending iView types. I introduced three events that helped the WebDynpro application to read/write Cookies via the JavaScript helper:

  1. getCookie(cookieName). Fired by WebDynpro application in order to request Cookie. Received by JavaScript and instructs it to read Cookie from a client.

  2. readCookie(cookieName, cookieValue). Fired by JavaScript in order to notify WebDynpro application about read Cookie. Transfers Cookie to WebDynpro application.

  3. storeCookie(cookieName, cookieValue). Fired by WebDynpro application in order to store Cookie. Received by JavaScript and instructs it to store Cookie on a client.

The following diagram below shows a sequence of steps how the application reads Cookies from a client. It happens initially while just authenticated user is opening the application. As JavaScript can only receive a Portal event after a Portal page has been completely transferred to a client, Cookie comes to a WebDynpro application within a second request to the server initiated by EPCF. During the second request the WebDynpro application receives Cookie if any and updates its UI with the personalized data.


 
   Two phases of Cookie reading initiated by WebDynpro application

 

When the WD application is about to store some personal data in Cookie it sends the corresponding Portal event charged with Cookie name/value. The JavaScript handles the event on a client. The process is illustrated below.


 
   How WebDynpro application stores Cookie

 

Now let me provide more details as well as the source code of the solution...

WebDynpro application - Cookie consumer

WebDynpro component controller (custom controller) is responsible for firing EPCF events and for generic usage of the Cookie in the application. Input points for the rest parts of the application are two methods:

  1. Invoke getReceivedCookie(...) to initiate event flow of Cookie reading. Or if the Cookie is already received the method will immediately return the Cookie value.
  2. Invoke storeCookie(...) to initiate event flow for Cookie writing.
/** Initiate Cookie writing.*/
private void storeCookie(String key, String value) {
   key = getUserCookieKey(key);
   WDPortalEventing.fire("urn:com.epam.xapp.ep:storeCookie", key, value);
}

/** Initiate Cookie reading.*/   
private String readCookie(String key) {
   key = getUserCookieKey(key);
   WDPortalEventing.fire("urn:com.epam.xapp.ep:getCookie", key, null);
   isCookieRead = true;
   return null;
}

private static final String COOKIE_NAME = "com.epam.xapp.UserPref";

//@@begin javadoc:getCookieKey()
/** Get Cookie name.*/
//@@end
public String getCookieKey( )
{
  //@@begin getCookieKey()
   return getUserCookieKey(COOKIE_NAME);
  //@@end
}

//@@begin javadoc:receiveCookie()
/** Receive Cookie and store it internally.*/
//@@end
public void receiveCookie( String key, String value )
{
  //@@begin receiveCookie()
   if (key.startsWith(COOKIE_NAME)) {
      receivedCookie = value;
      // invalidate context dependent on the cookie...
      // refresh UI elements dependent on the cookie...
   }
  //@@end
}

private String receivedCookie;
private boolean isCookieRead = false;

/** Get received Cookie or initiate Cookie reading.*/
private String getReceivedCookie(String key) {
   if (isCookieRead) {
      return receivedCookie;
   } else {
      return readCookie(key);
   }
}

private String getUserCookieKey(String baseKey) {
   return baseKey + "_" + WDClientUser.getLoggedInClientUser().getSAPUser().getUniqueName();
}

 

WebDynpro view controller is responsible only for subscription to EPCF events, simply because we cannot do this physically in the component controller (custom controller):

//@@begin javadoc:wdDoInit()
/** Hook method called to initialize controller. */
//@@end
public void wdDoInit()
{
  //@@begin wdDoInit()
   this.cookieKey2Listen = wdThis.wdGetController().getCookieKey();
   WDPortalEventing.subscribe(
      EVENT_NS_READ_COOKIE,
      cookieKey2Listen,
      wdThis.wdGetReadCookieAction());
  //@@end
}

//@@begin javadoc:wdDoExit()
/** Hook method called to clean up controller. */
//@@end
public void wdDoExit()
{
  //@@begin wdDoExit()
   WDPortalEventing.unsubscribe(
      EVENT_NS_READ_COOKIE,
      cookieKey2Listen,
      wdThis.wdGetReadCookieAction());
  //@@end
}

//@@begin javadoc:onActionReadCookie(ServerEvent)
/** Declared validating event handler. */
//@@end
public void onActionReadCookie(IWDCustomEvent wdEvent, String nameSpace, String name, String dataObject)
{
  //@@begin onActionReadCookie(ServerEvent)
   wdThis.wdGetController().receiveCookie(name, dataObject);
  //@@end
}

private static final String EVENT_NS_READ_COOKIE = "urn:com.epam.xapp.ep:readCookie";

private String cookieKey2Listen;

 

EP component with JavaScript

You have to create a new Portal application or reuse an existing one in order to store small JavaScript that will be deployed on the Portal. The script contains functions for reading/writing HTTP Cookies and also sends/receives Portal EPCF events mentioned above. Variable (constant) EVENTS_NS means a namespace prefix for the event names.

cookie_helper.js

var EVENTS_NS = "urn:com.epam.xapp.ep";

function storeCookie(eventObj) {
   var exdate = new Date();
   exdate.setFullYear(exdate.getFullYear() + 1);
   document.cookie=eventObj.eventName + "=" + escape(eventObj.dataObject) + ";expires=" + exdate.toGMTString();
}

function sendCookie(eventObj) {
   key = eventObj.eventName;
   cookie = readCookie(key);
   if (cookie != null) {
      parent.EPCM.raiseEvent(EVENTS_NS + ":readCookie", key, cookie);
   }
}

function readCookie(key) {
   if (document.cookie.length > 0) {
      c_start = document.cookie.indexOf(key + "=");
      if (c_start != -1) {
         c_start = c_start + key.length + 1;
         c_end = document.cookie.indexOf(";", c_start);
         if (c_end == -1) {
            c_end = document.cookie.length;
         }
         return unescape(document.cookie.substring(c_start, c_end));
      }
   }
   return null;
}

function subscribeEvents() {
   parent.EPCM.subscribeEvent(EVENTS_NS + ":storeCookie", "*", storeCookie);
   parent.EPCM.subscribeEvent(EVENTS_NS + ":getCookie", "*", sendCookie);
}

 

The following small HTML just loads the script and subscribes it to EPCF events getCookie and storeCookie.

cookie_helper.html


  
     
  
  

 

image
 
   EP Application project

 

Hidden URL iView

You have to create iView of type URL and point it to the HTML content that you put in the EP application. Set the following iView properties:

  • URL=/irj/portalapps/xapp.ep/scripts/cookie_helper.html
  • URL Parameters.Request Method=GET

Properties that make the iView invisible:

  • Height Type=FIXED
  • Fixed Height (Pixels)=0
  • Show Tray=No
  • Initial State of Navigation Panel=Always Close
  • Invisible in Navigation Areas=Yes

After you prepared the URL iView you need to insert it in the WebDynpro Portal page along with the WebDynpro iView. However, if you put the invisible iView directly on a layout of the page the Portal will reload it during each request/response cycle to a server. This behaviour results from the WebDynpro Page Builder's nature - every iView put on a WebDynpro Page will be reloaded during each outgoing request to a server.

Instead of a page layout I inserted the invisible iView into the list of Portal dynamic navigation of the page. As a result of this the iView with JavaScript is loaded within the WebDynpro page itself and is not reloaded while user is working with the WebDynpro iView:

image
 
   Portal content: WD iView, Page and JS iView connected as Dynamic Navigation iView

 

Summary

The implemented scheme for Cookie reading/writing uses only a legal API available for WebDynpro application within the Portal.

Moreover, it provides a solution even for the case when NW04s version of WebDynpro iView/Page are used (WebDynpro Page Builder). In the case pure WebDynpro API as well as internal classes (TaskBinder, HTTPServletRequest, ...) do not help at all.

8 Comments