Why to use PortletURL? - liferay

This thread is not a question , it was a doubt raised when I was going through Liferay Forums about using PortletURL.
In some cases I see this PortletURL inside the javscript Method
function createRowURL() {
var portletURL = new Liferay.PortletURL();
portletURL.setParameter("rowNumber", "25" );
return portletURL.toString();
}
In some cases I see this PortletURL inside the doView Method as shown
To get currentURL :
PortletURL url = PortletURLUtil.getCurrent(renderRequest, mimeResponse or renderResponse)
creating PortletURL from renderResponse :
For RenderURL:
PortletURL renderURL = renderResponse.createRenderURL();
For actionURL:
PortletURL actionURL = renderResponse.createActionURL();
Could anybody please tell me in which case PortletURL would be useful ?

Portlet applications are different from normal web applications. Portlets are mini pages inside a parent page called a portal and multiple portals become a book (a Weblogic term). Normal URL will not work in this situation. Aside from the reason given above, a portlet has a life circle with different states. You have to give the Portlet container a way to determine which portlet is communicating with it and what state it is being in - such as the window state of the portlet - is it minimized, maximized, or normal. Of course, another important function of the PortletUrl is to carry request parameters. If you are looking at a PortletURL you will sure see a lot exotic names along with the request parameters you give it.
Although most of the information needed by a PortletURL are common in many situations, the structure of a PortletURL is implementation-dependent and it is generated by the Portlet container one way or the other. There has been some time since my last liferay experience. I never used liferay specific javascript in my application. I used my own javascript/ajax to communication with the portal container. So I am just guessing the javascript way you presented is also liferay specific and won't be portable among different portal frameworks.
Edit: added types of PortletURLs and their differences and usage following comment from #PrakashK.
There are two types of PortletURLs:
Action URLs, they trigger an action request followed by a render request.
Render URLs, they trigger a render request.
So the purpose of an ActionURL is to trigger some kind of action - such as pressing a button. The action request will be intercepted by portlet container and send to appropriate action request handlers which process the action request and set necessary render parameters to be used by the render phase. In the life cycle of a portlet, a render request ALWAYS follows an action request. On the other hand, a RenderURl, as it's name suggested, is mainly for rendering the portlet.
Because of the "rendering" nature of a RenderURL, in JSR168(Portlet 1.0), you could not serve dynamically generated resources directly through the portlet. The only workaround is to use an additional servlet to serve the resources. The biggest problem of this approach is the inability of a Servlet to be involved in the lifecycle of a portlet. Direct links to the resources in the same portlet web application are not guaranteed to pass through the portal server and will not have portlet context available. To overcome this, in JSR286(Portlet 2.0), a feature called resource serving and a new kind of URL called ResourceURL has been introduced to enable a portlet to dynamically serve a resource. ResourceURL is not a PortletURL although they extend the same BaseURL. The biggest difference between a ResourceURL and an ActionURL is that a ResourceURL will NOT trigger a render request. This makes possible an Ajax request to the resource.
For more information on Portlet 2.0, please refer to [JSR286].
Hope the above information would be useful to you.

Related

Is it possible to load a Liferay portlet dynamically on a page from a .jsp file?

