something awful is happening
i have 2 servlets in my project - one of them simply has a post method and is responsible for handling file uploads. i recently added the other one - it has a get and a post method.
here is the 2nd servlet code
#Singleton
#WebServlet("/Medical_Web")
public class XXXDetailsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject
private Provider<XXXPersistenceManager> persistenceManager;
#Inject
private Provider<XXXChain> chainProvider;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("servlet address = " + this);
final String xxx= request.getParameter("xxx");
String json = "";
try {
final XXXBean xxxBean = persistenceManager.get().find(xxx);
json = new GsonBuilder().create().toJson(xxxBean);
} catch (Exception ex) {
ex.printStackTrace();
}
request.setAttribute("json", json.trim());
getServletContext().getRequestDispatcher("/XXX.jsp").forward(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("servlet address = " + this);
final String xxx = request.getParameter("xxx");
try {
final XXXChain chain = chainProvider.get();
chain.getContext().setAttribute(XXX_TYPE, XXXType.DELETE);
final XXXBean xxxBean = persistenceManager.get().find(xxx);
final List<XXXBean> xxxList = new ArrayList<XXXBean>();
xxxList.add(xxxBean);
chain.process(xxxList);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
now - here's whats getting me
for some reason - even though this is marked as a #Singleton - the servlet addresses are definitely coming back as different. I noticed this initially when I hit a null pointer in my post method - whenever i call the get method, the instance of the servlet i get back has all the fields populated. whenever i call the post method, the instance of the servlet i get back (it is a different instance) does not have the fields populated (just null, seems like they didn't get injected).
I'm really struggling to figure out what's going on here. it seems as if an instance of this servlet was created outside of the guice context. if it matters - we are using JBoss 7.1
(sorry about all the XXX's, don't know if i can post actual names)
here's the rest of my guice setup
public class XXXServletContextListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new XXXUploadModule(), new XXXServletModule());
}
}
and here's the servlet module
public class XXXServletModule extends ServletModule {
#Override
protected void configureServlets() {
serve("/xxx1").with(XXXDetailsServlet.class); // this one fails on post
serve("/xxx2").with(XXXUploadServlet.class); // this one works
}
}
I am not familiar with how Guice servlet integration works, but having the #WebServlet("/Medical_Web") annotation means that your web container will also instantiate that servlet to serve requests. A pool of them actually, it doesn't have a concept of singletons.
My guess is you just have to remove the annotation and let ServletModule control the servlet life-cycle.
Related
This question was already asked, however since then all answers (that I could found) are no longer valid.
Essentially I want to implement a website with Vaadin (V23), that communicates with a WebApp via POST requests that is running on another server (physically). To do it, I want to create separate Servlet that would handle the communication (receiving side) with another Server. Let's say, this is not implemneted version:
#WebServlet(urlPatterns = "/communication", name = "QuizServlet", asyncSupported = true)
public class QuizServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
}
The problem is however, that I always get redirected to default dispatcher Servlet, and it seems, regardless of what I do:
SpringVaadinServlet was deprecated and no longer exists, extending VaadinServlet does not work.
Changing mappings in properties (vaadin.url-mapping=) also does not work, I just get redirected to this new mapping in all cases.
Trying to do servlets on separate ports yields same redirection on all ports, even if explicitly registering my custom Servlet on the Connector, with separate Sevice (WebMvcConfigurer Tomcat configuration). Answer from this post, also too old.
Registering servlet directly also does not do anything (by implementing WebApplicationInitializer).
There for the question, how to make use of two different servlets with new Vaadin 23 and Spring Boot 2.7.1?
I have found some kind of a solution to my problem. Namely on startup of my BootAplication, I am also starting the second separate Tomcat server that uses my custom Servlet :
#Service
public class QuizServer {
private final Log log = LogFactory.getLog(QuizServer.class);
#PostConstruct
public void startServer() throws IOException, LifecycleException {
start();
}
private void start() throws IOException, LifecycleException {
Tomcat tomcat = new Tomcat();
String contextPath = "/";
String appBase = new File(".").getAbsolutePath();
Context ctx = tomcat.addContext(contextPath, appBase);
Tomcat.addServlet(ctx, "quizServlet", new QuizServlet());
ctx.addServletMappingDecoded("/*", "quizServlet");
tomcat.setPort(8085);
tomcat.start();
tomcat.getConnector();
log.info("Quiz server started");
}
}
#WebServlet(urlPatterns = "/*", name = "quizServlet", asyncSupported = true)
public class QuizServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("Test");
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(400, "Not implemented");
}
}
It is a bit crude though, since ideally, it shouldn't require a separate server.
I'm working on an application that's using a OncePerRequestFilter to do some custom log-like behavior using the incoming web request. This behavior uses both the HttpServletRequest & HttpServletResponse. Additionally, the filter uses both ContentCachingRequestWrapper & ContentCachingResponseWrapper to access the request/response bodies.
It's been decided that we only want to do this behavior when methods in particular Spring controllers have been called, since it's not something we want to do for other controllers/actuator endpoints/etc. Is there a way to tell whether the incoming request will be (or was) mapped to a controller?
public class ExampleFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Can I tell here whether this will be mapping to an endpoint in
// ExampleController or NestedExampleController?
ContentCachingRequestWrapper requestToUse = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseToUse = new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(requestToUse, responseToUse);
// Can I tell here whether this was mapped to an endpoint in
// ExampleController or OtherExampleController?
} finally {
responseToUse.copyBodyToResponse(); // Write the cached body back to the real response
}
}
}
#RestController
#RequestMapping("/example")
public class ExampleController {
#GetMapping("/{id}")
public Example retrieveExample() {
return getValue(); // Retrieve the value
}
// ...
}
#RestController
#RequestMapping("/example/{id}/nested")
public class NestedExampleController {
#GetMapping("/{nestedId}")
public NestedExample retrieveNestedExample() {
return getValue(); // Retrieve the value
}
// ...
}
I've dug around the Spring MVC/Boot internals a bit, and I'm not sure if there's a way to easily do this. As an alternative, I can do some manual URL pattern matching, which probably won't necessarily exactly match up to the methods in the controllers, but may get me close enough to be an acceptable solution.
To summarize: is there a way in a web filter to tell whether the incoming request will be mapped to a controller (prior to executing the filter chain) or whether it was mapped to a controller (after executing the filter chain)?
What you want is basically a cross-cutting concern that targets a specific part of your application - in this case, logging.
This is one of the most common use-cases for aspect-oriented programming, for which Spring has built-in support using AspectJ-style pointcuts.
You will need:
To enable AOP within your Spring configuration on a configuration class, as follows:
#Configuration
#EnableAspectJAutoProxy
public class AopConfiguration {
}
Define an aspect, e.g. as follows:
#Aspect
public class LoggingAspect {
Logger log = ...; // define logger
// Matches all executions in com.example.ExampleController,
// with any return value, using any parameters
#Pointcut("execution(* com.example.ExampleController.*(..))")
public void controllerExecutionPointcut() {}
#Around("controllerExecutionPointcut()")
public Object aroundTargetControllerInvocation(ProceedingJoinPoint pjp) {
log.debug("About to invoke method: {}", pjp.getSignature().getName());
try {
return pjp.proceed();
} catch (Throwable t) {
// note that getArgs() returns an Object[],
// so you may want to map it to a more readable format
log.debug("Encountered exception while invoking method with args {}", pjp.getArgs());
throw t;
}
log.debug("Sucessfully finished invocation");
}
}
See e.g. this guide to learn more about pointcut expressions.
Another common use-case for this is timing your method calls, although for that something like Micrometer (and the Micrometer adapter for Spring) using #Timed would probably be better.
You may also wish to read through the reference documentation, which devotes quite a lot of information on how AOP in Spring works.
Note: as will almost all other Spring proxying mechanisms, invocations from within the target object will not be proxied, i.e. this.otherControllerMethod() will not be subject to interception by the above advice. Similarly, private methods also cannot be intercepted. See section 5.4.3 of the reference documentation for more information.
As a last note, if performance is of great importance, you should check out AspectJ compile-time or load-time weaving, which gets rid of some of the overhead introduced by Spring's proxying mechanism (which is what Spring AOP uses under the hood). This will most likely not be necessary in your case, but is good to keep in mind.
Edit for comment:
Thanks! One caveat with this approach is that it does not give me access to the HttpServletRequest or HttpServletResponse, which is something I'm making use of. I can see where this would be helpful if that wasn't something I needed. I see that I wasn't explicit about that requirement in my question, so I'll update accordingly.
Indeed, that is unfortunately not directly possible with this approach. If you really need the request, then the HandlerInterceptor approach mentioned by #DarrenForsythe is another possible to go. If all you're going for is logging though, I see no reason why you absolutely need the request - unless you wish to extract specific headers and log those.
In that case, IMO, a OncePerRequestFilter as you originally tried would be far better, as you can control for which requests the filter gets applied (using shouldNotFilter(HttpServletRequest request) and matching on the URL).
After some additional poking around and some trial and error, I discovered that the controller is accessible through the RequestMappingHandlerMapping bean. When the request can be handled by a controller, this will map the request to a HandlerMethod for the controller's request handling method.
public class ExampleFilter extends OncePerRequestFilter {
private RequestMappingHandlerMapping requestMappingHandlerMapping;
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Object handler = getHandlerBean(request);
boolean isHandledController = handler instanceof ExampleController
|| handler instanceof NestedEampleController;
if (!isHandledController) {
filterChain.doFilter(request, response);
return;
}
// ...
}
private Object getHandlerBean(HttpServletRequest request) {
try {
HandlerExecutionChain handlerChain = requestMappingHandlerMapping.getHandler(request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
if (handler instanceof HandlerMethod) {
return ((HandlerMethod) handler).getBean();
}
}
return null;
} catch (Exception e) {
return null;
}
}
#Override
protected void initFilterBean() {
WebApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
requestMappingHandlerMapping = appContext.getBean(RequestMappingHandlerMapping.class);
}
}
To be extra thorough and truly mimic Spring's handler logic, the DispatcherServlet logic could be used/mimicked instead of directly referencing RequestMappingHandlerMapping. This will consult all handlers, not just the RequestMappingHandlerMapping.
public class ExampleFilter extends OncePerRequestFilter {
private DispatcherServlet dispatcherServlet;
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Object handler = getHandlerBean(request);
boolean isHandledController = handler instanceof ExampleController
|| handler instanceof NestedEampleController;
if (!isHandledController) {
filterChain.doFilter(request, response);
return;
}
// ...
}
private Object getHandlerBean(HttpServletRequest request) {
try {
HandlerExecutionChain handlerChain = getHandler(request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
if (handler instanceof HandlerMethod) {
return ((HandlerMethod) handler).getBean();
}
}
return null;
} catch (Exception e) {
return null;
}
}
/**
* Duplicates the protected "getHandler" method logic from DispatcherServlet.
*/
private HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
List<HandlerMapping> handlerMappings = dispatcherServlet.getHandlerMappings();
if (handlerMappings != null) {
for (HandlerMapping mapping : handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
#Override
protected void initFilterBean() {
WebApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
dispatcherServlet = appContext.getBean(DispatcherServlet.class);
}
}
I'm not sure if there is a more idiomatic approach, and it definitely feels like it's jumping through some hoops and digging into the Spring internals a bit too much. But it does appear to work, at least on spring-web 5.2.7.RELEASE.
I have two classes Server (with the main method, starting the server) and StartPageServlet with a Servlet.
The most important part of the code is:
public class Server {
public static void main(String[] args) throws Exception {
// some code
// I want to pass "anObject" to every Servlet.
Object anObject = new Object();
Server server = new Server(4000);
ServletContextHandler context =
new ServletContextHandler(ServletContextHandler.SESSIONS);
context.addServlet(StartPageServlet.class, "/");
// more code
}
And the StartPageServlet:
public class StartPageServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Here I want to access "anObject"
}
How do I do this?
Embedded Jetty is so wonderful here.
You have a few common options:
Direct instantiation of the servlet, use constructors or setters, then hand it off to Jetty via the ServletHolder (can be any value or object type)
Add it to the ServletContext in your main, and then access it via the ServletContext in your application (can be any value or object type).
Examples:
package jetty;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class ObjectPassingExample
{
public static void main(String args[]) throws Exception
{
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
// Option 1: Direct servlet instantiation and ServletHolder
HelloServlet hello = new HelloServlet("everyone");
ServletHolder helloHolder = new ServletHolder(hello);
context.addServlet(helloHolder, "/hello/*");
// Option 2: Using ServletContext attribute
context.setAttribute("my.greeting", "you");
context.addServlet(GreetingServlet.class, "/greetings/*");
server.setHandler(context);
server.start();
server.join();
}
public static class HelloServlet extends HttpServlet
{
private final String hello;
public HelloServlet(String greeting)
{
this.hello = greeting;
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/plain");
resp.getWriter().println("Hello " + this.hello);
}
}
public static class GreetingServlet extends HttpServlet
{
private String greeting;
#Override
public void init() throws ServletException
{
this.greeting = (String) getServletContext().getAttribute("my.greeting");
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/plain");
resp.getWriter().println("Greetings to " + this.greeting);
}
}
}
Singleton
You want to pass the same single instance to each servlet?
Use the Singleton pattern to create a single instance that is available globally.
The simplest fool-proof way to do that in Java is through an Enum. See Oracle Tutorial. Also see this article and the book Effective Java: Programming Language Guide, Second Edition (ISBN 978-0-321-35668-0, 2008) by Dr. Joshua Bloch.
So no need to pass an object. Each servlet can access the same single instance through the enum.
Per web app
If you want to do some work when your web app is first launching but before any servlet in that web app has handled any request, write a class that implements the ServletContextListener interface.
Mark your class with the #WebListener annotation to have your web container automatically instantiate and invoke.
I had a similar situation but needed to share a singleton with a servlet deployed via war with hot (re)deploy in a Jetty container. The accepted answer wasn't quite what I needed in my case since the servlet has a lifecycle and context managed by a deployer.
I ended up with a brute-force approach, adding the object to the server context, which persists for the life of the container, and then fetching the object from within the servlet(s). This required loading the class of the object in a parent (system) classloader so that the war webapp doesn't load its own version of the class into its own classloader, which would cause a cast exception as explained here.
Embedded Jetty server code:
Server server = new Server(8090);
// Add all classes related to the object(s) you want to share here.
WebAppContext.addSystemClasses(server, "my.package.MyFineClass", ...);
// Handler config
ContextHandlerCollection contexts = new ContextHandlerCollection();
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] { contexts });
server.setHandler(handlers);
// Deployer config (hot deploy)
DeploymentManager deployer = new DeploymentManager();
DebugListener debug = new DebugListener(System.err,true,true,true);
server.addBean(debug);
deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
deployer.setContexts(contexts);
deployer.setContextAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
WebAppProvider webapp_provider = new WebAppProvider();
webapp_provider.setMonitoredDirName("/.../webapps");
webapp_provider.setScanInterval(1);
webapp_provider.setExtractWars(true);
webapp_provider.setConfigurationManager(new PropertiesConfigurationManager());
deployer.addAppProvider(webapp_provider);
server.addBean(deployer);
// Other config...
// Tuck any objects/data you want into the root server object.
server.setAttribute("my.package.MyFineClass", myFineSingleton);
server.start();
server.join();
Example servlet:
public class MyFineServlet extends HttpServlet
{
MyFineClass myFineSingleton;
#Override
public void init() throws ServletException
{
// Sneak access to the root server object (non-portable).
// Not possible to cast this to `Server` because of classloader restrictions in Jetty.
Object server = request.getAttribute("org.eclipse.jetty.server.Server");
// Because we cannot cast to `Server`, use reflection to access the object we tucked away there.
try {
myFineSingleton = (MyFineClass) server.getClass().getMethod("getAttribute", String.class).invoke(server, "my.package.MyFineClass");
} catch (Exception ex) {
throw new ServletException("Unable to reflect MyFineClass instance via Jetty Server", ex);
}
}
#Override
protected void doGet( HttpServletRequest request,
HttpServletResponse response ) throws ServletException, IOException
{
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello from MyFineServlet</h1>");
response.getWriter().println("Here's: " + myFineSingleton.toString());
}
}
My build file for the servlet (sbt) placed the my.package.MyFineClass dependency into the "provided" scope so it wouldn't get packaged into the war as it will already be loaded into the Jetty server.
I would recommend that you investigate Google's solution to this problem... namely: dependency injection with Guice. They have a special servlet package that deals with servlets specifically.
We have unmanaged extension. We implemented custom communication API between server and client.
Now we need to ensure that client and server have same API version.
One solution - verify version in each resource. But this approach is messy and leads to code duplication.
What we want is to implement our own Filter and add it to Neo server.
Is this possible? If yes - then how?
This is possible!
Approach is a bit tricky and fragile, but it's working (blog post).
Dependency
You need neo4j-server dependency, because it contains SPIPluginLifecycle that is needed to get access to Neo4j web server.
So, add to your pom.xml:
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${version.neo4j}</version>
</dependency>
Filter
Create your filter. Let's take this one for example:
public class CustomFilter implements Filter {
public CustomFilter() {
}
#Override
public void init(final FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(final ServletRequest request,
final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
#Override
public void destroy() {}
}
This filter doesn't do anything usefull - just continue chain further.
Lifecycle plugin
Now tricky part. We need to:
Implement SPIPluginLifecycle
Get web server
Add filter to web server
Code:
public final class ExtensionPluginLifecycle implements SPIPluginLifecycle {
private WebServer webServer;
private CustomFilter customFilter;
#Override
public Collection<Injectable<?>> start(final NeoServer neoServer) {
webServer = getWebServer(neoServer);
addFilters();
}
#Override
public void stop() {
removeFilters();
}
#Override
public Collection<Injectable<?>> start(final GraphDatabaseService graphDatabaseService,
final Configuration config) {
throw new IllegalAccessError();
}
private WebServer getWebServer(final NeoServer neoServer) {
if (neoServer instanceof AbstractNeoServer) {
return ((AbstractNeoServer) neoServer).getWebServer();
}
throw new IllegalArgumentException(String.format("Expected: [AbstractNeoServer], Received: [%s].", neoServer));
}
private void addFilters() {
customFilter = new CustomFilter();
webServer.addFilter(customFilter, "/extension-path/*");
}
private void removeFilters() {
webServer.removeFilter(customFilter, "/extension-path/*");
}
}
Tricky part is not so "legal" access to web server. This can break in future, so be carefull.
Note addFilters() and removeFilters() methods - this is why we have been done all this way.
Important: lifecycle plugin should be registered as service:
// file: META-INF/services/org.neo4j.server.plugins.PluginLifecycle
my.company.extension.ExtensionPluginLifecycle
Servlets runs in several threads, so my question is:
If I have a lot of servlets which call some utility class (DbUtils, for example
Connection c = DbUtils.getConnection();
//....some action with db here
should I assume additional actions for synchronization inside DbUtils?
Actually I'd like to inherit HttpServlet into something like DatabaseInvokerServlet:
public abstract class DatabaseInvokerServlet extends HttpServlet
with methods:
public abstract void getResultSets(Connection connection) throws SQLException;
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
protected void processData() {}
protected void afterRequestProcessed() throws ServletException, IOException {}
protected void beforeRequestProcessed() throws ServletException, IOException {}
protected void execute() {
Connection c = null;
try {
c = DbUtils.getConnection();
getResultSets(c);
processData();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (c != null) {
c.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public HttpServletRequest getRequest() {
return request;
}
public HttpServletResponse getResponse() {
return response;
}
public AbstractUser getCurrentUser() {
return currentUser;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
this.request = request;
this.response = response;
this.currentUser = (AbstractUser) request.getSession().getAttribute("currentUser");
}
Then I'd just inherit my DatabaseInvokerServlet to new servlets to do custom stuff. The reason is not to copy-paste database invoke block with try-catch-finally in a lot of places.
But as I can see such approach won't work because of synchronization issues. Am I right?
If the DbUtils creates the connection in the same thread, like as:
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
Then it's threadsafe.
But if the connection is a class variable, like as:
private static Connection connection = DriverManager.getConnection(url, username, password);
public static Connection getConnection() throws SQLException {
return connection;
}
Then it is definitely not threadsafe because the same connection will be shared among all threads. Also when it's closed in a thread, all subsequent threads won't be able to use the connection because it's not open anymore. Also when it's never closed, the DB will timeout the connection sooner or later, usually after a few hours, and your application won't work anymore because the connection is not open anymore.
As to the servlet,
public abstract class DatabaseInvokerServlet extends HttpServlet {
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
// ...
}
it's definitely not threadsafe. You're assigning the current user, request and response as instance variables. From each servlet class, there is only one instance during the application's lifetime. This instance is shared among all visitors/sessions throughout the entire application's lifetime. Each HTTP request operates in a separate thread and uses the same instance.
Imagine two simultaneous visitors: visitor A will set the current user, request and response. The DB process however takes a long time. Before the response of visitor A has returned, visitor B calls the same servlet and thus the current user, request and response will be overriden. Then, the query of visitor A finishes and wants to write to the response, it is instead writing to the response of visitor B! Visitor B sees the result of the query of visitor A and visitor A sees nothing on his screen!
You should never assign request/session-specific data as instance variable of the servlet. You should keep them method (thread) local.
public abstract class DatabaseInvokerServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AbstractUser currentUser = request.getSession().getAttribute("user");
// Keep the variables in the method block!
// Do not assign them as instance variable!
}
}
As to the complete picture, this approach is clumsy. The database access layer should have nothing to do with servlets. It should operate in its own standalone classes which you could just construct/invoke in every other Java class, any servlet class, or a normal application with main(), or whatever. You should not have any single line of java.sql.* imports in your servlet classes (expect of maybe SQLException if it is not abstracted away). You should not have any single line of javax.servlet.* imports in your database classes.
See also:
Servlet instantiation and (session) variables
Basic DAO tutorial
If the utility class has state (example: class or instance variables) most probably yes.
If I guess right the DBUtils is returning new instance for each call of getConnection(). And as the DBUtils class is a utility class so it shouldn't be maintaining any state. In this scenario no you dont need any addition efforts for synchronization.
Servlets runs in several threads.
The J2EE spec says there is only one instance per servlet class running in one web container for non single thread servlet.
Servlet 2.3 specs
A servlet container may send
concurrent requests through the
service method of the servlet. To
handle the requests the developer of
the servlet must make adequate
provisions for concurrent processing
with multiple threads in the service
method.
Synchronisation in servlet.
Never have an member variable in a servlet, it is not thread safe.