Marking application without web.xml distributable for Tomcat session replication - java

I have Spring based application and using programmatic approach (AbstractAnnotationConfigDispatcherServletInitializer) for app configuration.
To make tomcat session replication work I need to 'mark' app distributable using <distributable/> tag in web.xml, however as I mentioned I am using programmatic style, e.g.
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
String activeProfile = activeProfile();
if (isNotEmpty(activeProfile)) {
servletContext.setInitParameter("spring.profiles.active", activeProfile);
}
super.onStartup(servletContext);
}
}
I can't find any docs about how to do it using Spring configs, so my question here is that, Is it possible to have distributable app without having web.xml? I can't move all configs to the web.xml, so any help is appreciated.

There are several option you cannot set from Java based configuration, one of them is <distributable /> another is the error-pages.
For that you still need a web.xml, just create an as empty as possible web.xml and only include <distributable />. Everything else can remain in Java based configuration.
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<distributable />
</web-app>

This appears to already be answered here... Mixing web.xml and AbstractAnnotationConfigDispatcherServletInitializer in Spring
Unless I am misunderstanding the question/answer.

It is not possible to configure the Cluster programmatically using Spring. One solution is to have a mix of XML and Java based configuration. So that the Web.xml entries can be maintained.
An example is here to do this.

Related

Spring Boot Datasource JNDI lookup on Websphere 9

I have a Spring Boot application that I usually deploy on a Tomcat server. Now I want to be able to also deploy it on Websphere 9, though it will still be deployed on the usual Tomcat server most of the time. I packaged the app as a war and deployed it on Websphere through the admin interface, then ran the application. And as pointed out in many other posts, it did not work because JNDI lookup does not work the same way. I tried solutions offered here and there, but nothing worked.
My datasource is defined in Websphere with name jdbc/foobar. My lookup is done in my Spring Boot app with:
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource ds = dataSourceLookup.getDataSource("java:comp/env/jdbc/foobar");
This works on Tomcat but does not on Websphere. Many answers on other SO posts about this say that for Websphere, one must lookup "jdbc/foobar" without the prefix (for instance here in the answer's comments), which is true (I could get it to work), but I want to have code that remains compatible with the usual deployment on tomcat.
As a side note, the getDataSource method automatically adds the prefix if it is absent, which means I needed to do this instead:
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
dataSourceLookup.getJndiTemplate().getContext().lookup("jdbc/foobar");
This still is useful because, since it worked well, it proved that my problem is not a wrong datasource definition at server side.
Since I want my code to remain the same tomcat-compatible code, I kept the "java:comp/env/jdbc/foobar" lookup and I looked into the answers advising to add some configuration, most notably this one. I located the ibm-web-bnd.xml file, which is created by Websphere at deployement time and put in the WEB-INF folder. I added the advised resource-ref tag there:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://websphere.ibm.com/xml/ns/javaee"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_0.xsd" version="1.0">
<virtual-host name="default_host"/>
<resource-ref name="jdbc/foobar" binding-name="jdbc/foobar" />
</web-bnd>
Then, since I don't have a web.xml in my war, I tried the #Resource trick:
#Component
#Resource(name = "jdbc/foobar",type = javax.sql.DataSource.class)
public class MyServlet extends HttpServlet {
I could verify the servlet is loaded correctly but the Resource annotation does no seem to do the trick. Then I noticed a web.xml is also created by Websphere beside the ibm-web-bnd.xml file, so I supposed I might give it a try and I added the resource-ref tag inside (the rest was already here, added by Websphere):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<env-entry>
<env-entry-name>logback/context-name</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>main</env-entry-value>
</env-entry>
<listener>
<listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
</listener>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<resource-ref>
<description />
<res-ref-name>jdbc/foobar</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</web-app>
This still did not work. I also noticed that Websphere created another file named web_merged.xml, which seems to merge the automatically created web.xml with the real one (which in my case does not exist). I tried to add the same code shown above to this file too, but it did not work better.
Now, I am out of clue. Does someone have any other idea, or maybe noticed an obvious mistake I made?
What you tried in the bindings file looks like it should have worked, assuming that you are performing the lookup from within the same web module in which you specified the binding (because it is java:comp scoped).
Even so, you ought to be able to do this in a completely standard way without a bindings file at all (where it can be difficult to get all of the syntax correct), by just using the #Resource annotation alone,
#Resource(name = "java:comp/env/jdbc/foobar", lookup = "jdbc/foobar", type = javax.sql.DataSource.class)
I'd recommend getting rid of the extra bindings/deployment descriptor that you were experimenting with and try with just the annotation, at least to start with. If it turns out that you aren't in the same module, you could use java:app (if in the same app) or otherwise java:global instead of java:comp, which you would need to update in both places.

Application property "server.servlet.session.timeout" is not working in Spring Boot project

According to the documentation of Spring Boot, session timeout can be configured by setting
server.servlet.session.timeout= 300s
in application.properties file. In this post and in Spring Boot documentation it is also said so. But unfortunately this is not working for me.
Is there any other configuration to get expected result?
You can use
Approach 1:
server.servlet.session.timeout=30s
server.servlet.session.cookie.max-age=30s
It is working fine for me
A possible cause for this problem might be using #EnableRedisHttpSession. As explained in this answer:
By using #EnableRedisHttpSession you are telling Spring Boot that you want to take complete control over the configuration of Redis-based HTTP sessions. As a result, its auto-configuration backs off and server.servlet.session.timeout has no effect. If you want to use server.servlet.session.timeout then you should remove #EnableRedisHttpSession. Alternatively, if you want to use #EnableRedisHttpSession then you should use the maxInactiveIntervalInSeconds attribute to configure the session timeout.
Hope this helps someone.
I am posting answer because this scenario is new for me. And I haven't got proper solution step by step.
According to the suggestion of M. Deinum I created a web.xml file under WEB-INF folder. Project structure is like
src
|_ main
|_ java
|_ resources
|_ webapp
|_ WEB-INF
|_ web.xml
And in web.xml I configured <session-timeout>...</session-timeout>
My web.xml is like
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<session-config>
<session-timeout>5</session-timeout>
</session-config>
</web-app>
And now session time of my webapp in server is working according to my configuration. Thanks goes to M. Deinum
Use HttpSessionListener.
server.servlet.session.timeout only works for embedded container.
#Configuration
public class MyHttpSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent event) {
event.getSession().setMaxInactiveInterval(30);
}
}
Follow the below solution.
Set the session time out in application.properties file like below.
server.servlet.session.timeout=01m
Specify the invalid session URL in WebSecurityConfiguration file like below
http.sessionManagement().invalidSessionUrl("/sessionexpired");
Configure the session expired mapping in controller class like below
#RequestMapping(value = "/sessionexpired", method = RequestMethod.GET)
public ModelAndView sessionexpired(HttpServletRequest request,
HttpServletResponse response) {
return new ModelAndView("sessionexpired");
}
spring doc
The latest version of SpringBoot is using the following properties.
server.servlet.session.timeout=30m

