renderRequest attributes are always null after calling renderURL - java

I can't seem to access data I want to pass to my .jsp files. I've simplified it to the bare-bones and it still doesn't work for me. This portlet is being deployed to a liferay portal.
Problem: I click on the link to call a renderURL for the next .jsp page. In the doView() method, I set an attribute with setAttribute. When I retrieve that attribute in the .jsp, it returns null.
Expected output: "Proper Value"
Actual output: "Default value"
NewPortlet.java (Controller)
public class NewPortlet extends MVCPortlet {
#Override
public void doView(RenderRequest request, RenderResponse response)
throws IOException, PortletException {
request.setAttribute("test", "Proper Value");
String path = ParamUtil
.getString(request, "path", "/html/new/view.jsp");
include(path, request, response);
}
}
view.jsp
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:renderURL var="testURL">
<portlet:param name="path" value="/html/new/edit.jsp"/>
</portlet:renderURL>
<p>Click me!</p>
edit.jsp
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%#page import="com.liferay.portal.kernel.util.ParamUtil"%>
<portlet:defineObjects />
<%
String test = ParamUtil.getString(renderRequest, "test", "default value");
%>
<p><%= test %></p>

I am not sure what exact usecase you have.
But here issue is, you are setting attribute and trying to fetch parameter, hence it returns null.
For solution to your issues as in code, use renderRequest.getAttribute("test") or use el, ${test}

The "view.jsp" is referring "edit.jsp" using portlet:renderURL and that can be an issue. The render requests may be executed sequentially or in parallel without any guaranteed order.
I am not sure why your workflow is this way (i.e. setting parameter in doView method), but try actionURL instead of renderURL.

Related

JSP not getting request parameters

I have a JSP page which is not seeing any of the request parameter values when displayed. Originally I tried with passing the parameters from a Servlet, which did not work. Just as a test I also tried calling that JSP from a form on an html page.
What I do in Servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String sampleValue = sampleModel.getMyValue();
request.setAttribute("param", sampleValue);
RequestDispatcher view = request.getRequestDispatcher("samplePage.jsp");
view.forward(request, response);
}
How I call JSP from an HTML page through a form with hidden fields:
<div>
<form action="samplePage.jsp" method="post">
<input name="param" type="hidden" value="sampleValue"/>
<input type="submit" value="Update">
</form>
</div>
Finally what I have on the JSP:
<body>
<p>Some info: ${param}</p>
</body>
As I said the problem is the value of the request attribute "param" which is lets say "sampleValue", does not get rendered on the page.
I have seen lots of examples how this is done and I think my code is correct. Is there any other reason why this may not be working? I am running a maven project with Tomcat 8.5.
EDIT: What I have found out so far is that the problem is not that the Expression language is not working. The request attribute just has no value when it arrives at the JSP.
Please ensure that isELIgnored is false in your jsp page.use bellow tag at the top of your jsp.
<%# page isELIgnored="false" %>
also you can ensure this by ${2 * 4} output is print as 8 on JSP.
Your form is using method=post. Your Servlet code should be located on the doPost method instead of doGet.
For Servlet case, replace ${param} in your samplePage.jsp with
<%=request.getAttribute("param")%>
For JSP case, replace ${param} in your samplePage.jsp with
<%=request.getParameter("param")%>
First, check whether variable sampleValue is capturing the string that you are passing from JSP like below
String sampleValue = sampleModel.getMyValue();
System.out.println(sampleValue);

How to Include a JSP Fragment into a JSP Page while forwading from Servlet?

First, Please suggest me if my question heading is not correct.
Moving on to question:
Say I am having below components:
search.jsp - A JSP Page with a Form to Submit Data
Search.java - A controller Servlet having both get() and post() defined separately so that it can acts as a dispatcher for path /search.jsp
searchResults.jspf - A Fragment with some JSTL code to show up the Search Results
What I want here is for every POST request the controller servlet has to do its calculation, set results as Request Attributes and than - forward the request to the view search.jsp that should include the Fragment after its own codes.
So that, I can have a View Defined in such a way as:
search.jsp
+
searchResults.jspf
on a single page.
Problem is, I can either do Forward or Include with the dispatcher as I don't know how can i Include a fragment while forwarding to a JSP into it.
Let me know if I need to post some code if necessary, or need any corrections.
In your search.jsp embed your searchResult.jsp using jsp:include:
<jsp:include page="searchResult.jsp"></jsp:include>
Exemple:
1. The servlet:
#WebServlet(name = "Servlet", urlPatterns = "/myForwardTest")
public class Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("search.jsp").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
search.jsp:
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>In search resust</title>
</head>
<body>
Search.jsp embed searchResult.jsp
<jsp:include page="searchResult.jsp" />
</body>
</html>
searchResult.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<body>
in searchResult
</body>
</html>
You can include your jspf in your jsp like below:
<%#include file="searchResult.jspf" %>
you can set a statement to execute a certain section only if a particular test evaluates to true .
Ex:
if(.....==true){
<%#include file="searchResult.jspf" %>
}else{
<%#include file="someOther.jspf" %>
}

