ICEfaces
  1. ICEfaces
  2. ICE-6117

Provide access to the HttpServletRequest and HttpServletResponse in a portlet application

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.2-EE-GA_P01
    • Fix Version/s: 1.8.2-EE-GA_P02
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      ICEfaces portlet
    • Affects:
      Documentation (User Guide, Ref. Guide, etc.), Sample App./Tutorial

      Description

      A customer running a portlet on WebLogic wants to use the Authentication.login() API provided by the container. The signature of that method, surprisingly, requires direct access to the HttpServletRequest and HttpServletResponse:

      http://download.oracle.com/docs/cd/E13155_01/wlp/docs103/javadoc/com/bea/p13n/security/Authentication.html

      In WebLogic, it appears that calling ExternalRequest.getRequest() in a portlet actually returns something that can be used as an HttpServletRequest. However, with ICEfaces, we provide a PortletExternalContext implementation that returns a PortletRequest of our own and there doesn't currently seem to be a way to drill down and get at the original request to pass into the login() method.

        Activity

        Hide
        Deryk Sinotte added a comment -

        I've checked in a fix that allows developers access to the original request and response instances provided by the portlet or servlet container. The way to access this feature works something like this:

        public HttpServletRequest getRequest(){
        FacesContext fc = FacesContext.getCurrentInstance();
        ExternalContext ec = fc.getExternalContext();

        if( ec instanceof BridgeExternalContext ){
        //The ICEfaces implementation of ExternalContext
        BridgeExternalContext bec = (BridgeExternalContext)ec;

        //BridgeExternalContext has two new methods:
        // getOriginalRequest()
        // getOriginalResponse()

        Object originalReq = bec.getOriginalRequest();

        //The implemenation returned here is container specific but will
        //be an instance of HttpServletRequest or PortletRequest
        //or, sometimes, both.

        if( originalReq instanceof HttpServletRequest)

        { return (HttpServletRequest)originalReq; }

        PortletRequest portletReq = (PortletRequest)originalReq;

        //Again, depending on the container, getting the HttpServletRequest
        //from the PortletRequest is likely to be specific to the platform.
        //For example on WebLogic Portal this could do the trick:
        portletReq = (PortletRequest) portletReq.getAttribute("javax.portlet.request");
        return (HttpServletRequest) portletReq.getAttribute("javax.servlet.request");
        }

        //If not ICEfaces, then just do it the plain JSF way.
        return (HttpServletRequest)ec.getRequest();
        }

        I tested this on Liferay as well as WebLogic Portal 1.0.3 and WebSphere Portal 6.1 and it appears to do the trick. I made an effort to ensure that the references to the original request and response are not retained in the requestMap when the BridgeExternalContext is released as this previously caused memory issues.

        Show
        Deryk Sinotte added a comment - I've checked in a fix that allows developers access to the original request and response instances provided by the portlet or servlet container. The way to access this feature works something like this: public HttpServletRequest getRequest(){ FacesContext fc = FacesContext.getCurrentInstance(); ExternalContext ec = fc.getExternalContext(); if( ec instanceof BridgeExternalContext ){ //The ICEfaces implementation of ExternalContext BridgeExternalContext bec = (BridgeExternalContext)ec; //BridgeExternalContext has two new methods: // getOriginalRequest() // getOriginalResponse() Object originalReq = bec.getOriginalRequest(); //The implemenation returned here is container specific but will //be an instance of HttpServletRequest or PortletRequest //or, sometimes, both. if( originalReq instanceof HttpServletRequest) { return (HttpServletRequest)originalReq; } PortletRequest portletReq = (PortletRequest)originalReq; //Again, depending on the container, getting the HttpServletRequest //from the PortletRequest is likely to be specific to the platform. //For example on WebLogic Portal this could do the trick: portletReq = (PortletRequest) portletReq.getAttribute("javax.portlet.request"); return (HttpServletRequest) portletReq.getAttribute("javax.servlet.request"); } //If not ICEfaces, then just do it the plain JSF way. return (HttpServletRequest)ec.getRequest(); } I tested this on Liferay as well as WebLogic Portal 1.0.3 and WebSphere Portal 6.1 and it appears to do the trick. I made an effort to ensure that the references to the original request and response are not retained in the requestMap when the BridgeExternalContext is released as this previously caused memory issues.
        Hide
        Deryk Sinotte added a comment -

        The getOriginalRequest and getOriginalResponse methods return generic Object instances on purpose because we can't really know the details of what the request is going to look like beforehand. We've made it broad like this on purpose because each container handles it differently. So when you use getOriginalRequest, you could get something that's a PortletRequest, an HttpServletRequest, or even both APIs at the same time. How to handle the result is currently in the app developer's hands and corresponds to the container/version that they are running on.

        In Liferay's case, it does indeed return a PortletRequest but the request does not implement the HttpServletRequest contract. It does provide a public method on the implementation to get at the raw HttpServletRequest. So you either have to use Liferay specific APIs or reflection to get at it. Here's a more detailed example for Liferay 6. If the original request is not an HttpServletRequest (which is perfectly valid) we can use reflection to get at the underlying HttpServletRequest through a Liferay API.

        public Object getOriginalRequest(){
        BridgeExternalContext bec = getBridgeExternalContext();
        if( bec == null )

        { System.out.println("TestBean.getOriginalRequest: not BridgeExternalContext "); return "[not a BridgeExternalContext]"; }

        Object originalReq = bec.getOriginalRequest();
        System.out.println("originalReq = " + originalReq);
        if( originalReq instanceof HttpServletRequest)

        { //If the original request is already an HttpServletRequest, we're done. This is how certain //portal containers implement their requests - as both PortletRequest and HttpServletRequests. System.out.println("TestBean.getOriginalRequest: original request is HttpServletRequest"); return originalReq; }

        //Liferay does it differently. Using reflection, we can try and get/invoke the specific Liferay method
        //that returns the raw HttpServletRequest.
        try {
        Method getHttpServletRequestMethod = originalReq.getClass().getMethod("getHttpServletRequest",null);
        Object httpRequest = getHttpServletRequestMethod.invoke(originalReq,null);
        if( httpRequest != null && httpRequest instanceof HttpServletRequest)

        { System.out.println("TestBean.getOriginalRequest: request from reflection = " + httpRequest); return (HttpServletRequest)httpRequest; }

        } catch (Exception e)

        { e.printStackTrace(); }

        //There may be other ways to get at the original HttpRequest depending on the portal vendor,
        //the version, what APIs they expose, etc. They would need to be investigated individually.
        return originalReq;
        }

        Show
        Deryk Sinotte added a comment - The getOriginalRequest and getOriginalResponse methods return generic Object instances on purpose because we can't really know the details of what the request is going to look like beforehand. We've made it broad like this on purpose because each container handles it differently. So when you use getOriginalRequest, you could get something that's a PortletRequest, an HttpServletRequest, or even both APIs at the same time. How to handle the result is currently in the app developer's hands and corresponds to the container/version that they are running on. In Liferay's case, it does indeed return a PortletRequest but the request does not implement the HttpServletRequest contract. It does provide a public method on the implementation to get at the raw HttpServletRequest. So you either have to use Liferay specific APIs or reflection to get at it. Here's a more detailed example for Liferay 6. If the original request is not an HttpServletRequest (which is perfectly valid) we can use reflection to get at the underlying HttpServletRequest through a Liferay API. public Object getOriginalRequest(){ BridgeExternalContext bec = getBridgeExternalContext(); if( bec == null ) { System.out.println("TestBean.getOriginalRequest: not BridgeExternalContext "); return "[not a BridgeExternalContext]"; } Object originalReq = bec.getOriginalRequest(); System.out.println("originalReq = " + originalReq); if( originalReq instanceof HttpServletRequest) { //If the original request is already an HttpServletRequest, we're done. This is how certain //portal containers implement their requests - as both PortletRequest and HttpServletRequests. System.out.println("TestBean.getOriginalRequest: original request is HttpServletRequest"); return originalReq; } //Liferay does it differently. Using reflection, we can try and get/invoke the specific Liferay method //that returns the raw HttpServletRequest. try { Method getHttpServletRequestMethod = originalReq.getClass().getMethod("getHttpServletRequest",null); Object httpRequest = getHttpServletRequestMethod.invoke(originalReq,null); if( httpRequest != null && httpRequest instanceof HttpServletRequest) { System.out.println("TestBean.getOriginalRequest: request from reflection = " + httpRequest); return (HttpServletRequest)httpRequest; } } catch (Exception e) { e.printStackTrace(); } //There may be other ways to get at the original HttpRequest depending on the portal vendor, //the version, what APIs they expose, etc. They would need to be investigated individually. return originalReq; }
        Hide
        Thomas Roka-aardal added a comment -

        I have found a similar issue when running under a Servlet 3 environment. I think the specification means that you should be able to access the actual environment implementation when you call getRequest on the ExternalContext, which should give you the real servlet/portlet request. However, the actual result is a wrapper (the anonymous inner class ServletExternalContext) which means you cannot access the real request. I posted this:

        http://www.icesoft.org/JForum/posts/list/22555.page

        This was found when using ICEfacesEE 1.8.2.GA_P03.

        Show
        Thomas Roka-aardal added a comment - I have found a similar issue when running under a Servlet 3 environment. I think the specification means that you should be able to access the actual environment implementation when you call getRequest on the ExternalContext, which should give you the real servlet/portlet request. However, the actual result is a wrapper (the anonymous inner class ServletExternalContext) which means you cannot access the real request. I posted this: http://www.icesoft.org/JForum/posts/list/22555.page This was found when using ICEfacesEE 1.8.2.GA_P03.

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Deryk Sinotte
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: