parameter in URL jsf2 - jsf

I need to have this link:
http://myserver:/myproject/innerpage/clip.jsf&id=9099
to extract the id from a code like this:
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String clipId = request.getParameter("id");
When I run it on tomcat I get:
message
/OnAir/innerpage/clip.jsf&id=9099
description The requested resource
(/OnAir/innerpage/clip.jsf&id=9099)
is not available.
When I run it without &id=9099 it runs all right.
How can I make it run?

The separator character between path and query string in URL is ?, not &. The & is separator character for multiple parameters in query string, e.g. name1=value1&name2=value2&name3=value3. If you omit the ?, then the query string will be seen as part of path in URL, which will lead to a HTTP 404 page/resource not found error as you encountered.
So, this link should work http://myserver:port/myproject/innerpage/clip.jsf?id=9099
That said, there's a much better way to access the request parameter. Set it as a managed property with a value of #{param.id}.
public class Bean {
#ManagedProperty(value="#{param.id}")
private Long id;
#PostConstruct
public void init() {
System.out.println(id); // 9099 as in your example.
}
// ...
}
The EL #{param.id} returns you the value of request.getParameter("id").
A tip: whenever you need to haul the "raw" Servlet API from under the JSF hoods inside a managed bean, always ask yourself (or here at SO): "Isn't there a JSF-ish way?". Big chance you're unnecessarily overcomplicating things ;)

You first have to show us how you are sending the parameter in your JSF, is it a commandButton/Link? An outputLink? A ? Also are you using redirect=true?
Chances are you are losing the id somewhere during the request.

Related

Adding ConversionService to Spring Cloud Stream

I'm using Spring Integration and String Cloud Stream. I have a header that I want my HTTP gateway to use, which has a Long value, but it can't convert from Long to String by default and so displays the error Consider registering a Converter with ConversionService.
Therefore I tried adding my own LongToStringConverter class and the following Bean so that LongToStringConverter can be used:
#Bean
public ConversionService conversionService()
{
DefaultConversionService service = new DefaultConversionService();
service.addConverter( new LongToStringConverter() );
return service;
}
Then then received the following error: Dispatcher has no subscribers.
If I only return an instance of DefaultConversionService from the above bean I still receive the error.
When I remove the above bean and instead simply convert the Long value to String when setting the header value and that works without errors. Is it possible to use ConversionService instead? If so then how?
First of all there is already a ConversionService: https://docs.spring.io/spring-integration/docs/4.3.12.RELEASE/reference/html/messaging-endpoints-chapter.html#payload-type-conversion. And it has some set of predefined converters. So, you should consider to use #IntegrationConverter on the matter.
On the other hand it is unclear why do you need to do that at all. I wonder why Long.toString() isn't enough for you when you declare that header in first place.

Obtaining a URL up to the context path from the current HTTP request in JSF

Assuming the following URL (with or without any query-string and/or extra path info).
https://localhost:8181/ContextPath/xxx/page.xhtml
Which I need to extract the following portion from.
https://localhost:8181/ContextPath
i.e. up to the context path.
This can be done in one way defining a utility method of our interest something along the following piece of code.
public static String getBaseURL(HttpServletRequest request) {
String url = request.getRequestURL().toString();
return new String(url.substring(0, url.length() - request.getRequestURI().length())) + request.getContextPath();
}
And it can be invoked from managed beans as follows.
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String link=Utility.getBaseURL(request);
But this in turn requires exposing the underlying javax.servlet.* API which I am not interested in.
Is there a sane JSF way in which the said portion of a URL from the current HTTP request can be obtained without explicitly exposing the underlying Servlet API?
I am not interested in individually collecting portions like scheme, server name, port, context path etc. using their respective separate methods associated with an instance of HttpServletRequest.
Just pass the FacesContext.getCurrentInstance().getExternalContext() to your utility methdod and the javax.servlet.* API is NOT exposed...

Implementing a Locale provider that works in JSF and JAX-RS

