I need access to the ServletContext to use the getRealPath() method on some files that are in my WEB-INF directory. However, the class I need to do this work in is a non-CDI class that is used for some backend processing based on a request made earlier from JAX-RS. How can I get the ServletContext outside of the lifecycle of the JAX-RS request?
I'm using Wildfly 10, if that changes the way I would go about this
The trick is to load a servlet at the startup of the Java EE application, see #WebServlet annotation. The Servlet.init() method is invoked upon startup of the container, which we will leverage to work with ServletContext, in this case calling getRealPath() and storing returned value into static variable. You may access the value from the rest of your app by calling RealPathServlet.getRealPath().
#WebServlet(value="/real-path", loadOnStartup=1)
public class RealPathServlet extends HttpServlet {
private static String realPath;
public void init(ServletConfig config) throws ServletException {
super.init(config);
realPath = config.getServletContext().getRealPath("yolo");
Logger.getLogger(ContextPathServlet.class.getName()).info("Real path is " + realPath);
}
public static getRealPath() {
return realPath;
}
...
}
Related
Building Spring Boot application, deploying(by copying to webapps folder while Tomcat is down) to local Tomcat8. Always get an error:
No thread-bound request found:
Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet:
In this case, use RequestContextListener or RequestContextFilter to expose the current request.
As I understand, problems are while instantiating bean with WebAuthenticationDetails extending:
#Component
public class AuthDetails extends WebAuthenticationDetails{
private final AuthTarget authTarget;
public AuthDetails(HttpServletRequest request) {
super(request);
this.authTarget = AuthTarget.valueOf(request.getParameter("target"));
}
public AuthTarget getAuthTarget(){
return this.authTarget;
}
}
It cannot provide HttpServletRequest for bean constructing, but I don't know how to evade it.
Tried to add RequestContextListener, in xml or as implementation(and marking as #WebListener), no effect.
Out of ideas, how to fix it. Tried example from here: https://github.com/Baeldung/spring-security-registration , no changes - same error at the similar place.
Any help is greatly welcome.
The key was simple: I should define filter bean explicitly in security configuration extends WebSecurityConfigurerAdapter:
#Bean
AuthFilter authFilter() throws Exception{
AuthFilter authFilter = new AuthFilter();
return authFilter;
}
instead of autowiring it.
The docs state that if I'm not within a servlet calling thread, but still want to make use of UriComponentsBuilder (eg in a batch import), I could use ServletUriComponentsBuilder.fromCurrentContextPath().
#see https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-uri-building
I tried as follows from the docs:
public String createUrl() {
UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
return uri.toString();
}
For testing a non-servlet call:
#PostConstruct
public void init() {
builder.createUrl();
}
But always getting the exception:
Caused by: java.lang.IllegalStateException: Could not find current request via RequestContextHolder
at org.springframework.util.Assert.state(Assert.java:392) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.web.servlet.support.ServletUriComponentsBuilder.getCurrentRequest(ServletUriComponentsBuilder.java:190) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromCurrentContextPath(ServletUriComponentsBuilder.java:158) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]
So what might be wrong here?
The documentation you mentioned clearly stated that the static methods are for use in a Servlet environment:
In a Servlet environment the ServletUriComponentsBuilder sub-class
provides static factory methods [...]
So if you're not in said Servlet environment, you need to use plain UriComponentsBuilder:
UriComponentsBuilder.newInstance().scheme("http").host("example.com")
Which would fit into your code as
public String createUrl() {
UriComponentsBuilder base = UriComponentsBuilder.newInstance().scheme("http").host("example.com").path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
return uri.toString();
}
The reason behind this is that in a servlet environment you can get access to scheme and host and context path by querying the Servlet / ServletContext and so on. Running outside of a webapp, this information (scheme, host, context path) need to come from someplace else.
I have an existing Web Application (Servlet) that remotely accesses an EJB currently written to the EJB 2.1 Specification (EJBHome, EJBObject, SessionBean, all configuration in ejb-jar.xml). The servlet access the EJB via JNDI lookup, the JNDI name being specified in weblogic-ejb-jar.xml.
I would like to update the EJB to EJB3.0, which will (hopefully) make it easier to add to the API.
My issue is that I need to do it with a minimum of change to the existing servlet code. In other words, I still need to:
Access the EJB with a simple, global JNDI name (it is stored in a database, and the servlet can can change the name it looks up on the fly), and
Be able to use the 2.1 style:
String jndiName = getJndiName(); // e.g. "BeanV2.0"
BeanHome home = (BeanHome) PortableRemoteObject.narrow(
jndiContext.lookup(jndiName), BeanHome.class);
BeanRemote remote = home.create();
remote.doBusiness(); // call business method
I have tried a stripped down version, applying #RemoteHome, but I keep getting errors during deployment.
I am deploying (for development/production) on Weblogic, mostly 10.3.5 (11gR1), and am limited to EJB 3.0. I am using Eclipse (with the Oracle Weblogic Pack) for development.
Thanks.
I would suggest you to first understand the architectural difference between EJB2.1 and EJB3.x (refer here)
You will have some major/minor changes in code based on your bean implementation and client side invocation, because of the removal of Home and Deployment Descriptor in EJB3.x
Refer this example for accessing EJB3.x from a client, in your case Servlet
/**
* Servlet implementation class SampleServlet
*/
public class SampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public SampleServlet() {
super();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Context ctx=getInitialContext();
String jndiName=getJndiName(); // eg. java:global/BeanProject/Bean!demo.BeanRemote
BeanRemote beanRemote = (BeanRemote)ctx.lookup(jndiName);
remote.doBusiness();
} catch(Exception exception) {
System.out.println(exception.getMessage());
}
}
private static Context getInitialContext() throws Exception
{
Properties properties=new Properties();
properties.put("java.naming.factory.initial","org.jboss.naming.remote.client.InitialContextFactory");
properties.put("java.naming.provider.url","remote://localhost:4447");
return new InitialContext(properties);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Hope this helps!
I'm working on some Java EE application which has to find some data in HashMap. The problem is that I want to load this HashMap to Tomcat only once - when Tomcat starts and I don't know how to do this. Could you give me some tips?
I suppose you want to load HashMap actually before when your web application start.
The ServletContextListener is what you want. It will make your code run before the web application is start.
Assuming that you want to load this HashMap only for one web application you can do it when container loads all settings for your app (after it reads web.xml file). To do this you can create class which implements ServletContextListener.
In its contextInitialized method create HashMap you are interested in, and add it as attribute to ServletContext. There can be only one ServletContext instance for one web application and this instance is available to all servlets/jsp so they can later get that attribute with map you set earlier.
Example:
class ContextListenerImpl implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent sce) {
//can be empty for now
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
//... here you can create and initialize your HashMap
//when map is ready add it as attribute to servlet context
sc.setAttribute("mySpecialMap", map);
}
}
You can get this map in servlets like
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//...
Map<Your,Types> map = (Map<Your,Types>) getServletContext()
.getAttribute("mySpecialMap");
//...
}
Oh, and one important thing: lets not forget to add this listener to your web application. So you will have to add
<listener>
<listener-class>full.name.of.ContextListenerImpl</listener-class>
</listener>
to your web.xml file.
I have this code,
#WebServlet(value="/initializeResources", loadOnStartup=1)
public class InitializeResources extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("HEREEEE");
}
}
But the servlet doesn't start when the web application is started.
How use load on startup on Servlet Annotation?
My Servlet API is 3.0 and I use Tomcat 7
With you current code, you need to do a GET request for see the output HEREEEE.
If you want to do something on the startup of the servlet (i.e. the element loadOnStartup with value greater or equal to zero, 0), you need put the code in a init method or in the constructor of the servlet:
#Override
public void init() throws ServletException {
System.out.println("HEREEEE");
}
It may be more convenient to use a listener to start a resource in the application scope (in the ServletContext).
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class InitializeListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("On start web app");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("On shutdown web app");
}
}
For an example, see my answer for the question Share variables between JAX-RS requests.
#WebServlet(name="InitializeResources", urlPatterns="/initializeResources", loadOnStartup=1)
urlPatterns to be ensure that the web conatainer finds the servlet path.
When loadOnStartup is specified for a Servlet, the container would only load and pre-instantiate an instance of your Servlet ready to process any GET/POST requests that may come. This by itself wouldn't cause doGet() or doPost() to get fired because an actual client request hasn't come for processing yet. So, what's its use then?
Well, loadOnStartup is typically used for Servlets that have heavy initialization code; say, they may make a JNDI call to get hold of a resource or a Database call to populate a local data structure with some backend values. In the absence of loadOnStartup the very first client request could be painfully slow because of all this extra initialization stuff and hence pre-instantiating it makes sense.
Now, your custom initialization code (JNDI, JDBC) would go in an overriden GenericServlet#init() method which is called by the servlet container to indicate to a servlet that it's being placed into service.