I have a simple question, but I'm searching for longer time, but I always found the same answers,which i don't really know how to handle...
i want to get the IP adress of the client, when he registers to my application...
i found something like this:
#ManagedBean(name="testController")
#SessionScoped
public class TestController implements Serializable {
private static final long serialVersionUID = -3244711761400747261L;
protected final HttpServletRequest req;
public TestController(HttpServletRequest req) {
this.req = req;
System.out.println(this.req.getRemoteAddr().toString());
}
}
but i don't have the HttpServletRequest in the constructor....
or i don't know how to use it, all i get are errors....
It's available by the ExternalContext#getRequest().
public TestController() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
System.out.println(request.getRemoteAddr());
}
Note that you're making one major conceptual mistake in your initial attempt. You're attempting to assign the current HTTP request as a property of a session scoped managed bean. The HTTP request instance will expire by the end of the current HTTP response and thus not be valid anymore and throw exceptions in all colors when you try to access its methods in the subsequent requests following the initial request when the session scoped bean was been created.
I'd go for a different approach, also used in the Seam Solder project: Make a servlet filter that captures the servlet request and makes it available via an application scoped producer. See corresponding source code of the solder project.
Related
This post is related to an older SO Post of mine, wherein I was trying to understand the requirements of a no-args constructor by WELD.
Right now, I'm trying to figure out if there is a way in CDI to inject an #ApplicationScoped bean (#Normal) into a #Dependent scope. From what I've read from WELD, the requirements are to have a non-private no-arg constructor to be proxyable. However, I do not have control over the bean definition as it is provided by a library. My code is doing the following:
#Produces
#ApplicationScoped
#Named("keycloakAdmin")
public Keycloak getKeycloakAdminClient(#Named("keycloakDeployment") final KeycloakDeployment deployment) {
String clientId = deployment.getResourceName();
Map<String, Object> clientCredentials = deployment.getResourceCredentials();
// need to set the resteasy client connection pool size > 0 to ensure thread safety (https://access.redhat.com/solutions/2192911)
ResteasyClient client = new ResteasyClientBuilder().connectionPoolSize(CONNECTION_POOL_SIZE).maxPooledPerRoute(CONNECTION_POOL_SIZE)
.defaultProxy("localhost",8888)
.build();
KeycloakBuilder builder = KeycloakBuilder.builder()
.clientId(clientId)
.clientSecret((String) clientCredentials.get(CredentialRepresentation.SECRET))
.realm(deployment.getRealm())
.serverUrl(deployment.getAuthServerBaseUrl())
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.resteasyClient(client);
return builder.build();
}
// error thrown here that cannot inject #Normal scoped bean as it is not proxyable because it has no no-args constructor
#Produces
#Dependent
#Named("keycloakRealm")
public RealmRepresentation getKeycloakRealm( #Named("keycloakAdmin") final Keycloak adminClient ){
// error thrown here that cannot inject #Normal scoped bean as it is not proxyable because it has no no-arg
return adminClient.realm(resolveKeycloakDeployment().getRealm()).toRepresentation();
}
The problem is that I do not control the Keycloak bean; it is provided by the library. Consequently, I have no way of providing a no-argument constructor to the bean.
Does this mean it is impossible to do? Are there any workarounds that one can use? This would seem like a significant limitation by WELD, particularly when it comes to #Produceing 3rd party beans.
My goal is to have a single Keycloak bean for the application as it is thread-safe and only needs to be initialized once. However, I want to be able to inject it into non-application-scoped beans.
There is a #Singleton scope which may address my issue, but if #Singleton works for this case, what is the purpose of the 2 different scopes? Under what circumstances would one want a non-proxied singleton (#Singleton) vs a proxied one (#ApplicationScoped)? Or is #Singleton for the entire container, whereas #ApplicationScoped for the application (WAR) only instead? How does it apply to an EAR or multiple ears?
I'm having trouble working out how to correctly handle automatic destruction of a session in JSF. Of course, at this time, the session gets invalidated by the container, resulting in #PreDestroy methods being called on the session scoped beans as well.
At PreDestroy of some session scoped beans, we're unregistering some listeners, like below:
#PreDestroy
public void destroy() {
getWS().removeLanguageChangeListener(this);
}
However, the getWS() method actually attempts to get a reference to another session scoped bean, but that fails, as FacesContext.getCurrentInstance() returns null.
The latter appears to be normal JSF behaviour, according to Ryan Lubke:
We're true to the specification here. I'm not sure it's safe to assume
that the FacesContext will be available in all #PreDestroy cases.
Consider session scoped beans. The session could be timed out by the
container due to inactivity. The FacesContext cannot be available at
that time.
Fine by me, but how should one then make sure all objects are correctly cleared? Is it bad practice to remove self as listener in PreDestroy?
Or would we only have to do this for request/view scoped beans, as they live less long than the session scope of WS (from getWS() ) ?
Note that I get this behaviour on Tomcat7, but I expect this problem happens on every container.
I think session beans are cleaned in a dedicated thread on a servlet container and thus are outside of FacesContext (which is associated with a JSF Request). You could use HttpSessionListener to overcome the problem and cleanup session resources. Something like:
#WebListener
public class LifetimeHttpSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(final HttpSessionEvent e) {
// create some instance here and save it in HttpSession map
HttpSession session = e.getSession();
session.setAttribute("some_key", someInstance);
// or elsewhere in JSF context:
// FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("some_key", someInstance);
}
#Override
public void sessionDestroyed(final HttpSessionEvent e) {
// get resources and cleanup them here
HttpSession session = e.getSession();
Object someInstance = session.getAttribute("some_key");
}
}
Hope this can be helpful for you
I have 2 #SessionScoped beans in my small application. Even when I restart of clean the server, all of the form values are retained.
#ManagedBean(name = "bill")
#SessionScoped
public class Bill implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String MANAGED_BEAN_NAME = "bill";
/**
* #return the current instance of Bill
*/
public static Bill getCurrentInstance() {
return (Bill) FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get(MANAGED_BEAN_NAME);
}
//other methods
}
#ManagedBean
#SessionScoped
public class TailorTip implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Bill bill;
private Participants[] participants;
private Integer participantIndex;
#PostConstruct
public void init() {
bill = Bill.getCurrentInstance();
}
//other methods
}
How do I avoid the retention of values? Note: I use tomcat.
This is indeed fully expected. Many servers save and restore sessions on restart, so that the endusers can continue with their website sessions. This is under the covers achieved by Java serialization. That's also exactly the reason why session scoped beans needs to implement Serializable.
As to the solution, there are several ways to fix this:
Put the bean in the right scope for the job. Are you absolutely sure that they need to be session scoped? Isn't the view scope a better fit for those beans, after all? The session scope is usually only used for client-specific information, such as logged-in user, its preferences, etc, and thus not for form data. Your apparent urgent need to clear them on every server restart confirms that the session scope is the wrong choice. See also How to choose the right bean scope?
Get rid of Serializable interface declaration in the class. This way they'll fail to be revived on server restart.
Tell Tomcat to not revive sessions on server restart. Edit context.xml to add a <Manager> element with an empty pathname to the <Context> element.
<Context ... >
<Manager pathname="" />
</Context>
See also:
JSF managed bean causing java.io.NotSerializableException during Tomcat deployment
If they're session scoped, then many servers retain session information across restarts. If you redeploy the application, then the information will be cleared. But simply restarting the application will not reset it. You'd have to consult your servers documentation to disable session persistence across server restarts.
I am writing an Jersey Response filter. I am using Jersey 1.17. I want to get access to some attributes of the httpServletRequest in the filter API. The way what i am doing right now is as below. Is it safe to inject the servletRequest like in the snippet below or will this cause some kind of concurrency issues? If there are multiple requests coming in conncurrently, will the servletRequest in different requests overwrite each other? Thanks for your hlep.
public class LoggingFilter implements ContainerResponseFilter {
#Context private HttpServletRequest servletRequest;
#Override
public ContainerResponse filter(final ContainerRequest req, final ContainerResponse resp) {
String s = this.servletRequest.getAttribute("xxx");
....
}
}
Section 9.1 (latest, 5.1 previously) Concurrency of the JAX-RS specification states:
Context is speciļ¬c to a particular request but instances of certain
JAX-RS components (providers and resource classes with a lifecycle
other than per-request) may need to support multiple concurrent
requests. When injecting an instance of one of the types listed in
Section 9.2, the instance supplied MUST be capable of selecting the
correct context for a particular request. Use of a thread-local proxy is a common way to
achieve this.
So, as per the specification, JAX-RS implementations (e.g. Jersey) are required to ensure that the context is safe. Keep doing what you're doing.
See also: Extract request attributes from container request of Jersey
You're safe. When you're injecting HttpServletRequest / HttpServletResponse you're not dealing with a particular instance but rather with a proxy through which you're invoking calls on a real instance stored in a ThreadLocal object. Each request is processed by a separate thread which has access to it's own HttpServletRequest / HttpServletResponse. Beside injecting HttpServletRequest / HttpServletResponse you can also inject ThreadLocal<HttpServletRequest> / ThreadLocal<HttpServletResponse> and through '#get()` method you can obtain the real request / response instances intead of proxies.
Continuing on my previous question, I'm trying to initialize a session-scoped JSF bean when the application's session first starts, so the bean will be available to a user, regardless of which page they access on my web application first. My custom listener:
public class MyHttpSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent se) {
if (FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.get("mySessionBean") == null) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.put("mySessionBean", new MySessionBean());
}
}
}
However, this is giving me a stack overflow error. It appears that the put() method in the SessionMap class tries to create a new HttpSession, thus causing an infinite loop to occur with my listener. How can I initialize a JSF session-scoped bean when my application's session first starts, without running into this issue?
I'm using JSF 2 with Spring 3, running on WebSphere 7.
Thanks!
The session isn't been fully finished creating at that point. Only when the listener method leaves, the session is put into the context and available by request.getSession() as JSF's getSessionMap() is using under the covers.
Instead, you should be grabbing the session from the event argument and use its setAttribute() method. JSF lookups and stores session scoped managed beans just there and won't create a new one if already present.
public void sessionCreated(HttpSessionEvent event) {
event.getSession().setAttribute("mySessionBean", new MySessionBean());
}
Note that I removed the superfluous nullcheck as it's at that point impossible that the session bean is already there.
Unrelated to the concrete problem, you should actually never rely on the FacesContext being present in an implementation which isn't managed by JSF. It is quite possible that the session can be created during a non-JSF request.