I have a portlet that is deployed on a page and I need to produce a link that will load a different portlet (which is in a different module) in full-screen mode. I can load the built in Login portlet this way without a problem, but when I try to load any of my custom portlets I get two red error boxes with the message "You do not have the roles required to access this portlet." And I have the permissions - I can access the portlet fine when added to a page - and I'm even testing with an omni-admin account.
The portlet ID that has the .jsp file is 'subscriptionmanagement_WAR_subscriptionmanagementportlet' and the portlet ID I'm trying to load is 'GRPSignupForm_WAR_NY511RMportlet'. The tag is:
<liferay-portlet:renderURL portletName="GRPSignupForm_WAR_NY511RMportlet" var="grpPortlet" windowState="<%= WindowState.MAXIMIZED.toString() %>">
</liferay-portlet:renderURL>
Which produces the URL: http://localhost:8080/group/test/unsubscribe?p_p_id=tripitinerary_WAR_NY511RMportlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view
However, as I've mentioned, I have been able to load other portlets in this way. The login portlet for example using the same tag works fine:
<liferay-portlet:renderURL portletName="<%= PortletKeys.LOGIN %>" var="loginURL" windowState="<%= WindowState.MAXIMIZED.toString() %>">
<portlet:param name="mvcRenderCommandName" value="/login/login" />
</liferay-portlet:renderURL>
The obvious difference is that it is passing a specific render command parameter, but otherwise it is the same. It produces the URL:
http://localhost:8080/group/test-1/unsubscribe?p_p_id=com_liferay_login_web_portlet_LoginPortlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName=%2Flogin%2Flogin
For completeness, here is the code for the portlet I'm trying to load. But as I mentioned above, I have tried to load various portlets in this project and all of them produce the permissions error.
#Component(
immediate = true,
property = {
"com.liferay.portlet.display-category=root//NYSDOT//GRP",
"com.liferay.portlet.instanceable=false",
"com.liferay.portlet.header-portlet-css=/css/main.css",
"com.liferay.portlet.footer-portlet-javascript=/js/main.js",
"com.liferay.portlet.css-class-wrapper=grh-signup-form-portlet",
"javax.portlet.display-name=GRP Signup Form",
"javax.portlet.init-param.template-path=/html/",
"javax.portlet.init-param.add-process-action-success-action=false",
"javax.portlet.init-param.config-template=/html/configuration.jsp",
"javax.portlet.init-param.view-template=/html/view.jsp",
"javax.portlet.init-param.edit-template=/html/edit.jsp",
"javax.portlet.name=" + GRPSignupPortletKeys.GRPSIGNUP,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=administrator,guest,power-user,user"
},
service = Portlet.class
)
public class GRPSignupPortlet extends GenericPortlet {
...
...
}
So it's obviously possible, as the Login portlet works. I'm sure there is just some small bit of config I'm missing. I've tried to see what is different in the Liferay Login portlet that allows it to work, but haven't found the secret.
Liferay CE 7.3
You need to add the property 'add-default-resource'. In the component add:
"com.liferay.portlet.add-default-resource=true"
From portal.properties: "add-default-resource" set to true will allow those portlets to be dynamically added to any page by any user. This is useful (and necessary) for some portlets that need to be dynamically added to a page, but it can also pose a security risk because it also allows any user to do it.
It's prudent to also add
"com.liferay.portlet.add-default-resource-check-enabled=true",
From portal.properties: Set this property to true to add a security check around this behavior. If set to true, then portlets can only be dynamically added to a page if it contains a proper security token. This security token is automatically passed when using a portlet URL from one portlet to another portlet.

How to retrieve data from portlet to portal_normal.flt - Liferay

I want to retrieve some data from my custom portlet and put it to meta tags in portal_normal.ftl .
I've tried this:
<#if (renderRequest.getAttribute("something"))??>
<#assign urlImg = renderRequest.getAttribute("something")/>
<#else>
<#assign urlImg = "defaultturl"/>
</#if>
, but i always get null. Probably my portlet is loaded after theme and it will never acces this data.
Have you any idea how to solve it?
Thanks!
It is not common that a custom Portlet will provide data for the theme. Also, I am not sure if it will be the same Request object in the theme as in your Portlet, because some request related objects (session etc.) are usually scope to the Portlet (unshared).
You should rather use a Theme Context Contributor as descripted on this Liferay tutorial: DXP context-contributors. When using TYPE_THEME and implementing the interface, you can add data to your theme template.

Access from internet the web.xml file of an applicaiton