Tomcat: Servlet Mapping vs. WebServlet Annotation

There are two ways for servlet mapping.
The first is in web.xml:
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>com.whatever.foo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>foo</servlet-name>
<url-pattern>/foo</url-pattern>
</servlet-mapping>
The second method uses the WebServlet annotation:
#WebServlet("/foo")
public class foo extends HttpServlet {
...
}
Which one is better? Where are the advantages of the first and the second way?
Provided that you're sure that you're using Tomcat 7 or newer, the webapp's web.xml has to be declared conform Servlet 3.0 spec in order to get Tomcat to scan and process the annotations. Otherwise Tomcat will still run in a fallback modus matching the Servlet version in web.xml. The support for servlet API annotations was only added in Servlet 3.0 (Tomcat 7).
So, the root declaration of your web.xml must look like below (make sure you remove any DOCTYPE from web.xml too, otherwise it will still be interpreted as Servlet 2.3!).
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
Further, there's a minor difference in the URL pattern. The URL pattern /notifications will let the servlet only listen on requests on exactly that path. It does not kick in on requests with an extra path like /notifications/list or something. The URL pattern /notifications/* will let the servlet listen on requests with extra path info as well.
The minimum #WebServlet annotation should thus look like this
#WebServlet("/notifications/*")
The rest of attributes are optional and thus not mandatory to get the servlet to function equally.
What is benefit of using java based config instead of web.xml for servlet 3.x?
It avoids repeating yourself, and making mistakes by doing so. The servlet class is, for example, com.foo.bar.SomeServlet. Using web.xml, you're forced to re-enter this class in web.xml:
<servlet-class>com.foo.bar.Someservlet</servlet-class>
But wait, you've made a typo and you'll only discover it at runtime.
Or you rename a servlet class, but you forget to rename it in the web.xml as well, and you only discover the mistake at deployment time.
Finally, they make our life easier. You're creating a servlet, and you obviously want to map it to some URL. So you just add an annotation. No need to go to another file to add the mapping, then go back to the class because you forgot its exact name, then go back to the file again. Everything regarding a servlet is in the servlet class. Same for a filter, listener, etc.
Annotations don't have all these problems.
I hope this helps you!
XML configuration :
advantages :
All mappings are in the same location, you have an overview of all of them in one single file.
disadvantages :
Needs a separate file in addition to the class files.
Annotation configuration :
advantages :
The mapping is described directly inside the relevant class.
disadvantages :
You have to open a particular class to see its mappings.

