What is the difference between doView() and render() functions in Liferay? - liferay

What is the actual difference between doView() and render() functions in Liferay? and also what is the difference between renderRequest and resourceRequest?

doView() = to handle render requests when in VIEW mode.
render() = This method invokes the doDispath() method and sets the title of the portlet by using getTitle() method. Then it invokes one of doView(), doEdit(), doHelp(), etc. depending of the portlet mode specified in the RenderRequest.
Again, RenderRequest is when you want to handle requests in the VIEW mode of the portlet. If your portlet uses additional resources to render the view (i.e. images, JavaScript files, etc.) then the JSP that renders the view will use <portlet:resourceURL /> tags to generate valid URLs to those resources. Those URLs will be processed with a pair of ResourceRequest and ResourceResponse objects.
You can override the resource phase though but bear in mind that when you use ResourceRequest/ResourceResponse to serve, the portlet can't change the current portlet mode, window state or render parameters. And also the parameters set on the resource urls are not the render parameters and they are valid to serve only that current resource request.

Related

JSF web application -- opening a particular page based on url parameters

Our project uses a Web Application developed using JSF, primefaces, xhtml. Currently user can login and navigate through pages sequentially by clicking on 'action' links, like:-
index.xhtml --> login.xhtml --> classes.xhtml --> students.xhtml --> student_info.xhtml
i.e. first login --> shows the list of classes --> user selects a class --> shows the list of students in that class --> user selects a student --> shows the student info.
Each of the pages has its own 'backing bean' classes. They are instantiated as and when the user clicks through the pages.
Also, user can navigate back via certain links on each page-- say, from 'student_info' page, he/she can go back to the 'students' page.
Now requirement is: user can directly go to an inner page, say, student_info page by typing an 'url' with additional parameters, ?user=alice,?passwd=xyz, ?class=5, ?studentRollNo=15.
Also, the user should still be able to navigate back to other pages (i.e. once the page is opened, their should be no behavior difference whether the user navigated normally to student_info page or, whether he directly provided url with parameters).
My questions are:-
How to read url parameters in JSF?
Which page (or backing bean) should handle the parameters? Should it be done centrally, or, in each page (backing bean) ?
In case each page handles its relevant parameters only -- is there way to redirect remaining parameters to the next page ?
What are the best practices used in such implementations?
Note:
Actual web application is much more complex, tried to provide a simpler picture which pinpoints my problem.
new to JSF, Web App etc. Don't know if there are some JSF terminologies to describe above issues.
you can pass it by url request, and each BackingBean handle it
ex:
mypage.xhtml?myparam=test
and inject the HttpServletRequest in your BackingBean (if you are using CDI)
#Inject
HttpServletRequest request;
and get the param
#PostConstruct
public void init() {
String myparam = request.getParameter("myParam");
}
for redirect to other page you can use
public String redirect() {
return "otherPage.xhtml?faces-redirect=true&otherParam=test";
}

ActionRequest vs RenderRequest

I've read here that actionrequest is only valid during the action phase and RenderRequest is only valid during the render phase. However if I set actionREquest.setAttribute("object", myobject) I can access this object from my JSP, which I understand is the render phase right? How is this possible and how does this fit with the answer I link?
While ActionRequest and RenderRequest are distinct classes/objects, they all relate to the same request handling cycle. The main difference is that ActionRequest allows you to change state, RenderRequest does not any more.
While only one portlet on the page can handle an action (per single HTTP request), all portlets on the page typically render to make up the whole markup of the page. That's what the separation of action/render brings you in the portlet world. Servlets didn't have this because one servlet was always meant to render the whole page on every single request anyway. Portlets can render (which they most often do) and they can change state (which they typically do in the action phase)
You shouldn't forget that after an action-phase, portlet lifecycles proceed toward render-phase.
Try to watch the image in this blog post (the first I found by a google search): http://haitaoblog.blogspot.it/2011/05/portlets-portal.html
So JSP can access to both attributes in request.
On the other hand, if you need to access in the render phase to an action RENDER parameter, you have to set it inside your action code
actionResponse.setRenderParameter("parameter-name", "value");

Navigation after IPC in Liferay

we want to navigate in Liferay to an other portlet after receiving a IPC-Event.
So we send the event from one portlet, implemented an second Portlet extends from MVCPortlet, and receive the event with some information!
So we want to navigate in Liferay to the second portlet.
The methode were we receive the event is this
#ProcessEvent(qname = "{http://liferay.com}empinfo")
public void handleProcessempinfoEvent(final javax.portlet.EventRequest request, final javax.portlet.EventResponse response) throws javax.portlet.PortletException, java.io.IOException
Also we override the methods from com.liferay.util.bridges.mvc.MVCPortlet but no one was called after sending the event.
Is there any way to navigate inside liferay (6.1.2)?
Thx Tim
Is the event handled at all? What do you mean with "navigate to the second portlet"?. Events - by default - only get distributed to the portlets that appear on the same page. If you want to receive an event on a portlet that exists on a different page, you'll have to explicitly configure Liferay to distribute events to all pages in the same site. Note that this might dig into your performance. Also - once you navigate to another page - by default the portlet's state on that page is being reset.
Check the following (and related) portal.properties:
#
# Set this property to specify how events are distributed. If the value is
# "layout-set", then events will be distributed to all portlets contained in
# a layout set. If the value is "layout", then events will be distributed to
# all portlets that are present in a layout.
#
portlet.event.distribution=layout
#
# Set this property to specify how public render parameters are distributed.
# If the value is "layout-set", then public render parameters will be
# distributed to all portlets contained in a layout set. This will only work
# correctly if the property "layout.default.p_l_reset" is set to false. If
# the value is "layout", then public render parameters will be distributed
# to all portlets that are present in a layout.
#
portlet.public.render.parameter.distribution=layout
#
# Set the default value for the "p_l_reset" parameter. If set to true,
# render parameters are cleared when different pages are hit. This is not
# the behavior promoted by the portlet specification, but is the one that
# most end users seem to prefer.
#
layout.default.p_l_reset=true
If you intend to navigate to a different page, you'll also have to note that this is not covered by the portlet API. Thus you'll have to identify how to find the relevant page, its URL and how to redirect. It's probably easier to have some more logic in the action-handling portlet and do the redirect there: At least you'll only handle one action. Potentially there might be several Events handled per Action - thus it's undefined which potential redirect will be triggered if they conflict. I'd see a real redirect (any way) as rather unexpected behavior if it comes from an EventHandler, but somewhat understandable from an ActionHandler.

