Invalidated object not currently part of this pool - spring-data-redis

When I use redisCacheManager to put something, it throws an exception "Invalidated object not currently part of this pool". But when I set the usePool to false, it can work. I think this is a Multi-threaded case. But I don't know why the spring-data-redis's annotation can work.
<code>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserServiceImpl userService = applicationContext.getBean(UserServiceImpl.class);
RedisCacheManager redisCacheManager = applicationContext.getBean(RedisCacheManager.class);
redisCacheManager.getCache("cacheName").put("key","value");
<cache:annotation-driven ></cache:annotation-driven>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"/>
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="usePool" value="true"></property>
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
</bean>
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate"/>
</code>

Related

Spring 5 MVC Test with MockMvc, test-context.xml, and annotation-based WebAppConfig (ie, in Java)

Versions (SpringBoot is not involved):
Spring: 5.2.16
web-app / servlet API: 4.0
JUnit: 5.8
Spring MVC Testing is not working for controller endpoint that returns ResponseEntity<ReturnStatus>, where ReturnStatus is a POJO with appropriate getters/setters. The exception triggered indicates that JSON conversion is not working for ReturnStatus. My research indicates that the annotation-based Java configuration for the WebApplicationContext is not loaded (and therefore the Jackson JSON converter is not recognized). Curiously, in a non-testing deployment in Tomcat, the controller endpoint works fine, presumably because the web.xml in the war-file is parsed by Tomcat.
QUESTION:
How can I adjust the setup for Spring MVC Test for this application so that the annotation-based Java configuration for the WebApplicationContext is properly loaded? Can this, for example, be done explicitly in the endpoint-test logic (ie, the JUnit test)?
Exception:
14:33:57,765 WARN DefaultHandlerExceptionResolver:199 - Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.acme.myapp.io.ReturnStatus] with preset Content-Type 'null']
14:33:57,765 DEBUG TestDispatcherServlet:1131 - Completed 500 INTERNAL_SERVER_ERROR
The Spring MVC app incorporates the following configurations:
test-context.xml, which houses Spring bean-configuration for access to data store:
web.xml, which declares and maps the DispatcherServlet with relevant setup for WebApplicationContext.
Annotation-based configuration in Java implementation of WebMvcConfigurer.
Relevant excerpt from test-context.xml:
<context:component-scan base-package="com.acme.myapp"/>
<jpa:repositories base-package="com.acme.myapp.repos"/>
<context:property-placeholder location="classpath:/application.properties" />
<!-- Data persistence configuration -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${db.showSql}" />
<property name="databasePlatform" value="${db.dialect}" />
<property name="generateDdl" value="${db.generateDdl}" />
</bean>
</property>
<property name="packagesToScan">
<list>
<value>com.acme.myapp.dao</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.user}" />
<property name="password" value="${db.pass}" />
<property name="initialSize" value="2" />
<property name="maxActive" value="5" />
<property name="accessToUnderlyingConnectionAllowed" value="true"/>
</bean>
<!-- Set JVM system properties here. We do this principally for hibernate logging. -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.System" />
<property name="targetMethod" value="getProperties" />
</bean>
</property>
<property name="targetMethod" value="putAll" />
<property name="arguments">
<util:properties>
<prop key="org.jboss.logging.provider">slf4j</prop>
</util:properties>
</property>
</bean>
Relevant excerpt from web.xml (where application-context.xml is our production version of test-context.xml):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>central-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.myapp.MyAppWebAppConfig</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>central-dispatcher</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Excerpt from Java implementation of WebMvcConfigurer (ie, where we incorporate Jackson JSON converter):
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "com.acme.myapp.controllers" })
public class MyAppWebAppConfig implements WebMvcConfigurer
{
private static final Logger logger = LoggerFactory.getLogger(MyAppWebAppConfig.class);
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters)
{
logger.debug("extendMessageConverters ...");
converters.add(new StringHttpMessageConverter());
converters.add(new MappingJackson2HttpMessageConverter(new MyAppObjectMapper()));
}
}
The controller endpoint looks like this (where the root is at /patients):
#RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ReturnStatus> readPatient(
#PathVariable("id") long id
)
{
ReturnStatus returnStatus = new ReturnStatus();
returnStatus.setVersionId("1.0");
...
return new ResponseEntity<ReturnStatus>(returnStatus, httpStatus);
}
Using JUnit5 and MockMvc, the endpoint-test looks like this:
#SpringJUnitWebConfig(locations={"classpath:test-context.xml"})
public class PatientControllerTest
{
private MockMvc mockMvc;
#BeforeEach
public void setup(WebApplicationContext wac) {
this.mockMvc = webAppContextSetup(wac).build();
}
#Test
#DisplayName("Read Patient from /patients API.")
public void testReadPatient()
{
try {
mockMvc.perform(get("/patients/1").accept(MediaType.APPLICATION_JSON_VALUE))
.andDo(print())
.andExpect(status().isOk());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Thanks!
Here are some options, possibly not exhaustive:
Per earlier comment, we can simply use <mvc:annotation-driven> directive in test-context.xml. For example:
<bean id="myappObjectMapper" class="com.acme.myapp.MyAppObjectMapper"/>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<constructor-arg ref="myappObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Effectively, this directive obviates the need for loading MyAppWebAppConfig, as <mvc:annotation-driven> in fact is the XML-equivalent of the annotation #EnableWebMvc in Java.
Implement WebApplicationInitializer so that effectively does in Java what we configure into web.xml. For example:
public class MyAppWebApplicationInitializer implements WebApplicationInitializer
{
#Override
public void onStartup(ServletContext container)
{
XmlWebApplicationContext appCtx = new XmlWebApplicationContext();
appCtx.setConfigLocation("classpath:application-context.xml");
container.addListener(new ContextLoaderListener(appCtx));
AnnotationConfigWebApplicationContext dispatcherCtx = new AnnotationConfigWebApplicationContext();
dispatcherCtx.register(MyAppWebAppConfig.class);
ServletRegistration.Dynamic registration = container.addServlet("central-dispatcher", new DispatcherServlet(dispatcherCtx));
registration.setLoadOnStartup(1);
registration.addMapping("/api/*");
}
}
For this solution, we expunge web.xml from the project; possibly we should parameterize the reference to application-context.xml as well.
Note that when I run JUnit5 tests, it appears that Spring does not instance MyAppWebApplicationInitializer, and that instead, the Spring context loaded for JUnit5 is the one referenced by the #SpringJUnitWebConfig annotation. I therefore recommend co-locating test-related configuration with test-context.xml, and reserving WebApplicationInitializer for production.
I'm sure there are other options, but I've only explored these two approaches.

Camunda Shared Engine Spring Junit factory-bean 'processEngine' returned null

I am writing a simple process application using Spring MVC and Camunda with a shared process engine. Now I want to add simple test cases and I am running into the problem that the process engine returns null for every factory method. When running the application the process engine returns the services as expected.
How should i configure camunda for JUnit tests, when using a shared process engine?
This is my camunda process engine configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bind the process engine service as Spring Bean -->
<bean name="processEngineService" class="org.camunda.bpm.BpmPlatform" factory-method="getProcessEngineService" />
<!-- bind the default process engine as Spring Bean -->
<bean name="processEngine" factory-bean="processEngineService" factory-method="getDefaultProcessEngine" />
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>
<bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
<bean id="authorizationService" factory-bean="processEngine" factory-method="getAuthorizationService"/>
<!-- bootstrap the process application -->
<bean id="processApplication" class="org.camunda.bpm.engine.spring.application.SpringServletProcessApplication" />
</beans>
and this is the releavant part of my simple test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration({
"file:src/main/webapp/WEB-INF/process-conf.xml",
"file:src/main/webapp/WEB-INF/hibernate-conf.xml",
"file:src/main/webapp/WEB-INF/camunda-conf.xml",
"file:src/main/webapp/WEB-INF/dispatcher-servlet.xml",
})
public class OrderControllerTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
#Test
public void testTest() throws Exception {
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/");
this.mockMvc.perform(builder)
.andExpect(ok);
}
}
This is the exception that is thrown when starting the junit test:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'repositoryService' defined in URL [file:src/main/webapp/WEB-INF/camunda-conf.xml]: factory-bean 'processEngine' (or a BeanPostProcessor involved) returned null
I solved the problem via a workaround based on a guess:
It seems that the tests are rund directly in java, without the tomcat server instance. Therefore there is no shared process engine which can be accessed.
The solution:
I created another camunda configuration for an embedded process engine which uses the same database as the shared engine that is configured in the tomcat instance. The process engine can be instantiated then and the test is running fine. My guess is that one should be cautious to not have tomcat and the test run concurrently.
this is the embedded process engine configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/CamundaProcessEngine_001?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="####"/>
<property name="password" value="####"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="processEngineConfiguration" class="org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
<!-- turn off metrics reporter -->
<property name="dbMetricsReporterActivate" value="false" />
<property name="history" value="full" />
</bean>
<bean id="processEngine" class="org.camunda.bpm.engine.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>
<bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
<bean id="authorizationService" factory-bean="processEngine" factory-method="getAuthorizationService"/>
<bean id="activitiRule" class="org.camunda.bpm.engine.test.ProcessEngineRule">
<property name="processEngine" ref="processEngine" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

Spring mvc redirect to different application on different jvm

My requirement is to redirection between two different apps in different JVMs. And also transfer data between the two. I tried using Flash Attributes, but in the controller, the attributes are null. I tried creating an interceptor also, but even there the flash attributes are null. Can anyone help me on how to pass attributes between two different applications?
Here is my code:
poc1 - calling application
dispatcher-servlet.xml
<context:component-scan base-package="controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean name="flashMapManager" class="org.springframework.web.servlet.support.SessionFlashMapManager" />
<mvc:annotation-driven />
</beans>
Controller.java
#RequestMapping(value = "add", method = RequestMethod.POST)
public String add(#ModelAttribute("customer") Customer customer,
final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("customer", customer);
redirectAttributes.addFlashAttribute("message", "Added successfully.");
return "redirect:http://localhost:8080/poc2";
}
poc2 - called application
dispatcher-servlet.xml
<context:component-scan base-package="controller" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean name="flashMapManager"
class="org.springframework.web.servlet.support.SessionFlashMapManager" />
<!-- <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors"> <list> <ref bean="requestInterceptor" /> </list>
</property> </bean> -->
<bean id="requestInterceptor" class="RequestInterceptor" />
<mvc:annotation-driven />
<mvc:interceptors>
<ref bean="requestInterceptor" />
</mvc:interceptors>
</beans>
Controller.java
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(Model model, HttpServletRequest request,
HttpSession session) {
Map<String, ?> inputFlashMap = RequestContextUtils
.getInputFlashMap(request);
Customer cust1 = (Customer) model.asMap().get("customer");
Customer cust = (Customer) inputFlashMap.get("customer");
ModelAndView modelMap = new ModelAndView("showCustomer");
System.out.println("Calling controller");
return modelMap;
}
you can use this,
Using just redirectAttributes.addFlashAttribute(...) -> "redirect:..." worked as well, didn't have to "reinsert" the model attribute.

Shiro Spring with filterchain definitions equivalent for #RequiresRoles logical.OR

I am trying to enhance my spring-enabled web-app's security using Apache Shiro and am thus configuring filterchain definitions into a spring-configured file.
How do i achieve the equivalent of
#Controller
#RequestMapping("/mywebapp")
// #RequiresAuthentication (is this possible ? wish i could do this !)
public class MyWebAppController {
#RequiresRoles(value={"Role1","Role2","Role3"},logical=Logical.OR)
#RequestMapping(value="/home", method = RequestMethod.GET)
public String home() { return .. }
and my spring-config file contains this :
assume that my dispatcherservlet is mapped to /rest/*
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/rest/secure/windowslogin"/>
<property name="successUrl" value="/mywebapp/rest/menu"/>
<property name="unauthorizedUrl" value="/mywebapp/rest/unauthorized"/>
<property name="filters">
<util:map>
<entry key="anon">
<bean class="org.apache.shiro.web.filter.authc.AnonymousFilter"/>
</entry>
<entry key="authc">
<!-- why is this not invoked ? -->
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter">
</bean>
</entry>
<entry key="roles">
<bean class="org.apache.shiro.web.filter.authz.RolesAuthorizationFilter"/>
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/rest/secure/** = anon
/rest/mywebapp/** = authc, roles[Role1,Role2,Role3]
</value>
</property>
</bean>
In the code above i need a logical.OR kind of mapping to the /rest/mywebapp/** using the roles mentioned. This is possible via shiro annotations and it works but rather than specifying at every method i would rather handle it here (since i dont think shiro supports class level annotations yet ?) .
Is this possible ?
Also on a side note why is the authc filter not invoked ?
( for now we assume that the windows login can serve as authentication, using shiro only for authorization )
home page = meta refresh to /rest/secure/windowslogin/
if within intranet -> login ...
else /rest/secure/login ... login page.
Is it because the loginurl is different ? How do i circumvent this ? Note that my realm's getAuthorizationInfo is invoked though using the roles[ .. ] part specified in the config file.. but i was assuming that there should be a check to see if the request is 'authc' ? (which probably means that the filter is invoked and SubjectUtils.getSubject() is checked for authentication). Am i missing something in the flow or configuration ?
This is how shiro-security.xml looks like.
<bean id="customFilter1" class="com.pkg.RolesAuthorizationFilter">
<property name="roles" value="ROLE1,ROLE3,ROLE5"></property>
</bean>
<bean id="customFilter2" class="com.pkg.RolesAuthorizationFilter">
<property name="roles" value="ROLE1,ROLE2,ROLE5,ROLE6"></property>
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/home" />
<property name="unauthorizedUrl" value="/unauthorized" />
<property name="filters">
<util:map>
<entry key="authc">
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/resources/** = anon
/login = anon
/logout = authc
/unauthorized = authc
/someurl/** = customFilter2
/** = customFilter1
</value>
</property>
</bean>
And this is RolesAuthorizationFilter class
package com.pkg;
import java.util.Arrays;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
public class RolesAuthorizationFilter extends AuthorizationFilter {
protected Logger logger = Logger.getLogger(this.getClass()
.getCanonicalName());
private String[] roles;
#Override
protected boolean isAccessAllowed(ServletRequest request,
ServletResponse response, Object mappedValue) throws Exception {
logger.info("= Roles = " + Arrays.toString(roles));
Subject subject = getSubject(request, response);
boolean allowAccess = false;
for (String role : roles) {
if (subject.hasRole(role)) {
logger.info("Authenticated role " + role);
allowAccess = true;
break;
}
}
return allowAccess;
}
public void setRoles(String[] roles) {
this.roles = roles;
}
}

How to call custom interseptor in spring portlet?

I have added my own interceptor in spring portlet i.e.
<bean id="portletModeParameterHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeParameterHandlerMapping">
<property name="interceptors">
<list>
<ref bean="customInterceptor"/>
</list>
</property>
<property name="portletModeParameterMap">
...............
.......
</property>
<bean id="customInterceptor" class="com.xyz.CustomInterceptor"></bean>
And I have write CustomInterceptor class
class CustomInterceptor extends HandlerInterceptorAdapter implements ServletContextAware {
//#override
public boolean preHandleAction(ActionRequest request, ActionResponse response, Object handler) {
...............
............
}
}
This CustomInterceptor should get call for every request before controller call.
But CustomInterceptor not getting called by spring.
Is anything goes wrong over here?
Thank You.
I may be late for responding to you question but you need to use below code..
<bean id="customInterceptor" class="com.xyz.CustomInterceptor"></bean>
<bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="customInterceptor" />
</list>
</property>
</bean>

Resources