include-prelude not being picked from web.xml using Spring 4

Hi I'm putting together a fairly basic app using spring 4 MVC. I am using config java classes rather than xml config. I'm pretty new to this but all is slowly moving forward well. I have hit a problem though in that I wanted to include a header into all the jsp page views.
So I have included the include-prelude into my web.xml file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Web Application</display-name>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<include-prelude>/WEB-INF/views/include/header.jspf</include-prelude> </jsp-property-group>
</jsp-config>
</web-app>
This is working if I add a dummy jsp file into the webapp folder (I'm using maven and eclipse) and access it directly. However it is not working for the JSP's accessed via spring MVC. It is working in a similar application I inherited which has the spring bootstrap config in xml files rather than java classes. I won't have millions of pages so I guess I can use a jsp:include but...
Can anyone tell me how I should go about getting the header.jspf picked up ? Ideally I'd like to keep the config in java classes but perhaps I have to use the xml bootstrapping ?
Also as a supplementary question which is not really what I'm asking so please ignore if it's against all the rules (!) when I've googled this a bit I keep reading that JSP's are no longer the way to go for views. I'm writing a fairly basic intranet forms app (I've recently switched from microsoft technologies so apologies if you don't like that terminology!). Do you think I should be using somethign other than JSPs & jspf's
Thanks
In case you are wondering what is the answer to the OP'S question, the answer is to simply add this to your web.xml tag (if you are using Tomcat instead of GlassFish):
xmlns:my="http://jakarta.apache.org/tomcat/jsp2-example-taglib"
So your web.xml should look like this at the beginning:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xmlns:my="http://jakarta.apache.org/tomcat/jsp2-example-taglib">
I hope this could helped you ;)
You can use jsp.There is no problem with that the only thing you need to change is instead of giving url-mapping like .jsp use url mapping .abc, here you can use abc,xyz,ani,spring,do etc anything rather then jsp.So it will work fine .
If you use *.jsp in url mapping and use jsp as view it will give you 404 everytime.

Java EE 5 / Servlet 2.5 inject EJB into ServletFilter

I want to inject session beans into my ServletFilter, which seems not to work. Can you please tell me how to achieve this?
public class MyExample implements Filter {
#EJB
private MyBean someEjb;
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException{
someEjb.toString();
}
}
Results in NullPointerException because myEjb is null. The platform used is JBoss 5.1
MyBean can be accessed correctly from other EJBs or from Servlets.
Thank you.
Problem Solved (though I do not know why):
The application consists of three artifacts:
- A jar containing the EJBs
- A war containing servlets
- An ear containing both the above
If i package the Filter in the jar, the problem occurs. If i package it along with the servlets in the war, the problem does not occur.
So, immediate problem solved but not understood.
Maybe someone can help me understand that?
If both the servlet and EJB are not in a single ear file, one must use #EJB(mappedName="name") while injecting EJB. Check this post for more details.
Related links: Injection from outside modules
Of course, Filter is a kinda Servlet, therefore known as "Servlet Filter". And both Servlet and Filter are web component, hence belongs to web archive, .war, not Java archive, .jar. Filter in jar will not be scanned to inject that kinda annotations and will be dealt as any other regular Java class.
We faced a similar problem, we had some #WebFilter and #WebListener components packaged inside a Jar that weren´t readed (the annotations weren´t processed).
The objetive was to tell the container to scan other jars looking for other annotated components.
We achive the goal adding the attribute metadata-complete to web.xml declaration.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false">
...NORMAL_CONTENT_HERE...
</web-app>
Hope it helps.

Categories