I've been joyfully using omnifaces' Faces.getLocale() to aquire the locale used by the currently logged in user (which in turn gets this from a <f:view> definition). I really like the fallback approach from view to client to system default locale as it fits the requirements for locale selection in my application:
If a user is logged in, use his language preference (obtained from the backend entity)
If no user preference can be found, use the highest ranking language from the Accept-Languages HTTP header
If no locale has been selected by now, use the system default.
Now I've started using JAX-RS (resteasy implementation) and find it quite difficult to write a service that will provide my backend code with the current user's locale.
I can't use Faces.getLocale(), since that requires a FacesContext which isn't present during JAX-RS request processing.
I can't use the #Context SecurityContext annotation in a #Provider (which would give me the user preferred locale) or #Context HttpHeaders (access to the client locale) since JAX-RS only injects those when it uses the provider itself, not when my backend code instantiates the class.
And I don't want to litter my method signatures with Locale parameters, since virtually everything requires a locale to be present.
To have a concrete example: I have a vcard generator that generates little NOTE fields depending on the user's preferred locale. I can both call the vcard generating method via JSF/EL:
<h:commandLink action="#{vcfGenerator.forPerson(person)}"
value="Go" target="_blank" />
And via a REST service:
#GET #Path('person/{id:[1-9][0-9]*}/vcard')
#Produces('text/vcard')
String exportVcard(#PathParam('id') Long personId, #Context HttpHeaders headers) {
VcfGenerator exporter = Component.getInstance(VcfGenerator) as VcfGenerator
Person person = entityManager.find(Person, personId)
if (! person)
return Response.noContent().build()
def locale = headers.acceptableLanguages[0] ?: Locale.ROOT
return exporter.generateVCF(person, locale).toString()
}
This works (VcfGenerator has a set of JSF-only methods that use Faces.getLocale()), but is a pain to maintain. So instead of passing the Locale object, I'd like to say:
Vcard generateVCF(Person person) {
Locale activeLocale = LocaleProvider.instance().getContext(VcfGenerator.class)
ResourceBundle bundle = ResourceBundle.getBundle("messages", activeLocale, new MyControl())
// use bundle to construct the vcard
}
Has anyone done similar work and can share insights?
I know this has been posted a while ago, but as it has not been marked as resolved, here is how I got a workaround working for this specific case:
First I got a custom ResourceBundle working, as #BalusC described here: http://balusc.blogspot.fr/2010/10/internationalization-in-jsf-with-utf-8.html
Then I updated the constructor in order to detect if a FacesContext is currently being in use, from this :
public Text() {
setParent(ResourceBundle.getBundle(BUNDLE_NAME,
FacesContext.getCurrentInstance().getViewRoot().getLocale(), UTF8_CONTROL));
}
To This:
public Text() {
FacesContext ctx = FacesContext.getCurrentInstance();
setParent(ResourceBundle.getBundle(BUNDLE_NAME,
ctx != null ? ctx.getViewRoot().getLocale() : Locale.ENGLISH, UTF8_CONTROL));
}
This now works both in JSF and JAX-RS context.
Hope this help,

Call to ActionResponse.setRenderParam is ignored / ineffective

