Use & lt; portlet: resourceURL & gt; In Liferay to trigger serveResource

Source: Internet
Author: User

Introduction:

<Portlet: resourceURL> is often used in portlet development. In general, the corresponding serveResource () method is called. Although everyone knows this process, they can understand the details of this process, I believe that there are no more than 100 people in the world. At least I asked our customer's liferay expert about this question last year. She cannot explain it. Later, Danny asked me this question last year. After studying it for a while, I had to put it on hold. Now, after I spent the last few days studying the details of deploying the war package in liferay, I suddenly found that I fully understand this problem.



Debugging analysis:

In fact, according to. From the conclusion above, we know that web. xml is added with a lot of additional content and then split into 2 files, 1 is the portal-web.xml file, which contains all the definitions of the filters except (Invoker Filter, the other is web. xml, it adds a lot of content, andMost importantly, it adds a PortletServlet definition in web. xml.


Therefore, go to the webapps on the server and check the web. xml in the Application Deployment directory,

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222U393-0.png "title =" 31.png"/>

I found that it is no longer the original web. xml. It has the PortletServlet definition. (For security reasons, the first part of the package name is removed ):

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222T011-1.png "title =" 33.png"/>

Therefore, this Portlet is equivalent to a bridge. It elevated the status of the Portlet originally affiliated to the Portal to a Servlet so that they can independently respond to various requests.

The Servlet ing of this Servlet is:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222Q620-2.png "title =" 34.png"/>



Now, there is a Search button on our page. Clicking the button triggers the following <portlet: resourceURL>:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V1B-3.png "title =" 35.png"/>


We can see that this <portlet: resourceURL> tag is recognized by the liferay-portlet.tld:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222VN4-4.png "title =" 36.png"/>

So the class that finally processes this tag is ResourceURLTag and ResourceURLTei.


It will eventually be converted into a request url by the processing class: The request url is:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222S160-5.png "title =" 45.png"/>


In the end, because the request url meets the/logearchportlet/* url mode,

(You will certainly ask, this http: // 172.29.175.236: 8080/web/guest/log-search ?...... This url obviously does not match the PortletServlet mode/logsearchportlet/*, because the PortletServlet mode is shown in:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222U005-6.png "title =" 46.png"/>

So how is the request url included in this portlet? I have been thinking about this for two days before I can understand it. I will mention it in my answers to the best questions)


So it will eventually go to The PortletServlet method.

First, obtain portletId from HttpServletRequest in row 64th:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222UQ3-7.png "title =" 37.png"/>


Then, get the PortletRequest and PortletResponse objects from HttpServletRequest/Response respectively in line 66-70, and then get the LIFECYCLE_PHASE of the request corresponding to the current request in line 72nd:

(Question 2: Why is the information about portletRequest, portletResponse, and lifecycle all set in HttpServletRequest? For more information, see troubleshooting)

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222S058-8.png "title =" 38.png"/>


Then, the PortletSession object in portletRequest is taken from line 8-90 and the PortalSession is associated with the PortletSession.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V359-9.png "title =" 39.png"/>


Then, in Row 3, The PortletUtilFilter. doFilter () method is called:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222R164-10.png "title =" 40.png"/>


Based on the current lifecycle value, it will determine the request type converted to PortletRequest:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222U132-11.png "title =" 41.png"/>

As we can see from the debugging information, the current lifecycle is "RESOURCE_PHASE", so it will convert PortletRequest to ResourceRequest. Then, in line 71st, it will continue to call the doFilter method of filterChain.


This time, it will first convert our portlet to ResourceServingPortlet. Here is our LogSearchPortlet, and then call the serveResource method of our LogSearchPortlet:

All parameters attached to the <portlet: resourceURL> structure are encapsulated in ResourceRequest.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V242-12.png "title =" 42.png"/>


It can be seen from the following that all the parameters in <portlet: resourceURL> will be added to ResourceRequest, a lot:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222S441-13.png "title =" 43.png"/>


The code in the portlet has implemented the serveResource method, so we can call and execute it correctly.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222R5L-14.png "title =" 44.png"/>



Q & A 1:

Our request url:Http: // 172.29.175.236: 8080/web-guest/logsearch ?.....How to access the url-pattern of PortletServlet/Logsearchportlet /*.

This problem is complicated, but we can guess that some preprocessing is performed before the request is sent to PortletServlet. We know that the Filter is always executed before the Servlet, and our request can meet the url-mapping of the Invoker Filter.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222VP1-15.png "title =" 47.png"/>


If this InvokerFilter is familiar with its code, it will find that it will actually call the doFilter method of each Filter chain according to the Filter definition on each Filter chain. Of course, these filters are defined in liferay-web.xml based on our previous research.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222Q101-16.png "title =" 48.png"/>


The first time the request was/web/guest/logsearch, it matched with us. Then it took some filters and finally called invokerFilterChain. doFilter (servletRequest, servletResponse ).

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V012-17.png "title =" 49.png"/>


The second time, when we enter this method, the request changes to/c/portal/layout.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222W391-18.png "title =" 50.png"/>


A lot of unimportant steps are omitted here, because the action-mapping of/c/portal/layout is defined in the struts-config.xml, as follows:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222U420-19.png "title =" 51.png"/>


Therefore, it will go to the execute () method of LayoutAction:

It will call the overloaded processLayout () method in row 244th:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222W0K-20.png "title =" 52.png"/>


Then in line 663-665, it will call the processPortletRequest method:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222U958-21.png "title =" 54.png"/>


Skip a long piece of code that has nothing to do with the focus of our research). In the end, it judges that lifecycle is "RESOURCE_PHASE" in the 899th line of porcessPortletRequest, So we enter this branch:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222QJ9-22.png "title =" 55.png"/>


Skip N non-related rows. At last, it constructs ResourceRequestImpl and ResourceResponseImpl through ServletRequest and ServletResponse, and creates and encapsulates a ServiceContext object through ResourceRequestImpl, looking at the debugging information on the right side, we can see that our request url is encapsulated in this ServiceContext object. (_ CurrentURL attribute), and then we add this ServiceContext object to the ThreadLocal list.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222W636-23.png "title =" 56.png"/>


Finally, call the serveResource method of InvokerPortlet in line 3. It will finally call the invoke () method of InvokerPortletImpl:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V642-24.png "title =" 57.png"/>


When we accessed the invoke () method, the answer was finally uncovered and I was given my eyes wide open:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222SE1-25.png "title =" 58.png"/>

Originally, it will get the name of the Portlet through PortletConfigImpl in row 610th. We get it as "logsearchportlet ", then splice it into the following/invoke string to get the path "/logsearchportlet/invoke", and then it creates a RequestDispatcher object for forwarding requests. Finally, as shown in:

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222V516-26.png "title =" 59.png"/>

It will forward the request to the/logsearchportlet/invoke specified by path, and the request url obviously matches/logsearchportlet/*, so you can enter PortletServlet correctly, therefore, this problem was successfully solved.


Question 2:

In the service method of PortletServlet serving the current request, why are portletRequest, portletResponse, and lifecycle information in HttpServletRequest?

After analyzing the entire process, this problem was solved. For more information, see lines 623rd to 626th of the invoke () method of InvokerPortletImpl,

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/11222Q610-27.png "title =" 60.png"/>

After the RequestDipatcher object is created, but the request has not been forwarded to/logsearchportlet/invoke, it will first obtain the HttpServletRequest object, and store the JAVAX_PORTLET_PORTLET, LIFECYCLE_PHASE, PORTLET_SERVLET_FILTER_CHAIN, in this way, the information can be correctly retrieved and processed in the service () method of PortletServlet.



Summary:

At the end of this article, I was very happy. In fact, I haven't figured it out for half a year, but I finally figured it out today. This was a question from our team called Danny. I did not solve the problem at the time. Later I hung up on the Liferay official website for a few months and no one could answer it, I am so happy that I still rely on my own strength to solve it.

(1) The request url corresponding to <portlet: resourceURL> On the page will be mapped to PortletServlet for processing, the purpose is to upgrade the request processing capability of the Portlet to the Servlet level, because it can now accept requests of the HttpServletRequest type. This PortletServlet will first obtain portletId and portletRequest from HttpServletRequest, portletResponse and lifecycle information, and then according to the lifecycle stage information, the request type of PortletRequest. For example, if lifecycle is RESOURCE_PHASE, it will convert portletRequest to ResourceRequest, which contains <portlet: all parameters included in resourceURL>. In the doFilter method, convert the portlet to ResourceServingPortlet and call the serveResource () method. Therefore, you can call the serveResource () method defined at the portlet application level correctly.

(2) This PortletServlet is not defined in the war package of our project at the beginning, but a piece of code added by the liferay framework after the war package is deployed to the liferay deployment directory, for details, see the previous article:Http://supercharles888.blog.51cto.com/609344/1286976

(3) but the most important thing is that the <portlet: actionURL> of our page does not directly correspond to the url-mapping of PortletServlet, which is also a problem that has plagued me for more than half a year. In fact, it first goes to InvokerFilter, and then goes to the struts framework when executing/c/portal/layout. After a series of long calls, it finally goes to invoke () of InvokerPortletImpl () solved In the method, it will generate a new path like/<portlet-name>/invoke, and then all the information related to the portlet, including the portlet, lifecycle, filterchain) add it to the HttpServletRequest object and create a new RequestDispatcher. The current request is forwarded to the new path. In this way, the request can match the url-pattern of PortletServlet and enter PortletSevlet.

This article from "parallel line cohesion" blog, please be sure to keep this source http://supercharles888.blog.51cto.com/609344/1287188

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.