I have a class library project , in which i need to access session and cookies .
So I am trying to use like
public WebContext getContext(){
WebContext ctx = null;
ctx = WebContextFactory.get();
return ctx;
}
But all i get is null in WebContextFactory.get() this statement .
This class library is added to JSP project which invoke this method from a servlet.
I am new to JAVA , so cannot think of much options.
Answear taken from WebContextFactory.get() always returns null
The problem is this when a request comes in for DWR, it's handled by the dwr servlet/controller which sets the proper info inside the WebContext to use in that request (ThreadLocal as said below). If you are accessing WebContext outside a normal DWR request, the WebContext isn't setup for > that thread so it's empty.
There were a few messages in the forum about this same issue, but I don't remember the details. At any rate, you should try to use the ServerContextFactory instead of the WebContextFactory if you're going to access DWR from a non-DWR request. It might be what you need.
See if this helps you get to bottom of the problem.
Related
Background
I have a java.lang.Thread that runs inside an application on a web server (JBoss or WebSphere) at a specific time, without human interaction, and all it does is send out an email. The contents of the email are similar to the contents of a JSP (/jsp/Report.jsp) we use as a display in a web view.
Instead of duplicating the same work or changing the JSP to a static class both can access, I would like to grab the contents of the run of the JSP from inside the thread and place it in the email for sending.
I have the current ServletContext from using a listener in the "web.xml". My current JSP call in the thread is like:
servletContext.getRequestDispatcher("/jsp/Report.jsp").include(dummyRequest, dummyResponse);
And the request/response classes are basically created like this:
final HttpServletRequest dummyRequest = new HttpServletRequest() { .... }
final HttpServletResponse dummyResponse = new HttpServletResponse() { .... }
I was going to set additional attributes (Classes) to the JSP via the dummyRequest like "dummyRequest.setAttribute(name, value)".
Whenever I make the call, I get exceptions because the dummy request/response is an anonymous class of HttpServletResponse/HttpServletRequest.
WebSphere Application Server 7.0.0.17:
java.lang.RuntimeException: SRV.8.2: RequestWrapper objects must extend ServletRequestWrapper or HttpServletRequestWrapper
JBoss AS 7.1.1:
java.lang.ClassCastException: my.test.thread$1$2 incompatible with javax.servlet.ServletRequestWrapper
And I can't create a HttpServletResponseWrapper/HttpServletRequestWrapper without an original request/response.
Question
So.... Is it possible to grab the contents of a JSP from inside a Thread on a web application using the context?
If so, how do I go about doing it?
Update
Here is the code I am using for my test: link
Research
I've now started diving into the server's source code to try and get a clue what is going on.
JBoss
In ApplicationDispatcher, "forward" does nothing since the "DISPATCHER_TYPE" attribute isn't set in the request (seen in the method processRequest). This isn't required for "include".
The problem I get with "incude" about the incompatible type is inside "ApplicationFilterFactory.createFilterChain". The Request object isn't the right class it is looking for, which in JBoss' case is either "org.apache.catalina.connector.Request" or "org.apache.catalina.connector.RequestFacade". It won't continue at all unless the request matches one of these types.
So when I use the following request:
final HttpServletRequest dummyRequest = new org.apache.catalina.connector.RequestFacade(new org.apache.catalina.connector.Request() { ... });
It successfully runs and returns the results of the JSP from inside the thread.
Websphere
I have not been able to produce the same results on Websphere.
Websphere requires an instance of "com.ibm.ws.webcontainer.srt.SRTConnectionContextImpl" and then manipulating the ServletContext to its original class "com.ibm.wsspi.webcontainer.facade.ServletContextFacade", but then I get stuck on an "access$200" null pointer exception inside "com.ibm.ws.webcontainer.srt.SRTServletRequest$SRTServletRequestHelper", which makes it seem like I am breaking Java somehow.
java.lang.NullPointerException at com.ibm.ws.webcontainer.srt.SRTServletRequest$SRTServletRequestHelper.access$200(SRTServletRequest.java:2629)
This is my current code:
SRTConnectionContext n = new SRTConnectionContextImpl();
(((SRTServletRequest) (n.getRequest())).getRequestContext())
.setCurrWebAppBoundary((WebApp) ((ServletContextFacade) context)
.getIServletContext());
servletContext.getRequestDispatcher("/jsp/Report.jsp").include(n.getRequest(), n.getResponse());
The End
Hopefully someone can find a way to accomplish this on Websphere.
From my viewing of the source, unless there is a side method I am missing, you cannot run a include/forward without the server's own specific class files for the request. Even request wrappers are unwrapped to their base classes, and that is why I was always getting the Class Cast Exception with and without a wrapper.
If there isn't a cleaner, not server specific with server classes, method of getting the results of a JSP from inside a thread, than this may be the answer to my original question, regardless of how messy it seems.
because the dummy request/response is an anonymous class of
HttpServletResponse/HttpServletRequest.
No. you get classcast exception b/c they are different container expects wrapper.. your code is providing request/response.
It is not very clear to us where exactly you are making call to create dummy HttpServletRequest/Response.. looks like from where you are calling... you actually need to instantiate ServletRequestWrapper/responseWapper object, set you request on it if you have a handle, and work with it.
May be this can help
http://hc.apache.org/ to read the html out of your jsp/response and create email out of it.
I'm creating a GWT application that will be accessed by a POST request, which contains parameters I care about (user id, etc.).
All the reading I've done so far has led me to believe that I should create a servlet (I'm using tomcat) that will handle the POST parameters and then forward to my GWT application. I've gotten this working, but I'm still having trouble passing this data to my application. I've seen 3 suggested approaches:
Save data to context: I have this working right now, but I'm not happy with it. When the servlet is accessed, I parse the parameters and update the context of my GWT web application and then forward to the application where I make an RPC call to read the context. This does what I want it to, but this creates a race condition when multiple users try to access the application at the same and the context is rapidly changing.
Store data in session: I've tried saving the data to the request session in my servlet, and then accessing the session in my RPC, but I always get a new/different session, so I assume I'm mucking this up somewhere.
Save session on servlet
HttpSession session = request.getSession();
session.setAttribute("test", "testValue");
response.sendRedirect(response.encodeRedirectURL("/GWT_Application"));
Access session in RPC
HttpSession session = this.getThreadLocalRequest().getSession();
session.getAttribute("test");
This returns a different session, which results in the "test" attribute being null.
Pass data in URL: My application will be opened in an iframe, meaning Window.location.getParameter() will not be usable.
Any help would be greatly appreciated! I'm still learning GWT and web development in general so don't be afraid to call me out on any obvious or silly mistakes.
Thanks!
SOLUTION
I figured out what the issue was with my session approach: the servlet in which I was previously trying to save the session data was in a separate tomcat web app from my GWT application. Moving them to the same web app solved my problems and it now works. I'm not sure, but I'm guessing that this was a problem because redirecting to another web app switches the context. I'll outline my whole approach in the hopes this saves someone else some time later:
Put your servlet code in the server folder of your GWT project:
package GWTApplication.server;
public class myServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
session.setAttribute("myAttribute", request.getParameter("myParam");
// handle rest of POST parameters
response.sendRedirect(response.encodeRedirectURL("/GWTApplication");
}
}
Map servlet in your GWT application's web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>GWTApplication.myServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
This servlet should now be accessible at .../GWTApplication/myServlet
Next make a standar RPC. Within whatever method you will be calling in the ServiceImpl class on the server:
HttpSession session = this.getThreadLocalRequest().getSession();
return session.getAttribute("myAttribute");
Finally, make your RPC call in the onModuleLoad() method of you GWT application. As a recap:
Send the original POST request to the servlet
Save POST parameters to session variables
Redirect to GWT application
Make RPC call in onModuleLoad()
Read session variables in ServiceImpl class
You can talk with servlets through RPC call in GWT
You need to make a RPC call in the starting point of GWT application.
Set that data to serverside session and get the session data in servceImpl call of GWT which extends to RemoteServiceServlet.
Example :
YourServiceImpl extends RemoteServiceServlet {
#ovveride
doGet(){
//you can access session here
}
#ovveride
doPost(){
//you can access session here
}
#ovveride
doPut(){
//you can access session here
}
----your other methods
}
A brief Example I wrote here:How to make an GWT server call(GWT RPC?)
Since RemoteServiceServlet extends HttpServlet, you can just override doPost() method to access your POST requests. Don't forget to call super.doPost() EDIT: This doesn't work because the method is finalized in AbstractRemoteServiceServlet so it cannot be overridden.
Also, GWT Servlets POST data using the proprietary GWT RPC format. Read more about that format and how to interpret it here: GWT RPC data format
EDIT
There are several methods you can override in your ServiceImpl class that extends RemoteServiceServlet:
public String processCall(String payload) will give you a String representation of the incoming request.
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) will give you a RPCRequest object that has an array of parameters, along with the method that was called.
public void service(ServletRequest request, ServletResponse response) will give you all the Attributes of the HTTP request.
I have a perfectly working demo server/client apps pair using Spring (only!) -- no CXF or WSDL involved. It runs with the help of Apache Tomcat 7.0.34.
I was curious to see whether I can see any trace to its presence on a browser (http://localhost:8080/) but I couldn't find any hint to a URL in the source code (copied verbatim from a tutorial).
I then found this thread which provided a way to get the endpoint's URL:
TransportContext tc = TransportContextHolder.getTransportContext();
WebServiceConnection wc = tc.getConnection();
URI uri = wc.getUri();
I added this to my demo/tutorial client's code and while the first statement (getTransportContext()) doesn't throw any exception, it returns null and so the second one (getConnection()) throws a NullPointerException .
Why?
Do "pure" Spring based servlets lack endpoint URLs?
If not, what am I missing? What is the way to retrieve the service's URL?
I know that the client knows about the server by means of the context path and the bean id (as defined in the shared beans.xml):
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext( new String[] {"/sample/spring/beans.xml" } );
But isn't there a URL equivalent to this? Like WSDLs do?
I agree with #GreyBeardedGeek's comment, there's no concept of endpoint URL on Spring web-app (java servlet web-app in general).
If you do need to runtime lookup what URL the user used to reach your app, you can use ServletRequest / HttpServletRequest methods such as getRemoteAddr(), getRemoteHost(), getURL(), getContextPath() etc. Eg:
#RequestMapping("/home")
public String home(HttpServletRequest req) {
String host = req.getRemoteHost();
// ...
}
However keep in mind multiple URL can point to the same tomcat server, eg if a reverse proxy / DNS CName is setup. And that might (or not) yield different URL for you.
I've been intermixing JSPs and Servlets in the web app I'm building and I'm starting to find that my more complex JSPs end up containing a lot of code, which flies in the face of all the MVC lessons that have been pounded into me. I know I can do this by just forwarding to the JSP, but this seems like a stupid hack.
What I'd like to do is use a servlet to do processing and then send a set of values to the JSP to render the HTML and return the response. Something along the lines of:
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// ... Do some processing
resp.getWriter.print(renderJSP("mypage.jsp", values));
}
}
I've been poking around Sun's documentation and found this: http://java.sun.com/developer/technicalArticles/javaserverpages/servlets_jsp/
It seems like the JSP Model 2 architecture is exactly what I want to implement, but I cannot find an example of how one can set that up. For technical reasons, I cannot use one of the more advanced template frameworks like Struts.
Is this possible or a lost cause?
Put the object(s) in the request, forward the request to the jsp page and then use the object(s) in the jsp to render the response.
In your servlet,
MyObject obj = ... //build somehow
request.setAttribute("myObject", obj);
RequestDispatcher rd = request.getRequestDispatcher("WEB-INF/jsp/my.jsp");
rd.forward(request, response);
If your result JSP should not be accessed directly from a URL you should hide it inside the WEB-INF directory where it can be accessed only through the forward directive.
Then on your jsp you can have,
<% MyObject obj = (MyObject) request.getAttribute("myObject"); %>
To retrieve the object and used it as needed.
As others suggested, eventually it would be a good idea to learn to use JSTL and maybe an MVC framework like Spring MVC. The tutorial can be found here.
Put Java objects in the Request/Response/Session and use a javax.servlet.RequestDispatcher in your servlet, something like that:
RequestDispatcher dispatcher = request.getRequestDispatcher("/test.jsp");
dispatcher.forward(request,response);
A forward is server-side and the target servlet/JSP receives the same request/response objects as the original servlet/JSP. Therefore, you can pass data between them using request.setAttribute().
The other option is to use response.sendRedirect(String location) which is client-side (this method sends a temporary redirect response to the client) so the location URL receives a new request from the client, and the only way to pass data is through the session or with web parameters (url?name=value).
This is basically what MVC frameworks do (and no, it's not a hack).
You describe forwarding to the JSP as a hack, but really, that's exactly what the MVC frameworks do (Spring MVC and Struts, at least).
The "model" is the request attributes, which the servlet populates; then the JSP just retrieves them to show. You can wrap that in a "ModelAndView" like Spring MVC does, but it's really about it.
You can get more sophisticated on the JSP, of course, parsing request parameters, session attributes or servlet context ("global") attributes. I've found, in general, it's cleaner to let the front controller/servlet marshall all those into request attributes and have the page just pull from them. If you're using JSTL, the difference between request and session can be even blurrier.
I would like to know if there is some way to share a variable or an object between two or more Servlets, I mean some "standard" way. I suppose that this is not a good practice but is a easier way to build a prototype.
I don't know if it depends on the technologies used, but I'll use Tomcat 5.5
I want to share a Vector of objects of a simple class (just public attributes, strings, ints, etc). My intention is to have a static data like in a DB, obviously it will be lost when the Tomcat is stopped. (it's just for Testing)
I think what you're looking for here is request, session or application data.
In a servlet you can add an object as an attribute to the request object, session object or servlet context object:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String shared = "shared";
request.setAttribute("sharedId", shared); // add to request
request.getSession().setAttribute("sharedId", shared); // add to session
this.getServletConfig().getServletContext().setAttribute("sharedId", shared); // add to application context
request.getRequestDispatcher("/URLofOtherServlet").forward(request, response);
}
If you put it in the request object it will be available to the servlet that is forwarded to until the request is finished:
request.getAttribute("sharedId");
If you put it in the session it will be available to all the servlets going forward but the value will be tied to the user:
request.getSession().getAttribute("sharedId");
Until the session expires based on inactivity from the user.
Is reset by you:
request.getSession().invalidate();
Or one servlet removes it from scope:
request.getSession().removeAttribute("sharedId");
If you put it in the servlet context it will be available while the application is running:
this.getServletConfig().getServletContext().getAttribute("sharedId");
Until you remove it:
this.getServletConfig().getServletContext().removeAttribute("sharedId");
Put it in one of the 3 different scopes.
request - lasts life of request
session - lasts life of user's session
application - lasts until applciation is shut down
You can access all of these scopes via the HttpServletRequest variable that is passed in to the methods that extend from the HttpServlet class
Depends on the scope of the intended use of the data.
If the data is only used on a per-user basis, like user login info, page hit count, etc. use the session object
(httpServletRequest.getSession().get/setAttribute(String [,Object]))
If it is the same data across multiple users (total web page hits, worker threads, etc) use the ServletContext attributes. servlet.getServletCongfig().getServletContext().get/setAttribute(String [,Object])). This will only work within the same war file/web applicaiton. Note that this data is not persisted across restarts either.
Another option, share data betwheen contexts...
share-data-between-servlets-on-tomcat
<Context path="/myApp1" docBase="myApp1" crossContext="true"/>
<Context path="/myApp2" docBase="myApp2" crossContext="true"/>
On myApp1:
ServletContext sc = getServletContext();
sc.setAttribute("attribute", "value");
On myApp2:
ServletContext sc = getServletContext("/myApp1");
String anwser = (String)sc.getAttribute("attribute");
Couldn't you just put the object in the HttpSession and then refer to it by its attribute name in each of the servlets?
e.g:
getSession().setAttribute("thing", object);
...then in another servlet:
Object obj = getSession.getAttribute("thing");
Here's how I do this with Jetty.
https://stackoverflow.com/a/46968645/1287091
Uses the server context, where a singleton is written to during startup of an embedded Jetty server and shared among all webapps for the life of the server. Can also be used to share objects/data between webapps assuming there is only one writer to the context - otherwise you need to be mindful of concurrency.