Is there a way to get the Base URL from an Application-scoped bean in JSF? - jsf

In my JSF Facelets pages I know I can just use
#{request.requestURL}
To get the full URL to build exportable links and the like. However I have an #ApplicationScoped bean where I need the base URL (i.e. "http://dnsname/app") for the purposes of reports and other data. Is there a standard way to access the web-app container to get this information?

Not until the first HTTP request is fired. The domain/host/base is namely configured completely independently from the web application (on the appserver and/or proxy server, if any). If it's not an option to lazily set it as an application wide variable during the 1st HTTP request in e.g. a servlet request listener or a servlet filter or perhaps in a lazy loading getter of that application scoped bean, then you'd need to configure it externally on the web application via e.g. system property, VM argument, properties file, etc.

Related

Call REST API with jQuery from JSF page and get current session without cookies

I have a web application which uses JSF 2.3 for the front end and offers also an API which is consumed by the front end with Jersey 2.29.1 running on a Tomcat 9 server.
The front end offers a login which will store the authenticated user in a #SessionScoped AuthenticationBean. The API methods should only be consumable if the user is logged in on the front end.
#Path("/service")
public class ApiService {
#GET
#Path("/data")
#Produces(MediaType.APPLICATION_JSON)
public String loadData() {
final AuthenticationBean authBean = CDI.current().select(AuthenticationBean.class).get();
if (authBean != null && authBean.isLoggedIn()) {
// Do business logic
}
else {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
}
}
On the JSF page the API is consumed with a 'basic' jQuery AJAX call $.ajax() and updates some visual content based on the JSON response. The URL which I pass to the AJAX call is "#{request.contextPath}/api/service/data".
Everything works fine as expected, until I disable the cookies in the browser. If the cookies are disabled, the session ID is added to the URL (instead of being stored in a session cookie) by the servlet engine. So if I do not explicitly append the session ID to the URL for the AJAX call I have no access to the current session in the API service method, e.g. "#{request.contextPath}/api/service/data;jsessionid=#{session.id}" and therefore I can not check whether the user is logged in or not.
My question is now if I do have to add the jsessionid manually for every AJAX request or is there any other 'clean' possibility to pass the session ID to the service methods? Or do I have to access the session in any other way in the API service?
... explicitly append the session ID to the URL ...
The HttpServletResponse#encodeURL() does exactly that task, see also javadoc (emphasis mine):
Encodes the specified URL by including the session ID, or, if encoding is not needed, returns the URL unchanged. The implementation of this method includes the logic to determine whether the session ID needs to be encoded in the URL. For example, if the browser supports cookies, or session tracking is turned off, URL encoding is unnecessary.
So, basically:
#{request.contextPath}#{response.encodeURL('/api/service/data')}
The same method is by the way delegated by ExternalContext#encodeResourceURL().
Return the input URL, after performing any rewriting needed to ensure that it will correctly identify an addressable resource in the current application.
Jakarta Servlet: This must be the value returned by the javax.servlet.http.HttpServletResponse method encodeURL(url).
So, technically you can also do
#{request.contextPath}#{facesContext.externalContext.encodeResourceURL('/api/service/data')}
But this is a bit less convenient to type down. Moreover, using #{request.contextPath} already indicates that you're using JSF on top of servlets, not portlets, so using #{response} should be perfectly fine. You might want to make it yet shorter by defining a custom utility method in an application scoped bean. E.g.
#{functions.encodeURL('/api/service/data')}
#Named #ApplicationScoped
public class Functions {
public String encodeURL(String uri) {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
return ec.getRequestContextPath() + ec.encodeResourceURL(uri);
}
}
This 'Answer' is not an answer to your real question but an explanation on why this is in no way JSF related (at the end there is a hint though to an answer)
JSF is an api and Jersey is an implementation of an api (JAX-RS). They effectively are complementary technologies and have no relation to one another in any way. It's the same like asking can I use JPA and Jersey in one application. Your actual questions have like stated no relation to JSF whatsover. JSF uses the session mechanism provided by the servlet engine, just like jax-rs does.
The second thing that is unclear is what your definition of 'front-end' is and where you run what. JSF in the JavaEE 'stack' is a front-end technology. JSF has a server side part in which you declare the components(See What is the definition of "component" in JSF) and when the html is generated they have client side html/javascript/css counterparts which communicate with the server in a way that is specified in the JSF specs. JSF 'components' by themselves do nothing if not backed by 'glue logic' on the server that in turn calls services (See JSF Controller, Service and DAO)
It might by now be clear that
is it possible for a JSF component to have called a Jersey service by an AJAX call?
is 'vague' and most likely given by your lack of knowledge of what the JSF is/does and how Jersey fits in (Jersey should be 'rest' here or jax-rs if you mean the api), See also How to implement JAX-RS RESTful service in JSF framework
JSF Components' html part on the client side communicates with the server in a JSF specific way, so
Rest is not needed there to get the client-side to communicate with the server (superfluous)
Trying to get rest in there makes things overly (overly) complex and without a real advantage
If you are trying to get the JSF server side components to communicate via REST
The server side is for interaction with the client side by means of the JSF spec for it
They are backed by code that in turn calls services. In this you can call a rest service, database or whatever
If, like I suspect, you want a non-jsf related $.ajax to call some rest service
You totally can, but read How to implement JAX-RS RESTful service in JSF framework
You can do anything with it to update the client side html
You can even update the html generated by JSF components
When doing 3, do NOT expect them to still work al the time, JSF is not to blame here
So after all this, your session id problem is not a jsf related problem. You'd have the same problem when using plain jsp or even plain html that has triggered a session.
HINT
So a better title would have been "jsessionid in url not added to ajax call in jquery" I posted this one in a search engine and added site:stackoverflow.com: jsessionid in url not added to ajax call in jquery site:stackoverflow.com
One of the results is effectively a duplicate of your question:
Appending my jsession ID at every ajax call by Jquery

When do HTTP requests happen in managed beans (depending on their scopes)?

Does a session scoped managed bean have an HTTP request per method? How can I know when an HTTP request starts and ends?
And what's the difference for a view scoped managed bean? (still concerning the HTTP requests)
And for a request scoped managed bean, does it have only one HTTP request for the entire managed bean?
Thank you!
How can I know when an HTTP request starts and ends?
You can use Fiddler to inspect HTTP requests/responses
The HTTP protocol is what a browser uses to communicate with a web server. Specifically, the browser sends an HTTP request to the server, which sends a back an HTTP response.
Therefore, HTTP requests don't happen in a bean. At most, a managed bean may be used for processing an HTTP request on the server.
The scope of a managed bean definition controls the sharing of bean instances:
If the bean has request scope, a dedicated bean object is used for every request.
If the bean has session scope, a dedicated bean object is used for every user session (i.e. all requests from the same user are processed using the same bean object).
If the bean has view scope, a dedicated bean object is used for every JSF view (i.e. as long as the user doesn't navigate to another page, all requests are processed using the same bean object)
How can I know when an HTTP request starts and ends?
It's unclear what you mean by a request starting or ending.
But I need to get those attributes at the first request of a use case, and then for all the other requests for the same use case.And when the use case is done,I need to clear the map with those attributes.
The idiomatic way to control the lifetime of state is to keep it in a bean with suitably long scope. If your use case only has a single view, a view scoped bean would fit nicely.
Otherwise, if it is only for a few views, I'd have the view scoped beans aggregate a conversation object, and pass that conversation object to the next view scoped bean upon navigation. That way, you won't need to take any special action when the user aborts the usecase (which he can typically do in many ways, for instance by using the main navigation ...).
If you have a big application any many such multi-view usecases, you might want to check out the many libraries that offer a conversation scope.

POS payment from backing bean in JSF

I want to implement a POST call to a virtual POS for card payment proceessing. The POS is simply a server program given by the bank, and must be accesses through a form with the transaction's data. This can be done by composing a form, method post, and a set of hidden params, and then targeting the output to a new window (which is required, because from this point, the bank software takes control).
But, for security issues, I want to make the POST call from a backing bean.
Thus:
A button in my facelet calls a method in a RequestScoped bean. This bean has access to the transaction's data in session.
The bean makes some stuff.
Inside the method, I can open an URLConnection, add the params, and then call the bank's program (I assume it's a servlet).
Whatever the output of this servlet, it must be redirected to a new window in the client side. This new window will contain the authentication and real payment stuff, but it's the bank's software.
Which would be the correct pattern to implement that behavior by using JSF?
Thanks in advance.
I think I understand now, you want to integrate the bank servlet functionality in your JSF application but do not want to bother with PCI compliance.
A redirect is an HTTP server response code that specifies a url to perform a GET on so you can't redirect the response of a form POST.
You also don't want to programmatically pass this POST request to the bank servlet from the server side and render the received response because you have already initiated a seperate session with bank servlet than the session exists between the user and your web application. That is actually a serious security concern.
You can't start this Bank Servlet session through JSF unless the server is handling all HTTP communication with the bank servlet.
The way I would do this under your scenario is to use Javascript to open a new window with a regular HTML form, and set the action of the form to the bank servlet URL, and have the initial inputs of that form match the required parameter names for the HTTP post. When this HTML form is submitted, the SSL certificate is negotiated with the users browser and the POST response will be rendered without any involvement of your web application whatsoever. The client will maintain two seperate sessions, the session for your application as well as the session for the Bank Servlet.
This is the secure way to do this that doesn't put any PCI compliance requirements on your web application.

Access JSF ViewScoped managed bean from Servlet

How may I access a JSF ViewScoped managed bean from a Servlet?
(Assume that the managed bean in question has already been created, and still not been destroyed)
View-scoped variables are stored in the view map on the component tree. To access this data outside the view context you would have to create a JSF context and restore the view for the request. This involves rewriting much of the functionality provided by the JSF container.
JSF 2 provides mechanisms for interacting with server-side state without a page refresh: AJAX tags and the JSF JavaScript API. I would look at utilizing those if possible.
Alternatively, place the data into a scope that is easily accessible via servlets (the session.)
Since the view state is generally held in the session, it is likely technically possible to access the view state from here. But this would involve implementation-specific hacks that may not survive an upgrade of the underlying framework. I wouldn't even look at this as a solution.

Support multiple client websites on the same application using JSF 2.0

I have a problem similar to
proof of concept for multiple clients in JSF 2.0
Our application is deployed as a single ear file within the ROOT context in Weblogic. However we need to support multiple client websites on the same application. The client name is appended in the URL e.g. http://myApp/client1/home.jsf , http://myApp/client2/home.jsf .
There is absolutely no problem when the different URLs are accessed from different machine or even different browsers. However when accessed through different tabs in Firefox, they share the data from one application to the other because of the same JSession ID. Is there any way to use custom scoped beans that look at the client URL before creating the session beans.
Having multiple ear files for each application is not an option as we support 100+ client websites. :(
Suitable scopes for this situation are conversation, request and view. Unsuitable scopes are session and (depending on your usage) application. Although CDI doesn't have a view scope, there are a number of 3rd party implementations you can use. (View scope is handy for ajax.)
Conversation scope acts like request scope until a conversation is explicity started. Until you end the conversation, it is tied to the view in which is was initiated, so you can have multiple instances of a conversation scoped bean, one per browser window.

Resources