strange jsf issue - java

I have a facelet component for displaying rss content:
rssFeedReader.xhtml
<h:outputText
binding="#{rssReaderBean.text}"
value="#{url}">
<f:attribute
name="url"
value="#{url}" />
</h:outputText>
<ui:repeat
value="#{rssReaderBean.rss}"
var="rss">
<ice:panelGroup>
<ice:outputLabel
value="#{rss['publishDate']} - "
rendered="#{not empty rss['publishDate']}">
</ice:outputLabel>
<a
href="#{rss['link']}"
target="_blank">#{rss['title']}</a>
</ice:panelGroup>
<ice:panelGroup>
<ice:outputLabel>#{rss['description']}</ice:outputLabel>
</ice:panelGroup>
<hr />
</ui:repeat>
and I include it where I need it like:
<myLib:rssFeedReader url="http://rss.news.yahoo.com/rss/topstories"></myLib:rssFeedReader >
If I include it with different urls, multiple times on my page, I do not understand why it displays multiple times the same FIRST url rss feed insted of taking each url separately.
To be able to read the specified url in my bean I bind it to the h:outputText from my facelet. Code from RssReaderBean bean:
private HtmlOutputText text;
public HtmlOutputText getText() {
return text;
}
public void setText(final HtmlOutputText text) {
this.text = text;
}
and the method which takes the url and returns the list:
public List<Rss> getRss() {
try {
final URL u = new URL((String) text.getAttributes().get("url"));
///read the rss feed and prepare the result, this code works good so its not required here
}
Can you see the problem...?
Thanks.
UPDATE: The bean has Request scope specified in faces-config.xml. If I print out the value of the text url it shows the LATEST url but all the content is taken from FIRST...
so basically for:
<gra:rssFeedReader url="http://blog.test.com/feed/rss/"></gra:rssFeedReader>
<gra:rssFeedReader url="http://rss.news.yahoo.com/rss/topstories"></gra:rssFeedReader>
it prints out the content of blog.test.com but text value when the page is rendered will show empty for first and yahoo url from second one...

The problem is caused because you're binding the <h:outputText> of the tag file to a single bean property. So, everytime you add another <myLib:rssFeedReader> tag, it will override the binding with the last added tag in the view. Finally, when #{rssReaderBean.rss} is been evaluated during rendering the view, it has only the last one at it hands.
There are several ways to solve this. The cleanest way is to create a fullworthy custom UIComponent wherein you specify the URL as an attribtue. The attribute is supposed to be specific to the component, not to a single bean property. An alternative is to use a Map<String, HtmlOutputText> property instead, this is however going to be clumsy.
Or if you're running a Servlet 3.0 / EL 2.2 capable container or replace the standard EL implementation by one which accepts method arguments, such as JBoss EL, then you could pass the URL as argument instead. E.g. #{rssReaderBean.rss(url)}. For installation/configuration detail, see this answer.

Related

Liferay 7.3 how to get the parameter values inside a portlet and access in view.jsp

I am trying to get the parameters inside a portlet in Liferay 7.3. If I pass the parameter like:
http://localhost:8080/web/guest?name=abhi
in a web page, that contains my portlet. So My question is
Q1) can I get this parameter inside the Portlet Controller (doView method) when user reloads the above page, by doing something like:
import com.liferay.portal.kernel.util.ParamUtil;
public class MySamplePortlet extends MVCPortlet {
#Override
public void doView(RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
String name = ParamUtil.getString(renderRequest, "name");
System.out.println(name);
}
}
Here I am getting a blank for the 'name' when printing.
And
Q2) how I check the condition of this parameter in view.jsp view file (how to get the class variable value inside the view file) ?
<% if(name) %>
render form view
<% else %>
render messageBox view
......
I want to render different views according to the parameter value.
Parameters to a portlet are typically namespaced - e.g. a HTTP-parameter name could be anything to any portlet - and a page potentially has many portlets. All of them might think of name as something different: A city, a user, a customer, the currently used computer, a pet...
Thus any form typically submits values that look like (in jsp-lingo):
<input name="<portlet:namespace/>name" ..../> rather than <input name="name" ..../>
If you use tags that are portlet-aware, they might do the decoration automagically, e.g. <aui:input name="name" .../>.
Utilizing undirected and unnamespaced parameters in the portlet world might generate maintenance nightmares, specifically when you run into your first ambiguous name.
However, you can deactivate the namespacing, per portlet. Or you can manually access the underlying HTTPServletRequest. Both are strongly discouraged. Here's how you shoot yourself in the foot if you like to:
Set the portlet's property com.liferay.portlet.requires-namespaced-parameters=false
Utilize PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(renderRequest)) (what these functions do - and why you need them both - is described, for example, here)
So the ParamUtil will work if the parameter is for the portlet. in this case it seems you want the parameter in the url in general meaning not specific for the portlet. to achieve this you need to use PortalUtil
HttpServletRequest httpReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(req));
String name = httpReq.getParameter("name");
Note im looking for the original request. not the portlet request.
hope it helps

