I want to join an existing conversation scope.
I start the conversation with:
conversation.begin(packageId);
I got close with using the following which seems to work:
#Inject #Http CoversationContext context;
context.activate(packageId);
However I'm seeing a warning in the log which suggests I'm not getting it right.
WARN: WELD-000335: Conversation context is already active, most likely
it was not cleaned up properly during previous request processing:
HttpServletRequestImpl [ POST /path/to/url ]
I'm also happy if there is an alternative way to just drop the conversation and recreate (so long as I can continue using the same custom conversation ID) I'm trying to avoid the user reloading the page multiple times filling up memory with duplicates of the same package data.
I also considered using a #SessionScoped bean but I thought if I can set the package ID to be the conversation ID then I can avoid the need to manage a #SessionScoped bean.
As long as the cid parameter is in request, and the conversation is long-running (since you did conversation.begin(packageId)) then there is no need to join a conversation context, it is already active in current request.
What you need to do however is to include the cid in every request form or in url parameters through:
e.g.
<h:link>
<f:param name="cid" value="#{javax.enterprise.context.conversation.id}"/>
</h:link>
or
<h:form>
<f:param name="cid" value="#{javax.enterprise.context.conversation.id}"/>
/h:form>
Note that the conversation must be long-running by explicitly starting it as conversation.begin(id)
Also:
At the end of your step processing, you need to explicitly call conversation.end() otherwise the conversation scoped beans will be destroyed only at the end of the session context
For book marking, then you need to include the cid parameter or any logical mapping in the path, and then use a filter to forward with the cid parameter:
#WebFilter(urlPatterns = "/*")
public class CidFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
String cid = extractCidParameterIfAny(request);
HttpServletRequest httpRequest = (HttpServletRequest) request;
if (cid != null) {
String forwardUrl = buildForwardUrlWithCidParameter(cid);
HttpServletRequest wrapper = new CidHttpServletRequest(httpRequest);
httpRequest.getRequestDispatcher(forwardUrl).forward(wrapper, response);
} else {
chain.doFilter(request, response);
}
}
}
Related
I have 2 java classes and I want to transfer data between them.
I take user id as parameter in a previous jsp form, and in a java class, using setAttribute I create a atribute named st_id.
then in another java clas I want to retrieve this data, but I get null.pointer exception.
first java file;
public class Signin implements Action {
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
Student stu = new StDAO().getUser(request.getParameter("st_id").toString());
request.setAttribute("st_id", request.getParameter("st_id").toString());
...
second;
public class addCourseStu implements Action{
#Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
TakeCourseDAO pf = new TakeCourseDAO();
String s= (String) request.getAttribute("st_id");
So s is null, it's not my intention.
A request exists from the time the web browser sends it to the web server until the web server (via the servlet) has made its response.Every request for a servlet has its own accessibilty scope. From a servlet, you can:
add new attributes to the request's scope
obtain exisiting attributes from the request's scope
remove exisiting attributes from the request's scope
As you are getting null it is quite obvious that the attribute is not accessed within the scope.
You can try alternatives like Session scope or Application scopes which ever suits you
It is not entirely clear what you want to do but I gather that you want to maintain some state on the server between two requests right?
Look into sessions & cookies for this.
What you do here is weird as it seems you are setting an attribute on an incoming request in the first file.
I'm having a JavaEE Website running on a cloud-platform.
Now I want to use two types of authentications:
Is from an SSO-System, which is well integrated in the platfrom and works very nicely.
Is the problematic part: I want to authorize a user from 1) for the time of a session, and give him access to a more restricted resource.
Some details
I get the user and his data from 1).
The user first has to ask for permission to 2), which can be denyed or granted. A user gets authorization from a service, which is outside of the scope of his servlet.
For this purpose I pass a User-POJO (with the session of this user as a member) to a service.
If the service grants the rights to this user, it will set an attribute to the user session:
userSession.setAttribute("auth", "granted");
To restrict access to that resource I use a Filter:
#WebFilter("/supersecret/*")
public class NiceFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
// check
if (session.getAttribute("auth") != "granted")
// redirect to login
else
chain.doFilter(req, res);
}
//...
While this is currently working, I feel that my solution is very sloppy.
Altering the user-session outside the scope of a servlet seems to be bad practice.
Adding an attribute to the session for security-purposes is probably not a good idea?
I'd rather want to use standard JavaEE-mechanisms, but most of them are already used for auth-method 1), like declaring login-config in the web.xml.
Any ideas for a more robust solution to this problem?
Thanks in advance :)
I created a spring-based Java web application,
for each request, an instance of 'controller class' will be created to handle the request.
in the business logic, I want to do some logging with a UNIQUE ID automatically assigned to each request so that I can track what the program exactly did.
the log may be like this(2 requests at same time):
[INFO] request #XXX: begin.
[INFO] request #XXX: did step 1
[INFO] request #YYY: begin.
[INFO] request #XXX: did step 2
[INFO] request #YYY: did step 1
[INFO] request #XXX: end.
[INFO] request #YYY: end.
from the log, I can realize:
req #XXX: begin-step1-step2-end
req #YYY: begin-step1-end
I hope the logging can be called easily everywhere in the code,
so I don't want to add a parameter of "requestId" to every java function,
It's perfect if the logging tool can be called in a static way:
LOG.doLog("did step 1");
any idea of how can I do this? thank you :)
You can also try using MDC class of Log4j. The MDC is managed on a per thread basis.
If you are using a ServletRequestListner then you can set the unique Id in the requestInitialized.
import org.apache.log4j.MDC;
import java.util.UUID;
public class TestRequestListener implements ServletRequestListener {
protected static final Logger LOGGER = LoggerFactory.getLogger(TestRequestListener.class);
public void requestInitialized(ServletRequestEvent arg0) {
LOGGER.debug("++++++++++++ REQUEST INITIALIZED +++++++++++++++++");
MDC.put("RequestId", UUID.randomUUID());
}
public void requestDestroyed(ServletRequestEvent arg0) {
LOGGER.debug("-------------REQUEST DESTROYED ------------");
MDC.clear();
}
}
Now anywhere in the code if you do a log either debug, warn or error. Whatever you had put in the MDC will be printed out. You need to configure you log4j.properties. Notice the %X{RequestId}. This referes to the key name which is inserted in the requestInitialized() above.
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %C %X{RequestId} - %m%n
I also found this link to be helpful -> What is the difference between Log4j's NDC and MDC facilities?
You have three different problems to solve:
Generate an unique id for each request
Store the id and access it everywhere in the code
Log the id automatically
I would suggest this approaches
Use a Servlet filter or a ServletRequestListener (as suggested by M. Deinum) or a Spring Handler Interceptor to intercept the request in a general way, there you can create a unique id, maybe with an UUID
You can save the id as an attribute of the request, in this case the id would propagate just in the controller layer, not in the services. So you can solve the problem using a ThreadLocal variable or asking Spring to do the magic with the RequestContextHolder: the RequestContextHolder will allow you to access the request of that specific thread, and the request attributes as well, in the service layer. The RequestContextHolder use ThreadLocal variable to store the request. You can access the request in this way:
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
// Extract the request
HttpServletRequest request = attr.getRequest();
There is an interesting article (2018 alternative), if you are using log4j, on the customization of the pattern layout of the logger. However, youncan simply create a proxy of your logging system interface and append manually the id to every logged string.
You can also use the "Fish Tagging" in Log4j 2. It is the same idea like MDC and NDC (thread-basis) as described in https://logging.apache.org/log4j/2.x/manual/thread-context.html
Here you can use either the Thread Context Stack or the Thread Context Map. An example for the Map looks like this:
//put a unique id to the map
ThreadContext.put("id", UUID.randomUUID().toString()
//clear map
ThreadContext.clearMap();
And for the pattern in log4j2.xml you can also use the %X{KEY} tag.
To put a new id to the map (for example for every incoming request) you can do that in an ServletRequestListener implementation how Sharadr described it.
If you don't mind using spring 4.1.3 or later, you can wrap your request into a custom subclass of ContentCachingRequestWrapper class.
public class MyHTTPServletRequestWrapper extends ContentCachingRequestWrapper {
private UUID uuid;
public MyHTTPServletRequestWrapper (HttpServletRequest request) {
super(request);
uuid = UUID.randomUUID();
}
public UUID getUUID() {
return uuid;
}
}
In your spring controller, add the request to the method's param, and cast it to your custom wrapper:
#RequestMapping(value="/get", method = RequestMethod.GET, produces="application/json")
public #ResponseBody String find(#RequestParam(value = "id") String id, HttpServletRequest request) {
MyHTTPServletRequestWrapper wrappedRequest = (WGHTTPServletRequestWrapper)request;
System.out.println(wrappedRequest.getUUID());
...
}
You will need to user filter though, to connect the dots:
public class RequestLoggingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest requestToCache = new MyHTTPServletRequestWrapper((HttpServletRequest) request);
System.out.println(((WGHTTPServletRequestWrapper)requestToCache).getUUID());
chain.doFilter(requestToCache, response);
}
}
You will find that the printlin from RequestLoggingFilter.doFilter() and from controllers getId() will produce the same UUID.
You will just need to play around to use the UUID in appropriate places, but at least you have the value in your controller where is the start of your business logic.
You could use the #Scope annotation to load a new instance of the service for each request.
See official documentation here
If you want to inject this in a non-request aware service, you should use proxyMode option. more info here (from this stack question)
You must use a database sequence (if your database is ORACLE) as follows
create sequence "sequence_Name";
String uniqueString=sessionFactory.getCurrentSession(). createSQLQuery("SELECT \"sequence_Name\".nextval FROM dual").list().get(0);
I'm using ServletRequestListener to attach to new requests, get a ServletRequest object and extract cookies from it.
I've noticed that only HTTPServletRequest has cookies but I haven't found a connection between those two objects.
Is it okay to use
HttpServletRequest request = ((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest());
to retrieve the request while in a RequestInitialized method? (I do want to run on every request)
FYI - This is all done in a JSF 1.2 Application
This is not correct. The FacesContext isn't available in a ServletRequestListener per se. The getCurrentInstance() might return null, leading to NPE's.
If you're running the webapp on a HTTP webserver (and thus not some Portlet webserver for example), you could just cast the ServletRequest to HttpServletRequest.
public void requestInitialized(ServletRequestEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
// ...
}
Note that a more common practice is to use a Filter for this since you can map this on a fixed URL pattern like *.jsf or even on specific servlets so that it runs only when the FacesServlet runs. You might for example want to skip cookie checks on static resources like CSS/JS/images.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
// ...
chain.doFilter(req, res);
}
When you happens to be already inside the JSF context (in a managed bean, phaselistener or whatever), you could just use ExternalContext#getRequestCookieMap() to get the cookies.
Map<String, Object> cookies = externalContext.getRequestCookieMap();
// ...
When running JSF on top of Servlet API, the map value is of type javax.servlet.http.Cookie.
Cookie cookie = (Cookie) cookies.get("name");
Yes, you can do that. In Web scenarios, this will always be ok. If you want to be sure, you could do a check for the type first. (Good practice anyway):
if (FacesContext.getCurrentInstance().getExternalContext().getRequest() instanceof HttpServletRequest) {
...
By the way: Why do you have to use FacesContext? From where are you calling this code?
Short question: Is it possible to do a redirection, say when a user isn't logged in, when a page is rendered?
For that you should use a Filter.
E.g.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("error.jsf"); // Not logged in, so redirect to error page.
} else {
chain.doFilter(request, response); // Logged in, so just continue.
}
}
Here I assume that the User is been placed in the session scope as you would normally expect. It can be a session scoped JSF managed bean with the name user.
A navigation rule is not applicable as there's no means of a "bean action" during a normal GET request. Also doing a redirect when the managed bean is about to be constructed ain't gong to work, because when a managed bean is to be constructed during a normal GET request, the response has already started to render and that's a point of no return (it would only produce IllegalStateException: response already committed). A PhaseListener is cumbersome and overwhelming as you actually don't need to listen on any of the JSF phases. You just want to listen on "plain" HTTP requests and the presence of a certain object in the session scope. For that a Filter is perfect.
Yes:
if(!isLoggedIn) {
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
}
You can use a PhaseListener to specify when you want to do redirection.
In a PhaseListener try:
FacesContext ctx = FacesContext.getCurrentContext();
ctx.getApplication().getNavigationHandler()
.handleNavigation(ctx, null, "yourOutcome");