I have a Liferay JSF 2.0 portlet that has code like the following:
private String userId
private String organization
private String registrationToken
...
public String submitLogin() {
ActionResponse actionResponse = (ActionResponse) PortletUtil.getExternalContext().getResponse();
actionResponse.setRenderParameter("userId", this.userId);
actionResponse.setRenderParameter("org", this.organization);
if ( StringUtils.hasText(this.registrationToken) )
actionResponse.setRenderParameter("token", this.registrationToken);
...
}
All of the private member variables are mapped to input form fields and have the appropriate getters and setters.
If I trace this code in Eclipse's debugger and examine the contents of the ActionResponse instance's _publicRenderParameters HashMap, I see that the userId and org params have been set just fine. Stepping through the next lines, I see that the registrationToken has the correct submitted hidden input value, and the last setRenderParameter() call is being made.
Here's the Bizarro World part: After that last setRenderParameter() call, there is absolutely no update to the _publicRenderParameters HashMap in the ActionResponse and the token stubbornly stays un-set in the params.
I've tried multiple ways to make it work, from passing the token through a session-scoped bean we've used for holding other params; to calling setRenderParameter() later in the code flow (still using the same ActionResponse reference); to using a different key name ("registrationToken") on the call, just in case "token" was some kind of reserved name or something. Nothing has gotten this last call to actually update the map.
I've also Googled every combination of relevant terms I can think of, but haven't found anything like this particular issue.
Has anyone else run into this problem? I'm at my wits end why ActionResponse's param map updates fine on the first two calls but not this last one.
= Joe =
If you are trying to develop a login type of portlet, then you might want to look at the jsf2-login-portlet demo.
Got in touch with one of my team members this morning, he saw the problem right away. Note that when I was debugging, I saw the user ID and organization values being set in the ActionResponse's _public_render_params Map. That was actually the key. My token value was being set, but I was looking in the wrong member variable. The value was set as a private render param in the ActionResponse's _params Map.
The actual fix was to add a public render param definition in the portlet.xml, and then make that new public render param supported in the above portlet along with the next one in the sequence.
Under the <portlet-app> tag I needed:
<public-render-parameter>
<identifier>registrationToken</identifier>
<qname xmlns:x="http://liferay.com/pub-renderparams">x:registrationToken</qname>
</public-render-parameter>
Then in the relevant <portlet> tag I had to add:
<supported-public-render-parameter>registrationToken</supported-public-render-parameter>
I used "registrationToken" rather than token just for clarity. Once that was done, I updated the setRenderParam() call to use key "registrationToken" instead of "token", and everything started to work as expected.

How to forward a request to non-JSF page in action method?

I want to forward request to a non-JSF page from JSF action method.
I am using below code in my JSF action :
public String submitUserResponse() {
// ...
parseResponse("foo.jsp", request, response);
// ...
return "nextpage";
}
private String parseResponse(String uri, HttpServletRequest request, HttpServletResponse response) {
if (uri != null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(uri);
dispatcher.forward(request, response);
return null;
}
// ...
return "xxxx";
}
The submitUserResponse() action method is being called when user clicks the submit button from the JSF page and this method returns nextpage string. Here the request forwards to next JSF page in normal flow. But in my requirement, I need to forward request to next non-JSF page. It is going, but it is displaying below exception in server.
java.lang.IllegalStateException: Cannot forward after response has been committed
I observed that code lines between parseResponse(...) and return "nextpage"; are still being executed after forwarding my request using dispatched.forward(uri). Same thing happened with response.sendRedirect(url). How is this caused and how can I solve it?
Here my doubts are: 1.why next lines of code is being executed after forwarding my request using dispatched.forward(uri) . Same thing happening in response.sendRedirect("").
Because you didn't call return to jump out of the method block. The include(), forward() or sendRedirect() really doesn't have some magic that they automagically does that. Those are still just Java methods like any other (except of System#exit() of course). They will be invoked in order and the code will just continue until end of method block or return statement. It's just all about the code flow you write and control yourself.
That said, the normal JSF practice is that you should use ExternalContext#dispatch() or ExternalContext#redirect() for this (the first is applicable in your case). Not only it keeps your code free from unnecessary "under-the-hood" clutter in JSF code such as the Servlet API, but it also removes the need to call FacesContext#responseComplete() which you could also have done to fix your initial IllegalStateException problem.
In a nutshell: replace your code by
public void submitUserResponse(){
String uri = "foo.jsp";
FacesContext.getCurrentInstance().getExternalContext().dispatch(uri);
}
That's all. No need to unnecessarily dig the Servlet request/response from under the JSF hoods. Note that the method is declared void. This is perfectly acceptable, although some know-it-better like IDE's will complain about it, if so, then just ignore it or replace by String and add return null;.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
ExternalContext.dispatch() not working
This worked for me:
FacesContext.getCurrentInstance().getExternalContext().dispatch("/ServletUrl");
(pay special attention to the fwd slash '/')

Resources