JSF Link not working (with Primefaces)

Sorry, really really basic question...
I've got a list of 'messageboard threads' that I display on a page. I want to be able to click on one of them and redirect to a page which displays the details for that thread. I'm struggling despite googling it for a while...
(I'm using PrimeFaces by the way)
Here's the relevant code from my 'list' page:
<p:commandLink value="#{thread.title}" action="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</p:commandLink>
(it's in an h:form element)
This is part of my named bean (other methods work fine)
...
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
...
public String showThread() {
System.out.println("id is " + getThreadId());
return "messageboard/list";
}
...
As you can see my method isn't implemented yet, but it's not even being called. Please can someone tell me why?
I tried with an h:link too by the way, same (or similar) problem.
Thanks!
UPDATE - Solved
Thanks to the help below, here is my solution (I've renamed 'messageboard' to 'discussion').
The link is generated using this code
value: what to display on the page, in my case the title of my discussion
outcome: refers to edit.xhtml, the faces file I want to go to
...and the [request] param is going to be called 'threadId' and has a value of the id attribute in my 'thread' object.
In the edit.xhtml page, I've got this
<f:metadata>
<f:viewParam name="threadId" value="#{viewDiscussionBean.threadId}" />
<f:event type="preRenderView" listener="#{viewDiscussionBean.loadDiscussion}" />
</f:metadata>
Note that 'threadId' is the same as the param name in the first page, and it is bound to my viewDiscussionBean's threadId property.
Then once the params are all set on my bean, I call the loadDiscussion method of my viewDiscussionBean. Since it now has the threadId property, it's able to do this (see below)
My viewDiscussionBean has the following managed property (I think the viewParam tag sets this, rather than the other way around).
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
private Discussion thread;
So once that's set, this method is able to run (because it now has an ID)
public String loadDiscussion() {
thread = mbDao.find(threadId);
return "edit";
}
This just uses a DAO (using Hibernate) to look up the discussion thread with that ID, and set it in the bean. And then...
In my edit.xhtml page, I can access values in the discussion thread using things like
<h:outputText value="#{viewDiscussionBean.thread.message}" />
Voila! Thanks.
There are many possible caused for an UICommand action not being invoked. You can find them all here: commandButton/commandLink/ajax action/listener method not invoked or input value not updated Among others a missing form, a nested form, or a conversion/validation error elsewhere in the form, being in a datatable whose datamodel is not properly preserved, etcetera.
As to your particular functional requirement, better is to use a <h:link>. A command link issues a POST request which does in your particular case not end up with a bookmarkable URL with the thread ID in the URL. A <h:link> creates a fullworthy link which is bookmarkable and searchbot-indexable.
E.g.
<h:link value="#{thread.title}" outcome="messageboard/list">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
This doesn't require a form nor an action method. You only need to move that #ManagedProperty to the bean associated with messageboard/list, or maybe replace it by <f:viewParam> in the messageboard/list view which allows for finer-grained validation/conversion.
See also:
Communication in JSF2 - Processing GET request parameters
When should I use h:outputLink instead of h:commandLink?
ViewParam vs #ManagedProperty(value = "#{param.id}")
Your best bet it probably to go with BalusC's answer and use <h:link>. However, I have some thoughts about the behavior you're seeing.
Primefaces <p:commandLink> (like <p:commandButton>) uses ajax by default. Therefore, there won't be any actual navigation resulting from returning an outcome from your action. This could make it look like your action isn't being invoked. Try adding ajax=false to your <p:commandLink>.
When using <h:link>, navigation is resolved when the link is rendered rather than when it's clicked. Modifying your example:
<h:link value="#{thread.title}" outcome="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
showThread() will be called (I think) when the view containing the link is being rendered. If you're not checking at the right time, this may also make it look like the method is being called.
In both cases, this doesn't explain why you wouldn't see the message to System.out at all, but I know I've tried that thinking it was fail-safe and still not seen the output, which all depends on your container, configuration, how you launched it, etc.

JSF not rendering span element for h:message

I have an h:inputText element and an h:message for it:
<h:form id="cancelForm">
<h:inputText id="days" />
<h:message for="days" />
</h:form>
So when I open the page, JSF renders a "span" element for the error message. This is ok.
When I press submit the application goes to java and validates the fields:
// Some code
if (error) {
FacesContext.getCurrentInstance().addMessage("days", new FacesMessage("Error message"));
return error();
}
But after this JSF does not render the "span" for h:message.
Why?
days is just the simple ID for the inputText component. For the addMessage call you need the full ID (the client ID).
You can obtain the client ID by looking at the rendered HTML source code, or if all parent naming containers on your Facelet have IDs, guess it. It's typically all the parent IDs concatenated with : as a separator.
To always get the 100% correct ID, bind the inputComponent to your backing bean and in the code fragment you show above query it for its ID.
Finally, one word of advice: typically the kind of error checking and adding faces messages is done via a Validator and/or Converter. Doing this in a backing bean should not be your first approach.

JSF 2.0 return null from action methods does not retain the original request parameters

I have a JSF application with a particular page to show/edit the details of a particular entity in my system (an attraction). I have a jsf page which takes the attractionId as a page parameter as follows:
<f:metadata>
<f:viewParam name="attractionId" value="#{attractionsBean.attractionId}" required="true" />
</f:metadata>
To submit the changes to the attraction I have this command button:
<p:commandButton styleClass="button"
ajax="false"
value="Update Attraction"
action="#{attractionsBean.updateAttraction()}" />
In the updateAttraction method, normally in JSF when you return null, the user is redirected to the same page showing any messages that might have been created. However, since the page requires an attractionId, it gives a validation error that the attractionId is null since it does not automatically add the original request parameter. Normally I do it as follows:
if (FacesContext.getCurrentInstance().getMessageList().size() > 0) {
return null;
}
But this does not send back the original parameters to display the specified attraction.
Can anyone suggest a clean solution for this please?
Thanks!!
You can add the includeViewParams=true parameter to an outcome to let jsf impl append all declared view parameters, but I think this can only work if you also include the view id. You could try something like this:
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?includeViewParams=true";
Or you could define a constant including the view id in your managed bean:
private static final String SUCCESS = "attraction?includeViewParams=true";
...
if (FacesContext.getCurrentInstance().getMessageList().size() > 0) {
return SUCCESS;
}
Some more examples for this param can be found at this blog post about POST-REDIRECT-GET and JSF 2.0.

JSF property transfer from backing bean A to backing bean B

I'm getting deeper into JSF 2.0 at the moment and lacking a bit of understanding about the "transport" of managed bean properties from one view to the other. I searched a bit but haven't found a really good example, so if anyone could point me to a tutorial or explain the things a little bit I'd really grateful.
So here is my scenario:
I'm developing a small playground calendar application. The first view select.xhtml contains the calendar selector, where the user can pick a specific date:
<html>
...
<h:form>
<!-- Calendar selector from primefaces -->
<p:calendar value="#{calendarSelect.date}" mode="inline" navigator="true" />
<p:commandButton value="Show entries for date" action="day" />
...
My corresponding backing bean looks like this:
#ManagedBean(name="calendarSelect")
#RequestScoped
public class CalendarSelectComponent {
private Date date = null;
... // Getters and setters
Now when I submit the form from select.xhtml I'm forwarded to day.xhtml
<html>
...
<h:form>
The current day ist:
<h:outputText value="#{calendarEdit.date}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
The backing bean now looks like this:
#ManagedBean(name="calendarEdit")
#ViewScoped
public class CalendarEditComponent implements Serializable {
private Date date = null;
private CalendarEntryBean currentEntry = null;
private List<CalendarEntryBean> allEntries = null;
....
I am now trying to solve the problem: How do I transfer the date parameter from the selector to the editor?
I've tried a number of options, one was this:
<p:commandButton value="Show entries for date" action="day" />
<f:setPropertyActionListener target="#{calendarEdit.date}" value="#{calendarSelect.date}" />
</p:commandButton>
A debugger shows, that indeed, the date property of the calendarEdit is populated with the value from calendarSelect, but since day.xhtml is a new view, a new CalendarEditComponent backing bean is being created and not the one I've populated with the date from the selector in the select view.
I've read that one solution would be to create a SessionScoped backing bean that does retain all it's values. But this is not the way I think it's supposed to work, because I don't really need the information in the session, I simply want it to "travel" from A to B. Another downside with the session based approach is that I can only use one selector and one editor per session - which I think isn't acceptible if you think of multi window browsing and so on.
I really don't think I'm the first one encountering such a scenario and I'm sure that JSF provides an elegant solution for this but I haven't been able to find that solution.
So once again, if anyone knows how to approach this - I'm listening! ;-)
The <f:setPropertyActionListener> is executed during invoke action phase of the form submit. So it expects that the value is still there at that point. But since your select bean is request scoped, it isn't there during form submit anymore. You want instead to pass a request parameter which get inlined in the output during render response. You can do this with <f:param>.
<p:commandButton value="Show entries for date" action="day" />
<f:param name="date" value="#{calendarSelect.dateAsString}" />
</p:commandButton>
It'll be available as request parameter (note that it only understands Strings, due to the nature of HTTP). You could let JSF set request parameters as managed properties, but since your edit bean is view scoped, this isn't possible with #ManagedProperty. You've got to gather it yourself by ExternalContext.
String dateAsString = externalContext.getRequestParameterMap().get("date");
True, that's clumsy. I would just have used the same bean and view for this and toggle visibility of select/edit forms by rendered attribute. The edit view is after all not directly openable/bookmarkable by a simple GET, isn't it? ;)

Categories

Resources