Skip to Content

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.

image
 
   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.

image
 
   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.

To report this post you need to login first.

8 Comments

You must be Logged on to comment or reply to a post.

  1. Kelly Ferguson
    WDScopeUtil.put(WDScopeType.CLIENTSESSION_SCOPE, “KEY”, “VALUE”);

    and

    String value = WDScopeUtil.get(WDScopeType.CLIENTSESSION_SCOPE, sessionkey);

    (0) 
    1. Siarhei Pisarenka Post author
      Hi Kelly
      Thanks for your interest…

      I also like the WDScopeUtil service and try to use the service whenever it’s possible. However, it has life-time restriction in the sense that it’s not a persistent storage. The data will not be survived between two different user sessions. In other words, the scope will be cleared as soon as user has logged out.

      At the same time HTTP Cookies can be persistent which makes it’s possible to use them in the task of personalization – let say for storing some user preferences. For example, I set Cookies’ life-time to one year in the blog’s source code.

      Regards, Siarhei

      (0) 
    1. Siarhei Pisarenka Post author
      Hi Daniel
      Thanks for your interest…

      Do you mean the code lines based on TaskBinder? The method do not work at all under the Portal. Servlet session in the case is almost empty, because this is an artificial request. No cookies inside…

      Regards, Siarhei

      (0) 
      1. Daniel Ruiz
        oh, it does work.. I have EP7 here, NW7.01.05 and it runs perfectly – you can use any internal interface, wdp itself needs this data for it’s own usage so you will always have it somehow. basically it’s just not exposed.. – I don’t have the serverimpl jar here, but I don’t think you will ever have problems with that.

        I would use the same approach you did in order to run dhtml in wdp frame, but I never did it since I think it’s waste of time.. still, it’s quite a constructive blog, one of the best I’ve seen so far in SDN.. and I quite like your approach of caching the dictionary as well, I just don’t do it since I think it’s a wdp flaw and I will just live with it until they improve it.. =)

        (0) 
        1. Siarhei Pisarenka Post author
          Hi Daniel

          Hm.. In fact there are two iView types available for WebDynpro applications in Portal: old WebDynpro iView based on SAP WebDynpro template (NW04) and new WebDynpro iView based on WebDynpro page builder (NW04s). I tested the internal servlet classes in my application with both iView types before posting the blog.

          For NW04 WebDynpro iView they work perfectly as you said.

          For NW04s WebDynpro iView they do not, because invocation TaskBinder.getCurrentTask().getProtocolAdapter().getResponseObjectInternal().getProtocolResponse() always returns NULL. I find this quite logical because in the case target WebDynpro application is invoked on a server side by a proxy – WebDynpro proxy page builder. The proxy uses internal WebDynpro framework classes to invoke the target application. That’s why I think the servlet response is not available for the application.

          In other words, the difference between the iView types is in the following. NW04 WebDynpro iView invokes target application by URL (isolated mode). NW04s WebDynpro iView invokes the target application via proxy with help of internal framework means (embedded mode).

          So I think that you use NW04 WebDynpro iViews in your application. Please check this and let me know.

          BR, Siarhei

          (0) 
          1. Daniel Ruiz
            we are currently under NW7.01.05 and we use NW04s iViews from what I know.

            WDProtocolAdapter singleton uses the same object you said before. So you are saying inside your WDPApp you will have will get a null instead of some implementation for IWDResponse?

            I will test on NWCE as well.. but I think the framework will carry both objects (servlet request and response) for internal use, it will just block access in the APIs. All you need is to read the source and see where it is and get it.

            Regards,
            Daniel

            (0) 

Leave a Reply