Within my project, I am using a property placeholder to read a property file, containing the configuration for my database connection. During my initial setup and reconfiguration at some point later I want to be able to change the details of the database host.
I tried to use the refresh() method called on the current application context, but somehow the Spring Data Beans are not reloaded and I am getting an IllegalStateException issued by Spring Data:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: open
Exception report: Message: Request processing failed; nested exception is java.lang.IllegalStateException: open description: The server encountered an internal error that prevented it from fulfilling this request. exception: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: open
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
root cause: java.lang.IllegalStateException: open
org.bson.util.Assertions.isTrue(Assertions.java:36)
com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:408)
com.mongodb.DBCollectionImpl.update(DBCollectionImpl.java:263)
com.mongodb.DBCollection.update(DBCollection.java:191)
com.mongodb.DBCollection.save(DBCollection.java:975)
com.mongodb.DBCollection.save(DBCollection.java:934)
org.springframework.data.mongodb.core.MongoTemplate$10.doInCollection(MongoTemplate.java:950)
org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:410)
org.springframework.data.mongodb.core.MongoTemplate.saveDBObject(MongoTemplate.java:945)
org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:885)
org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:833)
org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:73)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:512)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy2987.save(Unknown Source)
de.steilerdev.myVerein.server.controller.InitController.initSuperAdmin(InitController.java:158)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
Unfortunately I am not very confident with beans and their lifecycle, so I need help reloading the appropriate bean. I would also be okay with the possibility to restart the Spring application itself, even though it would be an expensive operation. Since it is only needed very rarely I would be okay with the costs of that.
I am not sure which parts of the code you need, but here is a link to the Github repository. (Sorry for the poor documentation, still at the beginning of the project)
Thanks!
Edit: Some classes involved in the process:
de.steilerdev.myVerein.server.controller.InitController (Receiving the related request, storing the settings to my SettingsRepository)
#Controller
#RequestMapping("/init")
public class InitController
{
#Autowired
private SettingsRepository settingsRepository;
#Autowired
private UserRepository userRepository;
#Autowired
private DivisionRepository divisionRepository;
#Autowired
private ReloadableResourceBundleMessageSource messageSource;
private static Logger logger = LoggerFactory.getLogger(InitController.class);
#RequestMapping(value = "settings")
public ResponseEntity<String> initSettings(#RequestParam String clubName,
#RequestParam String databaseHost,
#RequestParam String databasePort,
#RequestParam String databaseUser,
#RequestParam String databasePassword,
#RequestParam String databaseCollection,
#RequestParam String rememberMeTokenKey,
Locale locale)
{
logger.debug("Starting initial configuration");
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(clubName.isEmpty() || rememberMeTokenKey.isEmpty())
{
logger.warn("The club name or remember me key is not present");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.noKeyOrName", null, "The club name and remember me key is required", locale), HttpStatus.BAD_REQUEST);
} else
{
int databasePortInt = 27017;
if(databaseHost.isEmpty())
{
logger.warn("The database host is empty, using default value.");
databaseHost = "localhost";
}
if(databasePort.isEmpty())
{
logger.warn("The database port is empty, using default value.");
databasePort = "27017";
} else
{
try
{
databasePortInt = Integer.parseInt(databasePort);
} catch (NumberFormatException e)
{
logger.warn("The database port seems not to be a number " + databasePort);
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.dbPortNoNumber", null, "The database port needs to be a number", locale), HttpStatus.BAD_REQUEST);
}
}
if(databaseCollection.isEmpty())
{
logger.warn("The database collection name is empty, using default value");
databaseCollection = "myVerein";
}
if(!mongoIsAvailable(databaseHost, databasePortInt, databaseUser, databasePassword, databaseCollection))
{
logger.warn("The stated MongoDB is not available");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.mongoNotAvailable", null, "The stated MongoDB is not available", locale), HttpStatus.BAD_REQUEST);
}
try
{
logger.debug("Temporarily storing information");
settingsRepository.setClubName(clubName);
settingsRepository.setDatabaseHost(databaseHost);
settingsRepository.setDatabasePort(databasePort);
settingsRepository.setDatabaseUser(databaseUser);
settingsRepository.setDatabasePassword(databasePassword);
settingsRepository.setDatabaseName(databaseCollection);
settingsRepository.setRememberMeKey(rememberMeTokenKey);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsSuccess", null, "Successfully saved settings", locale), HttpStatus.OK);
}
}
#RequestMapping(value = "superAdmin")
public ResponseEntity<String> initSuperAdmin(#RequestParam String firstName,
#RequestParam String lastName,
#RequestParam String email,
#RequestParam String password,
#RequestParam String passwordRe,
Locale locale)
{
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(firstName.isEmpty() || lastName.isEmpty() || email.isEmpty() || password.isEmpty() || passwordRe.isEmpty())
{
logger.warn("A required parameter of the super admin is empty or missing during initial configuration");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.missingParameter", null, "A required parameter is empty or missing", locale), HttpStatus.BAD_REQUEST);
} else if(!password.equals(passwordRe))
{
logger.warn("The password and the re-typed password do not match!");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.passwordMatchError", null, "The password and the re-typed password do not match", locale), HttpStatus.BAD_REQUEST);
} else
{
logger.debug("Creating a new initial user.");
User superAdmin = new User();
superAdmin.setFirstName(firstName);
superAdmin.setLastName(lastName);
superAdmin.setEmail(email);
superAdmin.setPassword(password);
logger.debug("Creating a new initial root division.");
Division rootDivision = new Division(settingsRepository.getClubName(), null, superAdmin, null);
//Saving changes and restarting context
try
{
settingsRepository.setInitSetup(false);
//This call is restarting the application.
settingsRepository.saveSettings(superAdmin);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
try
{
userRepository.save(superAdmin);
divisionRepository.save(rootDivision);
} catch (ConstraintViolationException e)
{
logger.warn("A database constraint was violated while saving the new super admin.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.constraintViolation", null, "A database constraint was violated while saving the new super admin", locale), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingAdminSuccess", null, "Successfully saved the new super admin. The settings are now being saved and the application is restarted.", locale) , HttpStatus.OK);
}
}
private boolean mongoIsAvailable(String databaseHost, int databasePort, String databaseUser, String databasePassword, String databaseCollection)
{
logger.debug("Creating mongo client to test connection");
List<MongoCredential> credential = null;
MongoClient mongoClient = null;
if(!databaseUser.isEmpty() && !databasePassword.isEmpty())
{
credential = Arrays.asList(MongoCredential.createMongoCRCredential(databaseUser, databaseCollection, databasePassword.toCharArray()));
}
try
{
mongoClient = new MongoClient(new ServerAddress(databaseHost, databasePort),credential);
//Checking if connection REALLY works
List<String> databases = mongoClient.getDatabaseNames();
if(databases == null)
{
logger.warn("The list of databases is null");
return false;
} else if(databases.isEmpty())
{
logger.info("The databases are empty");
return true;
} else
{
logger.debug("The database connection seems okay.");
return true;
}
} catch (UnknownHostException e)
{
logger.warn("Unable to resolve mongoDB host: " + e.getMessage());
return false;
} catch (MongoException e)
{
logger.warn("Unable to receive list of present databases: " + e.getMessage());
return false;
} finally
{
if(mongoClient != null)
{
mongoClient.close();
}
}
}
}
de.steilerdev.myVerein.server.model.SettingsRepository (Retrieving and storing the settings persistent within a properties file, as well as restarting the application if the settings changed)
public class SettingsRepository
{
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private SimpleMongoDbFactory mongoDbFactory;
#Autowired
private ApplicationContext applicationContext;
private Properties settings;
private Resource settingsResource;
private final static String settingsFileName = "myVerein.properties";
//Property names
private final static String databaseName = "dbName";
private final static String databaseHost = "dbHost";
private final static String databasePort = "dbPort";
private final static String databaseUser = "dbUser";
private final static String databasePassword = "dbPassword";
private final static String rememberMeKey = "rememberMeKey";
private final static String clubName = "clubName";
private final static String initSetup = "initSetup";
private boolean changed;
private boolean databaseChanged;
private static Logger logger = LoggerFactory.getLogger(SettingsRepository.class);
public Properties loadSettings() throws IOException
{
if(settings == null)
{
logger.debug("Loading settings file from classpath");
settingsResource = new ClassPathResource(settingsFileName);
changed = false;
databaseChanged = false;
return (settings = PropertiesLoaderUtils.loadProperties(settingsResource));
} else
{
return settings;
}
}
//Getter and setter removed
public void saveSettings(User currentUser) throws IOException
{
saveSettings(loadSettings(), currentUser);
}
public void saveSettings(Properties settings, User currentUser) throws IOException
{
if(changed)
{
logger.debug("Saving settings to " + settingsResource.getFile().getAbsolutePath());
settings.store(new FileOutputStream(settingsResource.getFile()), "Settings last changed " + (currentUser != null ? ("by " + currentUser.getEmail() + " (" + LocalDateTime.now().toString() + ")") : LocalDateTime.now().toString()));
if(databaseChanged)
{
try
{
mongoDbFactory.destroy();
} catch (Exception e)
{
System.err.println("Problem destroying factory");
}
((ConfigurableApplicationContext) applicationContext).refresh();
}
this.settings = null;
} else
{
logger.debug("No need to save the settings");
}
}
}
The exception is thrown in line 178 of the InitController, which means after reloading and during saving an object to the new controller userRepository.save(superAdmin);
It's hard to say, why reload does not work, based on plain Exception, but here are some hints:
Regarding restarting application context, there is a good article
http://jroller.com/Solomon/entry/reloading_a_spring_web_application
You can get some clues for why it malfunctions from there.
With context reload you need to be careful to close all open resources, properly, on application shutdown.
Check that you closed Mongo connection properly in your application context.
What is the correct way to close the mongo connection using spring-mongo?
After you added your code. It's hard to understand, what are you trying to accomplish with this. This will take you allot of effort to make it work properly, and most of this efforts will be waist.
You can't reload specific bean in Spring Context, but you can reload whole context, by calling ApplicationContext refresh(), after which all beans will be recreated, including your Controller beans. So this should at least be a separate Controller, with no additional functionality. Also It seems you are assuming you can change mongo configuration, and at the same call write something to mongo, using old references ... this is not how things work in spring. So just don't.
Related
I'm using Spring and Hibernate for my project and my database is MySql. I'm using annotation instead of xml.
Every day, When I make the first request for login, I get this exception, then after refresh it works.
18-Feb-2016 10:59:20.990 SEVERE [http-nio-443-exec-9] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [dispatcher] in context with path [/ATS] threw exception
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:427)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.services.MyAuthoritiesPopulator$$EnhancerBySpringCGLIB$$9580eab6.getGrantedAuthorities(<generated>)
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.loadUserAuthorities(LdapAuthenticationProvider.java:215)
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:84)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1771)
at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:64)
at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:67)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380)
... 49 more
Caused by: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:76)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1471)
at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:61)
... 51 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 65,266,256 milliseconds ago. The last packet sent successfully to the server was 65,266,256 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:400)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3621)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2429)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2541)
at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4882)
at org.apache.commons.dbcp.DelegatingConnection.setAutoCommit(DelegatingConnection.java:371)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.setAutoCommit(PoolingDataSource.java:328)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:72)
... 54 more
Caused by: java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3603)
... 61 more
It seems that the server close connection with MySql, my application server is Tomcat, it may be a problem with code or Tomcat? This is my spring configuration class:
#EnableWebMvc
#Configuration
#PropertySource(value = { "classpath:application.properties" })
#ComponentScan({ "com.*" })
#EnableTransactionManagement
#Import({ SecurityConfig.class, SpringMvcInitializer.class})
#EnableJpaRepositories("com.repository")
public class AppConfig extends WebMvcConfigurerAdapter{
#Autowired
private Environment env;
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
// private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
/**
* This and the next methods are used to avoid exception while jackson mapping the entity, so fields are setted with null value
* unless use Hibernate.initialize
* #return
*/
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
//Registering Hibernate4Module to support lazy objects
mapper.registerModule(new Hibernate4Module());
messageConverter.setObjectMapper(mapper);
return messageConverter;
}
/**
* Used for spring security
* #return
*/
#Bean
public SpringSecurityDialect springSecurityDialect() {
SpringSecurityDialect dialect = new SpringSecurityDialect();
return dialect;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//Here we add our custom-configured HttpMessageConverter
converters.add(jacksonMessageConverter());
super.configureMessageConverters(converters);
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
}
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
ds.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
ds.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
ds.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return ds;
}
#Bean
public ServletContextTemplateResolver TemplateResolver(){
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/pages/");
resolver.setSuffix(".html");
resolver.setTemplateMode("LEGACYHTML5");
resolver.setCacheable(false);
return resolver;
/*ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
return resolver;*/
}
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(TemplateResolver());
templateEngine.addDialect(springSecurityDialect());
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setOrder(1);
resolver.setViewNames(new String[]{"*", "js/*", "template/*"});
return resolver;
}
/**
* Register multipartResolver for file upload
* #return
*/
#Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver=new CommonsMultipartResolver();
resolver.setDefaultEncoding("utf-8");
return resolver;
}
/**
* Allow use of bootstrap
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
}
/**
* Allow use of JPA
*/
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(env.
getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
return entityManagerFactoryBean;
}
}
UPDATE:
I created this class
#Service
#EnableScheduling
public class wakeUpDatabase {
#Autowired
private DatabaseFleetsAndCarsServices databaseFleetsAndCarsServices;
//This task is executing every 7h
#Scheduled(fixedDelay = 25200000)
public void smartQeury(){
databaseFleetsAndCarsServices.getEcu();
}
}
I test it and let you know if it works
I resolved with a query each 7 hours:
#Service
#EnableScheduling
public class wakeUpDatabase {
#Autowired
private DatabaseFleetsAndCarsServices databaseFleetsAndCarsServices;
//This task is executing every 7h
#Scheduled(fixedDelay = 25200000)
public void smartQeury(){
databaseFleetsAndCarsServices.getEcu();
}
}
Either set autoReconnect=true' as the stack trace tells you using the Connector/J connection property 'autoReconnect=true' to avoid this problem. or schedule a tickle thread that keeps the connection open:
/*
HeartBeat is scheduled on a BackgroundJobScheduler
*/
private static class HeartBeat implements Runnable {
private Connection conn;
public HeartBeat(Connection conn) {
this.conn = conn;
}
#Override
public void run() {
if (null != conn) {
try {
if (!conn.isClosed()) {
String queryStr = "select 1 from dual";
Statement st = conn.createStatement();
st.execute(queryStr);
st.close();
}
} catch (RuntimeException e){
LOG.fatal("Uncaught Runtime Exception "+e.getMessage());
return; // Keep working
} catch (SQLException e){
LOG.fatal("Uncaught SQL Exception "+e.getMessage());
return; // Keep working
} catch (Throwable e){
LOG.fatal("Unrecoverable error "+e.getMessage());
throw e; // abort
}
}
}
}
And schedule it as a background job that terminates if the app terminates:
#WebListener
public class BackgroundJobScheduler implements ServletContextListener {
private static ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
}
public void schedule (Runnable task) {
if (scheduler == null )
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(task, 0, 14, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
It looks like firewall is terminating connection after certain idle period. Something you can do to avoid this is to set the "validationQuery" property of the "BasicDataSource" class.
"select sysdate from dual" query would do.
Add the below in you datasource configuration method in the AppConfig class
ds.setValidationQuery("select sysdate from dual");
Doing this will validate the connection in the pool before returning the connection object to the caller. In case of closed connections, a new connection object would be created and returned to the caller.
Looking at the output of redis client list, I see there are 600 active clients at the moment, and it continues to grow. Here's a snippet of output:
id=285316 addr=x.x.x.x:55699 fd=14131 name= age=53055 idle=53029 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=sismember
id=285317 addr=x.x.x.x:55700 fd=14132 name= age=53055 idle=53050 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=sismember
Here's my code:
Listener.java:
import com.sun.jersey.api.model.AbstractResourceModelContext;
import com.sun.jersey.api.model.AbstractResourceModelListener;
import javax.ws.rs.ext.Provider;
#Provider
public class Listener implements AbstractResourceModelListener {
#Override
public void onLoaded(AbstractResourceModelContext modelContext) {
RedisManager.getInstance().connect();
}
}
RedisManager.java:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisManager {
private static final RedisManager instance = new RedisManager();
private static JedisPool pool;
private RedisManager() {
}
public final static RedisManager getInstance() {
return instance;
}
public void connect() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(5000);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setMaxIdle(50);
poolConfig.setMinIdle(1);
poolConfig.setTestWhileIdle(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(60000);
pool = new JedisPool(poolConfig, "redis_hostname");
}
public void release() {
pool.destroy();
}
public Jedis getJedis() {
return pool.getResource();
}
public void returnJedis(Jedis jedis) {
pool.returnResourceObject(jedis);
}
}
APIServlet.java:
#Path("/")
public class APIService {
#GET
#Path("/lookup")
#Produces(MediaType.APPLICATION_JSON)
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
) throws JSONException {
Jedis jedis = RedisManager.getInstance().getJedis();
if (jedis.sismember("inprocess", email)) {
RedisManager.getInstance().returnJedis(jedis);
return Response.status(202).entity("{\"status\":202, " +
"\"processing\":{\"type\":\"Lookup performed\", " +
"\"message\":\"We're performing analysis on this " +
"record. Result should be ready in a few minutes" +
".\"}}").build();
}
Person person = new Person();
person.lookup(person);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(person);
JSONObject jsonObj = new JSONObject(jsonString);
jsonObj.remove("objectID");
jsonObj.remove("data_quality");
jsonObj.put("status", 200);
RedisManager.getInstance().returnJedis(jedis);
if (!jsonObj.isNull("name") && !jsonObj.get("name").equals("")) {
if (hasPretty) {
return Response.status(200).entity(jsonObj.toString(4))
.build();
}
return Response.status(200).entity(jsonObj.toString()).build();
}
return Response.status(404).entity("{\"status\":404, " +
"\"error\":{\"type\":\"Data Not Found.\", " +
"\"message\":\"We were not able to find data " +
"on this email.\"}}").build();
}
}
Maven Dependencies:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.2.0</version>
</dependency>
The Listener creates an instance of RedisManager to be used throughout the application--this should happen only once, on startup (note: I have no idea how to call destroy on shutdown, which would be nice to know). Throughout the program, this instance of JedisPool is used in Jersey routes, as shown in APIServlet.java. In the route, I get a JedisPool resource, then before I return on any part of the route, I return the resource.
What is happening is that the resource does not seem to be returned (or my understanding of the pool is wrong). After a period of time, the connections to my Redis instance grow to the maxTotal of 5,000, and then I start getting errors "could not get a resource from the pool," and Tomcat dies.
A few things I've noticed:
There seems to be a large amount of ESTABLISHED https connections that stick around (not 100% sure on this, but it seems to be the case).
All Redis clients that are idle (well, nearly all anyway) have a cmd of sismember.
NOTE: I've not included the full APIService.java code because I'm really not allowed to do so. The snippet I included does give the overall gist of the code. I am returning throughout the APIService.java code (return 404, return 429, etc), and before each return I make sure I am returning the resource to the pool.
Finally, here's the stacktrace:
10-Feb-2016 08:04:23.161 SEVERE [http-nio-443-exec-14] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)
at co.talentiq.api.APIService.getMsg(APIService.java:63)
at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
First: If you already have pool initialized do not create a new one:
public class RedisManager {
...
public void connect() {
if(pool != null) {
System.out.println("Already exists");
return;
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
...
Second ... Do you have exceptions in your logs from getMsg method?
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
You should have all work with pooled resources being wrapped into try-catch-finally and always return resource in finally block. NB: make sure not to return resource (jedis in this case) to pool twice.
Jedis jedis;
try {
jedis = RedisManager.getInstance().getJedis();
...
} finally {
if (jedis != null) {
RedisManager.getInstance().returnJedis(jedis);
jedis = null;
}
}
Btw: you can create a small AutoCloseable wrapper around your jedis get/return code and use java try with resources - https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Code snippet with try-with-resource
public void release() {
pool.destroy();
}
public static class JedisWrapper implements AutoCloseable {
private final JedisPoolConfig pool;
private final Jedis jedis;
public JedisWrapper(JedisPoolConfig pool, Jedis jedis) {
this.pool = pool;
this.jedis = jedis;
}
public Jedis get() {
return jedis;
}
#Override
public void close() {
pool.returnResourceObject(jedis);
}
}
public JedisWrapper getJedis() {
return new JedisWrapper(pool, pool.getResource());
}
// you can delete this method
public void returnJedis(Jedis jedis) {
pool.returnResourceObject(jedis);
}
And later in usage place
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
) throws JSONException {
try(JedisWrapper jw = ...) {
Jedis jedis = jw.get();
...
}
When an error occurs in my Java based rest web service
I get the exception sent to the client like this
type Exception report
message Invalid Token
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.security.authentication.AuthenticationServiceException: Invalid Token
com.resource.security.TokenAuthenticationFilter.doFilter(TokenAuthenticationFilter.java:220)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:208)
com.thetransactioncompany.cors.CORSFilter.doFilter(CORSFilter.java:271)
note The full stack trace of the root cause is available in the Apache Tomcat/8.0.23 logs.
But I wanted to return a response like this
{
"code" : 500,
"message" : "invalid token"
}
How can this be done ?
UPDATE
#Provider
public class MyApplicationExceptionHandler implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException weException) {
// get initial response
Response response = weException.getResponse();
// create custom error
ErrorDTO error = new ErrorDTO();
error.setCode(response.getStatus());
error.setMessage(weException.getMessage());
// return the custom error
return Response.status(response.getStatus()).entity(error).build();
}
}
Web.xml
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.madzz.common.exception.MadzzApplicationExceptionHandler</param-value>
</context-param>
Application code:
public String getTrackingDetailById(long orderItemId) throws Exception {
throw new NotFoundException("not found"); }
I am using java.ws.rs.NotFoundException . But it doesn't seem to work.
Anypointer why?
What you are looking for is the #ControllerAdvice . The logic is as follows:
You create a class with annotation where each method inside that class responds to one or more exceptions. Example here:
#ControllerAdvice
public class MyExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);
#ExceptionHandler(MyCustomException.class)
#ResponseBody
public ExcObject handleSQLException(HttpServletRequest request, Exception ex){
logger.info("SQLException Occured:: URL="+request.getRequestURL());
return "database_error";
}
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
#ExceptionHandler(IOException.class)
public void handleIOException(){
logger.error("IOException handler executed");
//returning 404 error code
}
}
Inside the handleSQLException construct your newly created object of the newly created class ExcObject and return this.
In your controller you need to throw the specific exception.
Pay attention also that you need to create MyCustomException which will extend exception.
Use you own exception handler:
try {
...you code that throws AuthenticationServiceException
} catch (AuthenticationServiceException ex) {
... return you custom JSONObject
}
Catch all exceptions at the base level, and convert to JSON, then return the JSON representation of the exception, wit a return code of 400. Below is the routine to convert an Exception to JSON in a standardized way:
public static JSONObject convertToJSON(Throwable e, String context) throws Exception {
JSONObject responseBody = new JSONObject();
JSONObject errorTag = new JSONObject();
responseBody.put("error", errorTag);
errorTag.put("code", 400);
errorTag.put("context", context);
JSONArray detailList = new JSONArray();
errorTag.put("details", detailList);
Throwable nextRunner = e;
List<ExceptionTracer> traceHolder = new ArrayList<ExceptionTracer>();
while (nextRunner!=null) {
Throwable runner = nextRunner;
nextRunner = runner.getCause();
detailObj.put("code", runner.getClass().getName());
String msg = runner.toString();
detailObj.put("message",msg);
detailList.put(detailObj);
}
JSONArray stackList = new JSONArray();
for (StackTraceElement ste : e.getStackTrace()) {
ja.put(ste.getFileName() + ": " + ste.getMethodName()
+ ": " + ste.getLineNumber());
}
errorTag.put("stack", stackList);
return responseBody;
}
You can find the complete open source library that implements this at: Mendocino JSON Utilities. This library supports the JSON Objects as well as the exceptions.
This produces a JSON structure of this form:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
This is the format proposed by the OASIS data standard OASIS OData and seems to be the most standard option out there, however there does not seem to be high adoption rates of any standard at this point.
The details are discussed in my blog post on Error Handling in JSON REST API
This is my servlet class
here set my hibernate session and sending the objects to the client class where are the get and set class and call CustomerDAO
// star hibernate session 4.x
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
// call the class
Clientes clientes = new Clientes();
ClienteDAO clientedao = new ClienteDAO();
//send parameter to class
clientes.setNombre("nombre");
clientes.setApellido("apellido");
clientes.setTelefono("telefono");
clientes.setEmail("correo");
clientes.setPass("clave1");
//send the parameter to dao
clientedao.createCliente(clientes); // error here at com.utp.soft6.RegistroSv.processRequest(RegistroSv.java:80)
this is the code of clientesdao when recive the parameter of Clientes.java
public class ClienteDAO {
private Session session;
public ClienteDAO() {
this.session = session;
}
public long createCliente(Clientes cliente) {
long clienteId = -1;
Transaction tx = null;
try {
tx = session.beginTransaction(); //error here at com.utp.soft6.model.ClienteDAO.createCliente(ClienteDAO.java:30)
clienteId = (Long)session.save(cliente);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
}
return clienteId;
}
}
When run the aplication show this error
log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
Hibernate: drop table if exists clientes
Hibernate: create table clientes (id bigint not null auto_increment, apellido varchar(255), email varchar(255), nombre varchar(255), pass varchar(255), telefono varchar(255), primary key (id)) ENGINE=InnoDB
java.lang.NullPointerException
at com.utp.soft6.model.ClienteDAO.createCliente(ClienteDAO.java:30)
at com.utp.soft6.RegistroSv.processRequest(RegistroSv.java:80)
at com.utp.soft6.RegistroSv.doGet(RegistroSv.java:124)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
the class create table but have error when into values to table
public ClienteDAO() {
this.session = session;
}
Based on the information you provided, it seems issues is session variable is null.
You need to pass hibernate session to constructor as parameter (or) use setters;
Your session is null ,you are not setting it never
public ClienteDAO(Session session) {
this.session = session;
}
and in client code
// call the class
Clientes clientes = new Clientes();
ClienteDAO clientedao = new ClienteDAO(session);
By the way i know you speak spanish so class name Clientes should be Cliente always in singular, represents an Entity.
Can someone please tell me why am I geting java.sql.SQLException: This function is not supported using HSQL and Spring? I am trying to insert a new row into my database..
Below is my DAO and I get the error on the mySession.save(message) line:
#Transactional
#Repository
public class MessageDaoImpl implements MessageDao
{
private Log log = null;
#Autowired
private SessionFactory sessionFactory;
public MessageDaoImpl()
{
super();
log = LogFactory.getLog(MessageDaoImpl.class);
}
#SuppressWarnings("unchecked")
#Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public List<Message> listMessages()
{
try
{
return (List<Message>) sessionFactory.getCurrentSession()
.createCriteria(Message.class).list();
} catch (Exception e)
{
log.fatal(e.getMessage());
return null;
}
}
#SuppressWarnings("unchecked")
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void SaveOrUpdateMessage(Message message)
{
try
{
Session mySession = sessionFactory.getCurrentSession();
mySession.save(message);
mySession.flush();
} catch (Exception e)
{
log.fatal(e.getMessage());
}
}
}
Here is my main class:
public static void main(String[] args)
{
ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
MessageService mService = context.getBean(MessageService.class);
HelloWorld helloWorld = context.getBean(HelloWorld.class);
/**
* Date: 4/26/13 / 9:26 AM
* Comments:
*
* I added Log4J to the example.
*/
LOGGER.debug("Message from HelloWorld Bean: " + helloWorld.getMessage());
Message message = new Message();
message.setMessage(helloWorld.getMessage());
//
mService.SaveMessage(message);
helloWorld.setMessage("I am in Staten Island, New York");
LOGGER.debug("Message from HelloWorld Bean: " + helloWorld.getMessage());
}
}
Here is my DatabaseConfig:
public class DatabaseConfig
{
private static final Logger LOGGER = getLogger(DatabaseConfig.class);
#Autowired
Environment env;
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.HSQL).
addScript("schema.sql").build();
return db;
}
#Bean
public DataSource hsqlDataSource() {
BasicDataSource ds = new BasicDataSource();
try {
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUsername("sa");
ds.setPassword("");
ds.setUrl("jdbc:hsqldb:mem:mydb");
}
catch (Exception e)
{
LOGGER.error(e.getMessage());
}
return ds;
}
#Bean
public SessionFactory sessionFactory()
{
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(hsqlDataSource());
factoryBean.setHibernateProperties(getHibernateProperties());
factoryBean.setPackagesToScan(new String[]{"com.xxxxx.HelloSpringJavaBasedJavaConfig.model"});
try
{
factoryBean.afterPropertiesSet();
} catch (IOException e)
{
LOGGER.error(e.getMessage());
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return factoryBean.getObject();
}
#Bean
public Properties getHibernateProperties()
{
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.use_sql_comments", env.getProperty("hibernate.use_sql_comments"));
hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.setProperty("javax.persistence.validation.mode", env.getProperty("javax.persistence.validation.mode"));
//Audit History flags
hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", env.getProperty("org.hibernate.envers.store_data_at_delete"));
hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", env.getProperty("org.hibernate.envers.global_with_modified_flag"));
return hibernateProperties;
}
#Bean
public HibernateTransactionManager hibernateTransactionManager()
{
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory());
htm.afterPropertiesSet();
return htm;
}
}
and here is what I am getting to the console:
Exception in thread "main" org.hibernate.AssertionFailure: null id in com.xxx.HelloSpringJavaBasedJavaConfig.model.Message entry (don't flush the Session after an exception occurs)
Here is my message model bean:
#Entity
#Table(name = "messages")
public class Message
{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private String id;
#Column(name = "message")
private String message;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
#Override
public String toString()
{
return "Message{" +
"id='" + id + '\'' +
", message='" + message + '\'' +
'}';
}
}
This relates to the version of hsql being used probably the version causing issue was 1.8 with hibernate 4. Need to use 2.2.9 instead
You can't use a String with #GenerateValue with the Strategy GenerationType.AUTO since it uses sequence generator and those can't be used with non-numerical values. You have to set it yourself. Use an Integer or Long if you want it to be generated for you.
Hibernate docs
Or use an id generator that uses string values
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
it was a version issues. I updated the versions and now everything works
I had the same issue after I upgraded hibernate to version 4.2.8 .Looking in the logs, I noticed that the sql query generated by hibernate tried to insert a record with a null primary key. The field was annotated just with: #Id #GeneratedValue
Upgrading hsqldb to version 2.2.9 made this disappear just like Denis said and I am very thankful to him for the reply.
It seems very likely that this issue is related to attempting to use a Session which has already signaled an error. As Sotirios mentioned, it is a bad idea to catch exceptions in your DAO, and if you do, it is critical that you re-throw them.
Normally, once you catch a Hibernate exception, you must roll back your transaction and close the session as the session state may no longer be valid (Hibernate core documentation).
If the Session throws an exception, including any SQLException, immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block.
Since you're using Spring, most of that doesn't apply to you, but the exception message you are seeing indicates that the actual cause of your problem probably was related to catching an exception and then continuing to use the same session.