Is it possible for someone to access or view the web.xml file of a web application over internet, using somthing like wget tool? I'm asking for saecurity reasons like username
By specification, it is not possible to directly access /WEB-INF (and /META-INF) contents by a public URL. Here are extracts of relevance from the aforelinked specification:
10.5 Directory structure
...
Also, except
for the case where static resources are packaged in JAR files, any requests from the
client to access the resources in WEB-INF/ directory must be returned with a
SC_NOT_FOUND(404) response.
10.6 Web Application Archive File
...
Also, any requests to access the resources in META-INF
directory must be returned with a SC_NOT_FOUND(404) response.
However, there have been implementations, configurations and even homegrown servlets or filters which introduced a security bug making this possible. All those security issues boil down to be caused by a RequestDispatcher#forward() or even RequestDispatcher#include() (so watch out with dynamic <jsp:include>!) call forwarding or including a resource which is specified by a client-controlled request path or parameter, if necessary making use of path traversal with ../.
Here's the simplest example of such a servlet exposing the security issue:
#WebServlet("/test/*")
public class TestServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher(request.getPathInfo()).forward(request, response);
}
}
On Tomcat (tested with 8.0.21), you can with the above servlet get the web.xml contents by just calling http://localhost:8080/context/test/WEB-INF/web.xml. Such a servlet is often implemented as part of homegrown MVC front controller or dispatcher pattern. Decent MVC frameworks like JSF and Spring MVC shouldn't have this issue.
And, some users configure a MVC front controller on a "catch-all" URL pattern of /* or even /, and then re-map the static resources like CSS/JS/images on /static/* to container's default servlet like so:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
On older Tomcat versions (before 7.0.4), the enduser can get /WEB-INF (and /META-INF) contents through such a mapping. This problem was mentioned previously in this Q&A: Tomcat serving static content. Actually, this mapping approach is wrong and should have been solved with help of a filter as descibed in this answer: How to access static resources when mapping a global front controller servlet on /*. See also Tomcat issue 50026.
Summarized: by default it's not possible. But (bad) code and configuration can make this possible.

Portlet preferences scope in a Liferay configuration page

I develop a Liferay portlet which has preferences unique per layout: preferences are specific to each portlet window, and users can modify them through "Preferences" option (Edit mode).
In liferay-portlet.xml:
<preferences-unique-per-layout>true</preferences-unique-per-layout>
However i would like to add a configuration page, in order to manage global parameters which should be shared across all portlet windows. Currently these parameters are handled as "init-param" in portlet.xml but it is not very convenient, admin users should be able to change those parameters through portal UI.
I followed the approach described here to create a such page, it works for the current portlet window but preferences are not shared. Is it possible to use a specific scope for some preferences? This other wiki makes use of a method specifying "uniquePerLayout" and "uniquePerGroup" but i did not find this method in APIs from 5.2.3 to 6.2
public static PortletPreferences getPortletSetup(
ActionRequest req,
String portletId,
boolean uniquePerLayout,
boolean uniquePerGroup)
Please could someone enlighten me on this subject?
Thanks!
In 6.2, There is getPortletSetup method that accept layout and group,
PortletPreferencesFactoryUtil.getPortletSetup(scopeGroupId, layout,
portletId, defaultPreferences).
You can get scopeGroupId, layout from themeDisplay as below and portletId & defaultPreferences should be set as per your requirement.
ThemeDisplay themeDisplay = (ThemeDisplay) actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
Layout layout = LayoutLocalServiceUtil.getLayout(themeDisplay.getPlid());

Using Post when doing a sendRedirect

I have a requirement that a jsf page needs to be launched from a custom thin client in user browser (thin client does a http post). Since the jsf page may be invoked multiple times, I use a jsp to redirect to the jsf page with params on url. In jsp I do a session invalidation. The jsp code is below:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%#page session="true" %>
<%
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
session.invalidate();
String outcome = request.getParameter("outcome");
String queryString = "outcome=" + outcome ;
response.sendRedirect("./faces/MyPage.jspx?" + queryString);
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"></meta>
<title>title here</title>
</head>
<body></body>
</html>
My jsf page uses mutiple drop down items with autoSubmit enabled. I set the params on session when the form first inits and then use it from there when an action button is ultimately clicked by user. Following is the code I use to get the param in jsf backing bean constructor:
FacesContext ctx = getFacesContext();
Map sessionState = ctx.getExternalContext().getSessionMap();
outcome = (String)sessionState.get("outcome");
if(outcome == null) //if not on session, get from url
outcome = (String)JSFUtils.getManagedBeanValue("param.outcome");
This way I can get the param even after multiple autoSubmits of drop downs.
My problem is that I cannot have parameters show up on browser address bar. I need a way so that the parameters can be passed to the jsp page. I cannot post direct to jsp from thin client since I need the jsf page to have a new session each time the client launches user browser. This is imp due to the above code snippet on how I use params in the jsf page.
Is there nay way to use a post when doing a sendRedirect so that I do not have to pass params on url? I cannot use forward since when an autoSubmit fires on jsf page, it causes the browser to refresh the jsp page instead.
Is there any better way to handle the jsf page itself so that I don't have to rely on storing params on session between successive autoSubmit events?
Since you invalidate the session, no, you cannot.
The only way would be putting it in the session scope. Why are you by the way invalidating the session on first request? This makes really no sense.
Unrelated to your actual problem, doing sendRedirect() in a scriptlet instead of a Filter and having a bunch of HTML in the same JSP page is receipt for big trouble. Do not write raw Java code in JSP files, you don't want to have that. Java code belongs in Java classes. Use taglibs/EL in JSP only.
No. Because sendRedirect send the web-browser/client a 302 with the new location and according to the following it will usually be a GET, no matter what the original request was.
According to HTTP/1.1 RFC 2616 http://www.ietf.org/rfc/rfc2616.txt:
If the 302 status code is received in response to a request other
than GET or HEAD, **the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user**, since this might
change the conditions under which the request was issued.
Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, ***most
existing user agent implementations treat 302 as if it were a 303
response, performing a GET on the Location field-value regardless
of the original request method***. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.
Maybe playing carefully with ajax can get you something.
Update: Then again, as user: BalusC pointed out, you can redirect by manually setting the headers, as in:
response.setStatus(307);
response.setHeader("Location", "http://google.com");

Resources