JSF: Bookmarkability with ViewScoped

I am trying to make my app "Bookmarkable", and i am using view parameters to achieve it.
And i think i still do not get the right way to do it right in JSF, even after reading this, and many others.
My problem is that the get parameters get lost after any non-ajax postback, i mean, the parameter value is still set in the bean and the app works correctly, but it gets removed from the URL making the URL invalid.
For instance, having an URL like http://company.com/users?id=4, as soon as that page executes a non-ajax postback (for uploading data, for instance) the URL becomes just http://company.com/users. The app continues to work correctly, but the link is not any more "Bookmarkable".
Is there any way to prevent the non-ajax postbacks removing the viewParams from the URL?
My use case is to be able to bookmark a page to EDIT an object, and there i need to be able to upload data (if not i would not use non-ajax postbacks). I know i would not need any postback if i would want to bookmark the page to only VIEW the data of the object, but that is not my case.
I could also do a redirect to the same page with the same params, and let the app to recreate the view scoped bean, but then i really do not see any benefit over request scoped beans...
Any suggestion is very appreciated.
This behaviour is "by design". The <h:form> generates a HTML <form> element with an action URL without any view parameters. The synchronous POST request just submits to exactly that URL which thus get reflected as-is in browser's address bar. If you intend to keep the view parameters in the URL, while using ajax is not an option, then you basically need to create a custom ViewHandler which has the getActionURL() overridden to include the view parameters. This method is used by <h:form> to generate the action URL.
public String getActionURL(FacesContext context, String viewId) {
String originalActionURL = super.getActionURL(context, viewId);
String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
return newActionURL;
}
Or, as you're based on the comments already using OmniFaces, you could also use its <o:form> component which basically extends the <h:form> with the includeViewParams attribute which works much like the same as in <h:link> and <h:button>.
<o:form includeViewParams="true">
...
</o:form>
This way all <f:viewParam> values will end up in the form action URL.
See also:
Handling view parameters in JSF after post

How to create a RenderURL during action phase in a portlet?

In the method processAction(ActionRequest request, ActionResponse response), I insert a record into database and get the ID and then
I want to redirect to the view page of this record. So I need to create a RenderURL with a parameter value for that ID.
ActionResponse doesn't provide method to create a renderURL. Some codes in Liferay do similar things like:
create renderURL before accessing the actionURL
pass the renderURL as a parameter in the actionURL
However, at that time, I don't know the value of ID.
Other codes also use new PortletURLImpl() directly. My portlet cannot see that class.
Other codes also use new PortletURLImpl() directly. My portlet cannot see that class.
Because this class is in portal-impl.jar and also it is not recommended to use classes from this jar. Starting from Liferay 6.1, you won't be able to build your portlet from plugins-sdk if you classes point to portal-impl.jar.
Now to answer your question:
Any jsp is rendered by the render method or doView method (if using liferay's MVCPortlet) and this method would be called as part of the normal life-cycle of portlets.
Here are the steps you would need to take:
set a render parameter (using response.setRenderParameter() method) in your `processAction' method at the last which would be available in your render method, as follows:
actionResponse.setRenderParameter("myID", 1201);
Just for info: After using setRenderParameter you cannot use sendRedirect method
fetch this "myID" in your render method as you fetch any other request parameter:
//assuming your ID is a long
long myUserName = ParamUtil.getLong(renderRequest, "myID");
or
String strMyID = renderRequest.getParameter("myID");
long myID = Long.parseLong(strMyID);
After this, just use
include(renderPage, renderRequest, renderResponse);
were renderPage is nothing but a string containing the path to your jsp within docroot like /html/yourportlet/view.jsp
Just as an afterthought:
If you are using a Liferay IDE, then you can try creating a simple portlet project with MVCPortlet and then look at the generated portlet.xml's <init-param>
So basically you need to pass information from action-phase to render-phase, the development guide is a good place for explaining this in detail.
That's it.
Hope this helps.
Let me know if you have any confusion regarding this.
In action phase do the following:
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute (WebKeys.THEME_DISPLAY);
PortletURL url = PortletURLFactoryUtil.create(request, this.getPortletName(), themeDisplay.getPlid(), PortletRequest.RENDER_PHASE);
For example, if you want to redirect to the login page and back, you can do the following:
response.sendRedirect("/c/portal/login?redirect=" + HttpUtil.encodeURL(url.toString()));
Definitely you can add or copy the parameters as required.
Instead of creating the renderURL you can include the view page include(viewTemplate,actionRequest,actionResponse). Or if you want to sent any parameter any want's to get it in doView then use actionResponse.setParameter(name,value) method
I create a RenderURL with a place holder as parameter value, like this:
<portlet:renderURL var="redirect">
<portlet:param name="ID" value="__ID__" />
</portlet:renderURL>`
In processAction:
String redirect = redirectParam.replace("__ID__", "123213");
actionResponse.sendRedirect(redirect) ;

Resources