Liferay portlet rerenders init page after processAction

I'm working with portlets and was working through the sample on liferay's wiki: https://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/writing-the-my-greeting-portl-4
I'm having some issues with the portlet redirecting back to the init jsp after processing a form. My Java class is:
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletPreferences;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class Directory extends MVCPortlet {
#Override
public void processAction(
ActionRequest actionRequest, ActionResponse actionResponse)
throws IOException, PortletException {
PortletPreferences prefs = actionRequest.getPreferences();
String greeting = actionRequest.getParameter("greeting");
if (greeting != null) {
prefs.setValue("greeting", greeting);
prefs.store();
}
super.processAction(actionRequest, actionResponse);
}
}
I have two jsps. view.jsp:
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# page import="javax.portlet.PortletPreferences" %>
<portlet:defineObjects />
<%
PortletPreferences prefs = renderRequest.getPreferences();
String greeting = (String)prefs.getValue(
"greeting", "Hello! Welcome to our portal.");
%>
<p><%= greeting %></p>
<portlet:renderURL var="editGreetingURL">
<portlet:param name="mvcPath" value="/edit.jsp" />
</portlet:renderURL>
<p>Edit greeting</p>
And edit.jsp:
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%# page import="com.liferay.portal.kernel.util.ParamUtil" %>
<%# page import="com.liferay.portal.kernel.util.Validator" %>
<%# page import="javax.portlet.PortletPreferences" %>
<portlet:defineObjects />
<%
PortletPreferences prefs = renderRequest.getPreferences();
String greeting = (String)prefs.getValue(
"greeting", "Hello! Welcome to our portal.");
%>
<portlet:actionURL var="editGreetingURL">
<portlet:param name="mvcPath" value="/edit.jsp" />
</portlet:actionURL>
<aui:form action="<%= editGreetingURL %>" method="post">
<aui:input label="greeting" name="greeting" type="text
value="<%=greeting%>
<aui:button type="submit" />
</aui:form>
<portlet:renderURL var="viewGreetingURL">
<portlet:param name="mvcPath" value="/view.jsp" />
</portlet:renderURL>
<p>← Back</p>
On the form submit of the edit.jsp, it's supposed to re-render that page. When I just use portlet:renderUrl instead of portlet:actionUrl, it does it correctly, but actionUrl isn't re-rendering. The tutorial says that it IS supposed to render edit.jsp again, so I'm not sure what I'm missing. Note: It is saving all my parameters correctly.
According to the JSR 286 (aka Portlet Specification 2.0), PLT.11.1.1.2:
The portlet-container must not propagate parameters received in an
action or event request to subsequent render requests of the portlet.
This is what happens when the user clicks the Submit button on the browser page:
The browser sends an Action request to Liferay, which contains, as its parameters, "name" and "mvcPath".
The portlet is now in Action phase, and so it executes the processAction method.
When the processAction method terminates without errors, Liferay is still responding to the Action request and the browser is still waiting for a response, which will be the HTML of the current page.
Because Liferay now has to respond the browser with the HTML of the page, it calls the render method for every portlet in page. That is, if makes a Render request to these portlets.
For your portlet, which is a MVCPortlet, the render method reads the "mvcPath" parameter to find out which JSP page it has to render.
But now, the JSR 286 says that there's no parameter passing between the Action and the Render phases, so the mvcPath, which was part of the Action request, is not copied by Liferay to the Render request that Liferay makes to your portlet.
Now, solutions:
As you suggested, at the end of the processAction method (but usually you don't change the processAction method, instead you create different methods for different actions, they'll tell you how to do in the tutorials... have a look to http://dev.liferay.com), you can set actionResponse.setRenderParameter("mvcPath","/edit.jsp"). This is perfectly normal.
If you want that your Action parameters are always copied to the subsequent Render request that Liferay makes to your portlet, you can set the copy-request-parameters init parameter to true (have a look here)
But you'll see that usually Liferay portlets go back to the view after executing an "edit" action (passing a "redirect" parameter in the Action request), so it's up to you.
Sorry, there's a lot to say about this subject, hope what I wrote can be useful to you!

Using jsp:param / c:param in a Portlet Environment

I'm trying to include JSP pages with jsp:param in a Portlet environment (using the Pluto portlet container).
for example,
<jsp:include page="test.jsp">
<jsp:param name="foo" value="bar"/>
</jsp:include>
and in test.jsp,
<c:out value="${foo}"/> or <%= request.getParameter("foo") %>
The output is always null and i've also tried using c tags, but got the same result.
<c:import url="test.jsp">
<c:param name="foo" value="bar"/>
</c:import>
I've searched through the net and many people have faced the same problem, except that there is no solution to it.
Is this a limitation or is there a different way to do it?
This works fine in a normal Servlet environment, but I see from a bit of googling that the portlet environment seems to break it. This is a shame, but indicative that the portlet spec is, to put it bluntly, broken.
If <jsp:param> won't work for you, the alternative is to use request attributes instead:
<c:set var="foo" value="bar" scope="request"/>
<jsp:include page="test.jsp"/>
And in test.jsp:
<c:out value="${requestScope.foo}"/>
or maybe just:
<c:out value="${foo}"/>
It's not as neat and contained as using params, but it should work for portlets.
I had the same problem. My solution was to work with Portlet's renderRequest object (which is accessible from included jsp files). In my portlet I set the attribute on the RenderRequest object then in my JSP (included via jsp:include). I use Portlet API to access the implicit renderRequest object. Here is a sample:
MyPortlet:
public void doView(RenderRequest request, RenderResponse response) {
request.setAttribute("myBean", new MyBean());
getPortletContext().getRequestDispatcher("myMainJSP.jsp").include(request, response);
}
myMainJSP.jsp:
<jsp:include page="header.jsp"/>
header.jsp:
<%# taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<% page import="sample.MyBean" %>
<portlet:defineObjects/>
<%
MyBean myBean = (MyBean)renderRequest.getAttribute("myBean");
%>
... html code...

How to check if external URL content loads correctly into an <IFRAME> in JSP page using HTTP response code

I am looking into a solution that would allow to load an external URL content into an <iframe> element in a JSP page.
However, before displaying any content, JSP code would first check for HTTP response of included in iframe's src URL and if 200/OK returned then display it otherwise a custom message or another page is displayed instead. I'd like to do it on the server side only.
Is there a way of achieving it without AJAX / user side scripting that could have potential cross-browser incompatibilities?
You can make use of JSTL (just drop jstl-1.2.jar in /WEB-INF/lib) c:import tag to import an external resource, which will throw FileNotFoundException if the URL is invalid, which in turn can be catched using JSTL c:catch tag. You can finally use JSTL c:choose to check whether to display the iframe or the eventual error.
Here's an SSCCE, copy'n'paste'n'run it (with JSTL installed):
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
<title>SO question 2291085</title>
</head>
<body>
<c:set var="url" value="http://google.com" />
<c:catch var="e">
<c:import url="${url}" varReader="ignore" />
</c:catch>
<c:choose>
<c:when test="${empty e}">
<iframe src="${url}"></iframe>
</c:when>
<c:otherwise>
<p>Error! ${e}</p>
</c:otherwise>
</c:choose>
</body>
</html>
Change http://google.com to http://google.com/foo or something invalid, you'll see that the error shows instead.
Note that I used varReader="ignore" to have it buffered but unread, so that it won't entirely hauled in which may be expensive because after all you're requesting the same URL twice.
Update: Alternatively, you can use a Servlet for this which preprocesses the request inside doGet() method with help of java.net.URLConnection. Here's a kickoff example.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
URL url = new URL("http://google.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int status = connection.getResponseCode(); // 200 = OK, 404 = Not Found, etc.
if (status == 200) {
request.setAttribute("url", url);
} else {
// Do your thing to set custom message or request another page.
}
request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
}
...and in page.jsp then just have something like
<c:if test="${not empty url}">
<iframe src="${url}"></iframe>
</c:if>
Map the servlet on an url-pattern of something like /foo and call it on http:/example.com/contexty/foo instead of the JSP.
The actual loading of the <iframe> is going to take place because the client loads it. There have simply got to be better ways of validating the URL than by trying to include it via JSP. Do it in Java, or just don't do it at all: have the server return a "not found" page that runs some Javascript to hide the iframe. (Have it show an error for people browsing with Javascript turned off.)

Categories