Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Is RPC the best SmartClient server integration for portal servers?

    I want to integrate as much of the SmartClient 8.0 server framework as possible into my Liferay 5.2 portal server environment. (Liferay 5.0 is a JSR 286 compliant portal server.) My goal is to get a SmartClient TreeGrid working within a portlet bound to a dynamic data source. I'd like to use the call to the SmartClient server's IDACall servlet and just write a custom datasource Java class but I cannot becuase the datasource for the tree grid needs access to the portlet's session to generate its data.

    The problem of needing to access the portlet's session from an AJAX request is nicely illustrated here:
    http://www.ibm.com/developerworks/websphere/library/techarticles/0803_hepper/0803_hepper.html#N10186

    I want to solve this problem by having my SmartClient TreeGrid call its containing portlet's resourceURL with all of its fetchData requests as the article suggests. To do this here is my planned approach using the SmartClient RPCManager on both the client and the server side. Can someone from Isomorphic please let me know if you know of any better approach (possibly integrating the complete functionality of the IDACall servlet into the portlet architecture)?

    UI jsp code:
    Code:
    isc.DataSource.create({
        ID: "pivotDS",
        fields: 
    	[
    	  { name: "nodeid", type:"integer", primaryKey:true, hidden:true }
    	 ,{ name: "parentnodeid", type:"integer", foreignKey:"pivotDS.nodeid", hidden:true }
         ,{ name: "name" }
         ,{ name: "sec_id" }
         ,{ name: "total_qty" }
         ,{ name: "exposure_percent" }
         ,{ name: "total_amt" }
         ,{ name: "target_weight" }
         ,{ name: "deviation" }
        ]
    });
    isc.RPCManager.actionURL = '<portlet:resourceURL id="AJAX_RESPONSE" escapeXml="false" />';
    Portlet serveResource() method which is called by the resource URL looks like this:
    Code:
    public void serveResource(ResourceRequest request, ResourceResponse response) {
    	String resourceID = request.getResourceID();
    	if(!resourceID.equals("AJAX_RESPONSE")){
    		super.serveResource(request, response);
    		return;
    	}
    	
    	RPCManager rpc = null;
    	try {
    	    rpc = new RPCManager((HttpServletRequest)request, (HttpServletResponse)response);
    	} catch (ClientMustResubmitException e) { 
    	    return; 
    	}
    
    	for(Iterator i = rpc.getRequests().iterator(); i.hasNext();) {
    	    Object req = i.next();
    	    if(req instanceof RPCRequest) 
    	         throw new Exception("This example expects only DSRequests");
    	    DSRequest dsRequest = (DSRequest)req;
    	    
    	    String dsName = dsRequest.getDataSourceName();
    	    if(!"pivotDS".equals(dsName)) {
    	        rpc.send(dsRequest, dsRequest.execute());
    	        continue;
    	    }
    
    	    String operation = dsRequest.getOperationType();
    	    if(operation.equals(DataSource.OP_FETCH)) {
    	    	List resultData = getResultData(request);
    		    DSResponse dsResponse = new DSResponse();
    		    dsResponse.setSuccess();
    	    	dsResponse.setData(resultData);
    	    } else {
    	        dsResponse.setFailure();
    	        dsResponse.setData("Unsupported operationType: " + operation);
    	    }
    
    	    rpc.send(dsRequest, dsResponse);
    	}
    }
    Thank you,
    Jeff

    #2
    Your approach is fine, except that by calling RPCManager.processRequest() you can eliminate your manual request processing loop (unless you need it for something else).

    There is almost nothing in IDACall except a call to processRequest() and some top-level error handling logic to ensure exceptions are logged.

    Comment


      #3
      Thank you for your response. The code example I supplied in the prior post, wasn't actually compiled and tested. Now that I have tested and slightly modified the code from my prior post I'm getting an exception when I create the RPCManager. The code below gives an exception with the message "Non-RPC request ignored" when I try to construct the new RPCManager.

      Code:
      public void serveResource(ResourceRequest request, ResourceResponse response) {
      	String resourceID = request.getResourceID();
      	if(!resourceID.equals("AJAX_RESPONSE")){
      		super.serveResource(request, response);
      		return;
      	}
      	
      	RPCManager rpc = null;
      	try {
      		HttpServletRequest servletRequest = PortalUtil.getHttpServletRequest(request);
      		HttpServletResponse servletResponse = PortalUtil.getHttpServletResponse(response);
      		// This line throws an exception saying that the request is not a valid HttpRequest
      		rpc = new RPCManager(servletRequest, servletResponse);
      	} catch (ClientMustResubmitException e) { 
      		return true; 
      	}
      ...
      }
      Can you help me properly construct the RPCManager? Here is what I see on the servletRequest:
      The request string contains what look like important RPCManager fields
      Code:
      isc_rpc=1
      isc_v=SC_SNAPSHOT-2011-01-06
      isc_xhr=1
      isc_tnum=0
      The Post contains the following 2 fields and values:
      Code:
      _transaction=<transaction xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" xsi:type="xsd:Object"><transactionNum xsi:type="xsd:long">0</transactionNum><operations xsi:type="xsd:List"><elem xsi:type="xsd:Object"><criteria xsi:type="xsd:Object"></criteria><operationConfig xsi:type="xsd:Object"><dataSource>pivotDS</dataSource><operationType>fetch</operationType><textMatchStyle>exact</textMatchStyle></operationConfig><componentId>pivotTreeGrid</componentId><appID>builtinApplication</appID><operation>pivotDS_fetch</operation><oldValues xsi:type="xsd:Object"></oldValues></elem></operations></transaction>
      protocolVersion=1.0
      I have only 1 session cookie and it is:
      Code:
      JSESSIONID=284EDF4F17B4F02C395E5BB8D3C4BAA2
      When I compare my failed RPC request with other successful RPC requests looks to me like the problem is that I'm missing two cookies that should look something like this:
      Code:
      isc_cState=ready
      GLog=%7B%0D%20%20%20%20left%3A482%2C%20%0D%20%20%20%20top%3A55%2C%20%0D%20%20%20%20width%3A748%2C%20%0D%20%20%20%20height%3A786%2C%20%0D%20%20%20%20priorityDefaults%3A%7B%0D%20%20%20%20%20%20%20%20Log%3A4%0D%20%20%20%20%7D%2C%20%0D%20%20%20%20defaultPriority%3A3%2C%20%0D%20%20%20%20trackRPC%3Anull%0D%7D
      Can you please let me know if it looks like I'm missing anything else other than the cookies? I'd really like to use the DSReqeust and DSResponse objects that I can only get access to through the RPCManager.

      Thank you,
      Jeff

      Comment


        #4
        The cookies are not a problem. The problem is that whatever is processing the request before you do new RPCManager() has removing the information in the request, that is, by the time you are calling new RPCManager(), those parameters (especially _transaction) are gone.

        Comment


          #5
          You are right. After converting from the PortletRequest to the ServletRequest SC fields are dropped from the queryString and from the posted parameters.

          I've been working hard to try to integrate as much SC server logic as possible into my portlets, but I haven't found a a supported way through SmartClient server APIs to extract DSRequests and formulate DSResponses from the PortletRequests that I get from my Liferay portal server. It seems like the SmartClient RPCManager and DSRequest objects are all built on the assumption of using HttpServletRequests, not PortletRequests. How should I go about building a custom data source within a Portlet, not a Servlet?

          You're advice and direction are helpful and appreciated. Thank you!
          -Jeff

          Comment


            #6
            Do you have access to the inbound parameters at all via the PortletRequest or some other means? If so, you should be able to build a valid ServletRequest to use with the RPCManager (whatever PortalUtil is doing is obviously wrong if it's just dropping all the inbound data).

            Comment


              #7
              I need access to the portlet's session in order to create the data response. So simply forwarding the portlet request to a servlet (even with the right parameters on it) isn't going to work for me.

              So what I've done instead is built a class within my portlet that can extract DSRequest objects from the "_transaction" parameter on the request. Then I can utilize my portlet's session to create the response and send it back to the requester.

              This code is highly simplified version of what I'm doing to create new DSRequest objects from the portlet request.
              Code:
              Map transactionData = XML.parseXMLToMap(request.getParameter("_transaction"));
              Map operation = transactionData.get("operations");
              DSRequest dsr = new DSRequest(operation);
              Once I have my DSRequest objects I utilize my custom data retrieval logic to create the portlet response and send it to the requester.

              Comment


                #8
                Well, that will work (and we understand the volume of code you've omitted here, which is significant), but still drops major features such as transactions and automatic delivery of compressed results.

                To clarify the prior suggestion, you don't need to forward a request to a servlet, you just need to provide HttpServletRequest and HttpServletResponse objects that contain the passed parameter at all. A common way to do this is to create facade versions of these objects based on the Abstract base classes in the servlets API.

                Comment


                  #9
                  Thank you for your suggestion of the facade HttpServletRequest and Response objects. That is an idea that I haven't fully played with. But, the approach of building a class within my portlet that can extract DSRequest objects from the "_transaction" parameter on the request is working for me now. I may revisit your facade suggestion in the future if needed.

                  Thank you for your help and discussion. I'm sure that I'll be posting something else sometime soon.

                  Cheers,
                  Jeff

                  Comment

                  Working...
                  X