Cannot find cache named '' for CacheableOperation[] caches - spring

My error is :
Exception in thread "main" java.lang.IllegalArgumentException: Cannot find cache named 'getActionsBycasId' for CacheableOperation[public java.util.List com.codinko.database.DataBaseConnection.getActionsByCasId(int)] caches=[getActionsBycasId] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless=''
at org.springframework.cache.interceptor.AbstractCacheResolver.resolveCaches(AbstractCacheResolver.java:81)
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:214)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.<init>(CacheAspectSupport.java:553)
at org.springframework.cache.interceptor.CacheAspectSupport.getOperationContext(CacheAspectSupport.java:227)
at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContexts.<init>(CacheAspectSupport.java:498)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.codinko.database.DataBaseConnection$$EnhancerBySpringCGLIB$$21a0d8a.getActionsByCasId(<generated>)
at com.codinko.caching.EmployeeDAO.getActionBycasId(EmployeeDAO.java:47)
at com.codinko.caching.EmployeeDAO$$FastClassBySpringCGLIB$$191aa49b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:649)
at com.codinko.caching.EmployeeDAO$$EnhancerBySpringCGLIB$$3399d753.getActionBycasId(<generated>)
at com.codinko.caching.Main.main(Main.java:22)
My function is :
#Cacheable("getActionsBycasId")
public List<SMSAction> getActionsByCasId(int casId){
System.out.println("Inside getActionsByCasId");
//My logic
return list;
}
when i add below on ehcache.xml then above error not comes but can't know why this error come .
<cache name="getActionsBycasId" maxElementsInMemory="50" eternal="false"
overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />
Is this above configuration required in ehcache.xml file even though i used annotation ????

Try this :
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<Cache>();
caches.add(new ConcurrentMapCache("getActionsBycasId"));
cacheManager.setCaches(caches);
return cacheManager;
}

If you use spring cloud aws, disable automatic elasticache configuration.
#EnableAutoConfiguration(exclude = ElastiCacheAutoConfiguration.class)
#EnableCaching
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

#SpringBootApplication(exclude = {
ContextStackAutoConfiguration.class,
ElastiCacheAutoConfiguration.class
})
Just being nit-picky use #SpringBootApplication instead of #EnableAutoConfiguration

Add ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns='http://www.ehcache.org/v3'>
<persistence directory="${java.io.tmpdir}" />
<!-- Default cache template -->
<cache-template name="default">
<expiry>
<tti unit="hours">4</tti>
<!-- <ttl unit="minutes">2</ttl> -->
</expiry>
<listeners>
<listener>
<class>com.org.lob.support.LoggingTaskCacheListener</class>
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<event-ordering-mode>UNORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>REMOVED</events-to-fire-on>
<events-to-fire-on>UPDATED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap unit="MB">10</heap>
<offheap unit="MB">50</offheap>
<disk persistent="true" unit="GB">1</disk>
</resources>
<!--
<heap-store-settings>
<max-object-graph-size>2000</max-object-graph-size>
<max-object-size unit="kB">5</max-object-size>
</heap-store-settings>
-->
</cache-template>
<!-- Cache configurations -->
<cache alias="books" uses-template="default" >
<key-type>java.lang.String</key-type>
<value-type>com.org.lob.project.repository.entity.Book</value-type>
</cache>
<cache alias="files" uses-template="default" >
<key-type>java.lang.String</key-type>
<value-type>java.lang.String</value-type>
</cache>
</config>
Update your application.properties
spring.cache.jcache.config=classpath:ehcache.xml

Try changing
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="cacheManagerName" value="cacheManager_service" />
<property name="configLocation" value="classpath:ehcache-services.xml" />
<property name="shared" value="true" />
</bean>
To
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" primary="true">
<property name="cacheManagerName" value="cacheManager_service" />
<property name="configLocation" value="classpath:ehcache-services.xml" />
</bean>

You can define ehcache.xml in resources folder and consider configuring ,, tags and set alias as your cache able method. It worked for me.

As you have in your class path resource an ehcache.xml file already with configurations, the best way there is to initialize a bean with this file configuration:
#Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
final EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
ehCacheManagerFactoryBean.setShared(true);
return ehCacheManagerFactoryBean;
}
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}

just create a #Bean like this in your unit-test's configurations:
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("cacheName1", "cacheName2", "cacheName3", "cacheNameN");
}

The above exclude option, didnt work for me. But, the below worked.!!
If you are using spring aws cloud, then exclude the elastic like below.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
<exclusions>
<exclusion>
<groupId>com.amazonaws</groupId>
<artifactId>
elasticache-java-cluster-client
</artifactId>
</exclusion>
</exclusions>
</dependency>

Related

Spring boot logbcak to file is not working on tomcat

I am running spring boot as War on tomcat with logback to console and file.
as long as i run as Java application it is fine i can see logs in console and file.
but i dont see logs printed to file when run on server.
I tried setting logger manager also, didnt work. was wondering to know if some one has faced similar issue.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}app.log}"/>
<property name="LOG_FILE_MAX_SIZE" value="10MB" />
<property name="LOG_TOTAL_SIZE_CAP" value="100MB" />
<property name="LOG_FILE_MAX_HISTORY" value="20" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Verify that you have the following dependency :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
or even if you have spring-boot-starter-web dependency added, logging should work.
and have the following in yml or properties file :
logging.path=logs
logging.file=${logging.path}/log.log
logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
and you can also have a logback.xml and use the spring default base.xml in that so that all default spring configurations apply for your logging as well :
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
Here is my logback-spring.xml which i have
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<property name="LOG_FILE"
value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}app.log}"/>
<property name="LOG_FILE_MAX_SIZE" value="10MB" />
<property name="LOG_TOTAL_SIZE_CAP" value="100MB" />
<property name="LOG_FILE_MAX_HISTORY" value="20" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
I could fix it by writing the logs to a different folder looks application doesn't have write access the path, however i need to make some changes to springboot main class for loading application props based profile, please find the class below. not sure if others had to the same.
anyway i am glad it is working finally:)
public class Application extends SpringBootServletInitializer{
public String PROFILE = null;
private static String CONFIG_LOCATION = null;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
//Grab the active profile from the servlet conext
PROFILE = servletContext.getInitParameter("spring.profiles.active");
CONFIG_LOCATION = servletContext.getInitParameter("spring.config.path");
super.onStartup(servletContext);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//...and pass it to the boot application
application.application().setAdditionalProfiles(PROFILE);
return application.sources(Application.class).properties(getProperties());
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//For Loading config from server
static Properties getProperties() {
Properties props = new Properties();
props.put("spring.config.location", CONFIG_LOCATION);
return props;
}
}
web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>
<context-param>
<param-name>spring.config.path</param-name>
<param-value>classpath:app.config/</param-value>
</context-param>

Spring MVC and EhCache is not working

I am trying to integrate ehcache into spring mvc and hibernate application but its not working below is the code. I have followed the link - how to use ehcache in spring mvc with hibernate but still i am facing the problem. This problem is coming when i am starting the sertver. I am using spring 5.0.5
springmvc.xml
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan">
<beans:array>
<beans:value>com.kalavakuri.springmvcandorm</beans:value>
</beans:array>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${hibernate.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">${hibernate.show_sql}</beans:prop>
<beans:prop key="hibernate.cache.use_second_level_cache">true</beans:prop>
<beans:prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</beans:prop>
<beans:prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</beans:prop>
<beans:prop key="hibernate.cache.use_query_cache">true</beans:prop>
<!-- <beans:prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</beans:prop> -->
</beans:props>
</beans:property>
</beans:bean>
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir" />
<!--defaultCache eternal="false" maxElementsInMemory="1000" maxElementsOnDisk="10000"
overflowToDisk="true" diskPersistent="true" timeToLiveSeconds="300" statistics="true"
copyOnWrite="true" / -->
<cache name="student" maxElementsInMemory="100000"
eternal="true" overflowToDisk="false" memoryStoreEvictionPolicy="LFU"
statistics="true" timeToLiveSeconds="3600" />
</ehcache>
I am getting below error:
Caused by: org.hibernate.cache.CacheException: On-the-fly creation of JCache Cache objects is not supported [org.hibernate.cache.spi.TimestampsRegion]
at org.hibernate.cache.ehcache.internal.EhcacheRegionFactory.createCache(EhcacheRegionFactory.java:106)
at org.hibernate.cache.ehcache.internal.EhcacheRegionFactory.getOrCreateCache(EhcacheRegionFactory.java:100)
at org.hibernate.cache.ehcache.internal.EhcacheRegionFactory.createTimestampsRegionStorageAccess(EhcacheRegionFactory.java:86)
at org.hibernate.cache.spi.support.RegionFactoryTemplate.buildTimestampsRegion(RegionFactoryTemplate.java:70)
at org.hibernate.cache.internal.EnabledCaching.<init>(EnabledCaching.java:80)
at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:33)
at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:24)
at org.hibernate.service.spi.SessionFactoryServiceInitiator.initiateService(SessionFactoryServiceInitiator.java:30)
at org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.initiateService(SessionFactoryServiceRegistryImpl.java:68)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
... 99 more
According to the hibernate documentation you must create other 2 cache regions
org.hibernate.cache.spi.UpdateTimestampsCache: thios should be as great as possible (ideally never expiring)
org.hibernate.cache.internal.StandardQueryCache
Hibernate can't crate them on the fly (above all the first one)
Actually by using ehcahe 3 and hibernate 5 I use this configuration:
#Configuration
#EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport
{
#Autowired
private Environment env;
#Bean("cacheManager")
#Override
public org.springframework.cache.CacheManager cacheManager()
{
return new JCacheCacheManager(createCacheManager());
}
private CacheManager createCacheManager()
{
long dimensioneCache = new Long(env.getProperty("arca.context.cache.size"));
long ttlMillisecondi = new Long(env.getProperty("arca.context.cache.ttl"));
org.ehcache.config.CacheConfiguration<Object, Object> cacheConfiguration = CacheConfigurationBuilder.
newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(dimensioneCache)
).withExpiry(Expirations.timeToLiveExpiration(new org.ehcache.expiry.Duration(ttlMillisecondi, TimeUnit.MILLISECONDS))).build();
Map<String, org.ehcache.config.CacheConfiguration<?, ?>> caches = createCacheConfigurations(cacheConfiguration);
//Creo la cache di hibernate org.hibernate.cache.spi.UpdateTimestampsCache.
//Dalla documentazione di hibernate https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#caching
ResourcePoolsBuilder rpb = ResourcePoolsBuilder.heap(dimensioneCache*1000000);
org.ehcache.config.CacheConfiguration<Object, Object> eternalCacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class, rpb).withExpiry(Expirations.noExpiration()).build();
caches.put("org.hibernate.cache.spi.UpdateTimestampsCache", eternalCacheConfiguration);
EhcacheCachingProvider provider = getCachingProvider();
DefaultConfiguration configuration = new DefaultConfiguration(caches, provider.getDefaultClassLoader());
CacheManager result = provider.getCacheManager(provider.getDefaultURI(), configuration);
return result;
}
private Map<String, org.ehcache.config.CacheConfiguration<?, ?>> createCacheConfigurations(org.ehcache.config.CacheConfiguration<Object, Object> cacheConfiguration)
{
Map<String, org.ehcache.config.CacheConfiguration<?, ?>> caches = new HashMap<>();
// I'm searcing for all objects with #Entity annotation in order to create cache regions
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
for (BeanDefinition bd : scanner.findCandidateComponents("it.test.models"))
{
String className = bd.getBeanClassName();
caches.put(className, cacheConfiguration);
}
//org.hibernate.cache.internal.StandardQueryCache creation
caches.put("org.hibernate.cache.internal.StandardQueryCache", cacheConfiguration);
return caches;
}
private EhcacheCachingProvider getCachingProvider()
{
return (EhcacheCachingProvider) Caching.getCachingProvider();
}
}
In my hibernate configuration I use this cache facory it.olegna.tests.hibernate.cache.config.JCacheRegionFactory its code is the following:
public class JCacheRegionFactory extends org.hibernate.cache.jcache.JCacheRegionFactory
{
private static final long serialVersionUID = 1021281213463444167L;
#Override
protected Cache<Object, Object> createCache(String regionName, Properties properties, CacheDataDescription metadata)
{
throw new IllegalArgumentException("Unknown hibernate cache: " + regionName);
}
}
I had the same issue. By adding #EnableCaching to the spring boot application #SpringBootApplication problem got resolved. Please try.

Spring Framework 5 and EhCache 3.5

I tried to use EhCache 3.5 caching features in our web application based on Spring Boot 2/Spring Framework 5.
I added EHCache dependency:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
Then created ehcache.xml file in src/main/resources folder:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<cache name="orders" maxElementsInMemory="100"
eternal="false" overflowToDisk="false"
memoryStoreEvictionPolicy="LFU" copyOnRead="true"
copyOnWrite="true" />
</ehcache>
Spring 5 reference guide does't mention EHCache usage, Spring 4 reference guide states: "Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it."
So I created controller OrderController and REST endpoint:
#Cacheable("orders")
#GetMapping(path = "/{id}")
public Order findById(#PathVariable int id) {
return orderRepository.findById(id);
}
Spring Boot configuration:
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But when I call this endpoint I get an exception:
Cannot find cache named 'orders' for Builder[public org.Order org.OrderController.findById(int)] caches=[orders] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
Then I tried to use example from Spring Framework 4:
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
#Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
But it doesn't compile because of exception:
The type net.sf.ehcache.CacheManager cannot be resolved. It is indirectly referenced from required .class file
Please, advise.
There is a mix of things here. Ehcache 3, which you are using, is used with Spring through JCache.
Which is why you need to use spring.cache.jcache.config=classpath:ehcache.xml.
Then, your Ehcache configuration is indeed an Ehcache 2 configuration. So is the EhCacheCacheManager. For JCache, you should use JCacheCacheManager. But in fact, you don't even need it with an ehcache.xml.
Here are the steps to make it work
Step 1: Set the correct dependencies. Note that you don't need to specify any version as they are provided by the parent pom dependency management. javax.cache is now version 1.1.
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
Step 2: Add an ehcache.xml file in src/main/resources. An example below.
<?xml version="1.0" encoding="UTF-8"?>
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.5.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.5.xsd">
<service>
<jsr107:defaults enable-management="false" enable-statistics="true"/>
</service>
<cache alias="value">
<resources>
<heap unit="entries">2000</heap>
</resources>
</cache>
</config>
Step 3: An application.properties with this line is needed to find the ehcache.xml
spring.cache.jcache.config=classpath:ehcache.xml
Note that since JCache is found in the classpath, Spring Cache will pick it as the cache provider. So there's no need to specify spring.cache.type=jcache.
Step 4: Enable caching like you did
#SpringBootApplication
#EnableCaching
public class Cache5Application {
private int value = 0;
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Cache5Application.class, args);
Cache5Application app = context.getBean(Cache5Application.class);
System.out.println(app.value());
System.out.println(app.value());
}
#Cacheable("value")
public int value() {
return value++;
}
}
You need to force it to use ehcache version 2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.3</version>
</dependency>
To use ehcache 3:
Here is the application:
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is the application.yml
spring:
cache:
ehcache:
config: ehcache.xml
Here a service with a counter for testing
#Service
public class OrderService {
public static int counter=0;
#Cacheable("orders")
public Order findById(Long id) {
counter++;
return new Order(id, "desc_" + id);
}
}
Here is a test to prove it is using the cache:
#RunWith(SpringRunner.class)
#SpringBootTest
public class OrderServiceTest {
#Autowired
private OrderService orderService;
#Test
public void getHello() throws Exception {
orderService.findById(1l);
assertEquals(1, OrderService.counter);
orderService.findById(1l);
assertEquals(1, OrderService.counter);
orderService.findById(2l);
assertEquals(2, OrderService.counter);
}
}
See here for working example.
I made additional research. The following configuration isn't picked up by Spring Boot(from application.properties):
spring.cache.ehcache.config=classpath:ehcache.xml
So I created jcache.xml and also put into src/main/resource folder:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<cache alias="orders">
<key-type>org.springframework.cache.interceptor.SimpleKey</key-type>
<value-type>java.util.Collections$SingletonList</value-type>
<heap unit="entries">200</heap>
</cache>
</config>
Then I changed setting in application.properties to
spring.cache.jcache.config=classpath:jcache.xml
Now Spring Caching works correctly. However it's still a question how to pick up ehcache.xml
Facing the same issue.
My ehcache.xml looks like
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<service>
<jsr107:defaults>
<jsr107:cache name="vehicles" template="heap-cache" />
</jsr107:defaults>
</service>
<cache-template name="heap-cache">
<heap unit="entries">20</heap>
</cache-template>
</config>
Have configured spring.cache.jcache.config=classpath:ehcache.xml in application.properties
Have #EnableCaching on my application class.
Have #CacheResult on my service implementation.
#CacheResult(cacheName = "vehicles") public VehicleDetail
getVehicle(#CacheKey String vehicleId) throws VehicleServiceException
Do NOTE that I do not have a CacheManager bean.
Would be really helpful if someone can point out what am I missing.
hmm.. changing ehcache.xml to, did the trick ..
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<service>
<jsr107:defaults enable-management="true"
enable-statistics="true" />
</service>
<cache alias="vehicles" uses-template="heap-cache" />
<cache-template name="heap-cache">
<heap unit="entries">20</heap>
</cache-template>
</config>

Spring 3.1.1 java based configuration issue of FreeMarkerConfigurer

I am using Spring 3.1.1 with Freemarker.
After I have successded to use the new concept of java based configuraion of the new spring 3.1.
Now I try to use Freemarker with it.
However,I got that exception:
javax.servlet.ServletException: Could not resolve view with name
'/welcome' in servlet with name 'appServlet'
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1139)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:927)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
Here is the WebConfig:
package com.springway.config;
#Configuration
#ComponentScan("com.springway")
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Inject
private Environment environment;
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJacksonHttpMessageConverter());
}
#Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(FreeMarkerView.class);
return viewResolver;
}
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath(
"/WEB-INF/freemarker.xml");
return configurer;
}
freemarker.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- freemarker config -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
<property name="freemarkerSettings">
<props>
<prop key="number_format">0.######</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
</map>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
<!--
View resolvers can also be configured with ResourceBundles or XML files. If you need
different view resolving based on Locale, you have to use the resource bundle resolver.
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
</bean>
</beans>
The controller :
#RequestMapping(value="/", method=RequestMethod.GET)
public ModelAndView home(Principal user) {
return new ModelAndView("/welcome.ftl");
}
I am struggling the same problem as yours. And I tried to turn on logging level "DEBUG" for "org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer". I found following message:
java.io.FileNotFoundException: ServletContext resource [/WEB-INF/freemarker/] cannot be resolved to URL because it does not exist
at org.springframework.web.context.support.ServletContextResource.getURL(ServletContextResource.java:154) ~[spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.web.context.support.ServletContextResource.getFile(ServletContextResource.java:169) ~[spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.ui.freemarker.FreeMarkerConfigurationFactory.getTemplateLoaderForPath(FreeMarkerConfigurationFactory.java:351) [spring-context-support-3.1.1.RELEASE.jar:3.1.1.RELEASE]
at org.springframework.ui.freemarker.FreeMarkerConfigurationFactory.createConfiguration(FreeMarkerConfigurationFactory.java:304) [spring-context-support-3.1.1.RELEASE.jar:3.1.1.RELEASE]
.....
And a wired log from Jetty:
WARN org.eclipse.jetty.util.log - /freemarker/
I don't know what going on! So that I replaced the value of "templateLoaderPath" with another name, like "/WEB-INF/tmpl-freemarker/", then everything is workable!!
Next, I tried to use ServerContext.getResource() to test "/WEB-INF/freemarker/html.ftl". Here is the result:
Resource under /WEB-INF/freemarker/: null
My code of testing:
#Inject
private ServletContext servletContext;
try {
logger.info("Resource under /WEB-INF/freemarker/: {}", servletContext.getResource("/WEB-INF/freemarker/html.ftl"));
} catch(Exception e) {
logger.info("Exception while getResource", e);
}
It seems ServletContext can't find out the resource under "/WEB-INF/freemarker/" correctly either. But I'm not sure the object of ServletContext of Spring is as same as one on normal environment of Java Servlet.
I'm using FreeMarker 2.3.19, Springframework 3.1.1.RELEASE, and jetty-maven-plugin 7.4.5.v20110725 of Maven.
#Configuration
#EnableWebMvc
#ImportResource("classpath:/security-integration.xml")
#ComponentScan("com.springway")
public class WebConfiguration extends WebMvcConfigurerAdapter {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public FreeMarkerViewResolver viewResolver() {
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setCache(true);
freeMarkerViewResolver.setPrefix("");
freeMarkerViewResolver.setSuffix(".ftl");
return freeMarkerViewResolver;
}
#Bean
public FreeMarkerConfigurer freemarkerConfig() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("/WEB-INF/freemarker/");
Properties settings = new Properties();
settings.setProperty("number_format", "0.######");
freeMarkerConfigurer.setFreemarkerSettings(settings);
Map variables = new java.util.HashMap<String, Object>();
variables.put("xml_escape", new XmlEscape());
freeMarkerConfigurer.setFreemarkerVariables(variables);
return freeMarkerConfigurer;
}
}
You might have done wrong import
import org.springframework.web.portlet.ModelAndView;
instead of do this
import org.springframework.web.servlet.ModelAndView;

Shiro Authorization Permission check using Annotation not working

Platform: Shiro 1.1.0, Spring 3.0.5
I'm trying to secure the MVC Controller methods using Shiro annotation. However something is wrong with annotations. Regular calls are just working OK. There is nothing specific in Shiro debug also.
My shiro configuration:
<!-- Security Manager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="sessionMode" value="native" />
<property name="realm" ref="jdbcRealm" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- Caching -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehCacheManager" />
</bean>
<bean id="ehCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
<bean id="sessionDAO"
class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" />
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="sessionDAO" />
</bean>
<!-- JDBC Realm Settings -->
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="name" value="jdbcRealm" />
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="SELECT password FROM system_user_accounts WHERE username=? and status=1" />
<property name="userRolesQuery"
value="SELECT role_name FROM system_roles r, system_user_accounts u, system_user_roles ur WHERE u.user_id=ur.user_id AND r.role_id=ur.role_id AND u.username=?" />
<property name="permissionsQuery"
value="SELECT permission_name FROM system_roles r, system_permissions p, system_role_permission rp WHERE r.role_id=rp.role_id AND p.permission_id=rp.permission_id AND r.role_name=?" />
<property name="permissionsLookupEnabled" value="true"></property>
</bean>
<!-- Spring Integration -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!-- Enable Shiro Annotations for Spring-configured beans. Only run after
the lifecycleBeanProcessor has run: -->
<bean id="annotationProxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean
class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations
can be associated with a Subject for security checks. -->
<bean id="secureRemoteInvocationExecutor"
class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Shiro filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/dashboard" />
<property name="unauthorizedUrl" value="/error" />
<property name="filterChainDefinitions">
<value>
<!-- !!! Order matters !!! -->
/authenticate = anon
/login = anon
/logout = anon
/error = anon
/** = authc
</value>
</property>
</bean>
I can get the following working correctly:
#RequestMapping(value="/form")
public String viewPatientForm(Model model, #RequestParam(value="patientId", required=false) Long patientId){
if (!SecurityUtils.getSubject().isPermitted("hc:viewPatient")){
logger.error("Operation not permitted");
throw new AuthorizationException("No Permission");
}
}
But the below doesn't work:
#RequiresPermissions("hc:patientView")
#RequestMapping(value="/form")
public String viewPatientForm(Model model, #RequestParam(value="patientId", required=false) Long patientId){
Am I missing something? Please help.
You were absolutely right. After seeing your comment, I started giving it a thought. Well then I found out that it was NOT an implementation problem with Shiro, but the jar dependecies were not properly configured. Shiro's pom.xml should have dependency for cglib2 too.
So the below changes worked for me :
Include all these four jar files.
aspectjrt-1.6.11.jar,
aspectjweaver-1.6.12.jar,
cglib-2.2.2.jar,
asm-3.3.1.jar,
If you are using maven then :
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
And finally placing the aop:aspectj-autoproxy in the webApplicationContext.xml
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Annotation, so that it's easier to search controllers/components -->
<context:component-scan base-package="com.pepsey.soft.web.controller"/>
Note : The above two configuration should be placed together in the same spring-webApplicationContext.xml. Otherwise it won’t work. Moreover remove context:annotation-config if you have used it in your config. context:component-scan already scans all annotations.
Once you start testing , set your log4j to debug or (better) trace mode. Whenever you are starting your server you will find somewhere the following entry in your logs :
08:16:24,684 DEBUG AnnotationAwareAspectJAutoProxyCreator:537 -
Creating implicit proxy for bean 'userController' with 0 common
interceptor and 1 specific interceptors
Guess Shiro was built when Spring 2.0 was in place. Shiro’s annotations (RequiresRoles etc…) works well for the spring container managed beans (service layer), but it does not work with #Controller annotation. This is due to the fact that #Controller is being component scanned by spring framework. I used AOP to resolve the issue. Below is the solution which worked for me.
For the below solution to work you have to include the below four jars:
aspectjrt-1.6.11.jar
aspectjweaver-1.6.12.jar
cglib-2.2.2.jar
asm-3.3.1.jar
If you are using maven then below configuration would be helpful.
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Below is a controller class
import org.apache.shiro.authz.annotation.RequiresRoles;
#Controller
public class PatientController {
#RequiresRoles(“admin,warden”)
#RequestMapping(value="/form")
public String viewPatientForm(Model model, #RequestParam(value="patientId", required=false) Long patientId){
return “somePatientFormJsp”;
}
}
Create the below Aspect for the annotation (RequiresRoles). You can use the same principle to create pointcuts for RequiresPermission.
import java.util.Arrays;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class WebAuthorizationAspect {
#Before("#target(org.springframework.stereotype.Controller) && #annotation(requiresRoles)")
public void assertAuthorized(JoinPoint jp, RequiresRoles requiresRoles) {
SecurityUtils.getSubject().checkRoles(Arrays.asList(requiresRoles.value()));
}
}
In your spring-webApplicationContext.xml wherever you have mentioned
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Annotation, so that it's easier to search controllers/components -->
<context:component-scan base-package="com.example.controller"/>
Note : The above two configuration should be placed together in the same spring-webApplicationContext.xml. Otherwise it won’t work. Moreover remove context:annotation-config if you have used it in your config. context:component-scan already scans all annotations.
If you're avoiding Spring XML and using primarily Java and annotation configuration, the easiest way to fix this is to add
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
to all your #Controller classes. You need cglib on the classpath.
I have only used spring-hibernate example from sample. To use annotations like #RequiresPermissions and others I tried configuration from shiro manual, configuration from this post, but I was either unsuccessful to compile or run the valid urls. So I only commented all the #RequiresPermissions from ManageUserController and started to use it in service implementation. E.g In DefaultUserService in getAllUsers method I added the annotation #RequiresPermissions("user:manage"). Magically now the application works as expected. Whenever the url manageUsers is called it displays the list page if the user has role user:manage and throws the user to /unauthorized if the user don't have that permission.
I have even configured the application to use mysql instead. To make the permissions independent of roles according to new RBAC(http://www.stormpath.com/blog/new-rbac-resource-based-access-control) I have created a new class called Permission as
#Entity
#Table(name = "permissions")
#Cache(usage= CacheConcurrencyStrategy.READ_WRITE)
public class Permission {
#Id
#GeneratedValue
private Long id;
private String element;
private String description;
// setter and getter
Now Role class is configured as
#CollectionOfElements
#JoinTable(name="roles_permissions")
#Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public Set<Permission> getPermissions() {
return permissions;
}
And finally SampleRealm as
for (Role role : user.getRoles()) {
info.addRole(role.getName());
System.out.println("Roles " + role.getName());
// Get permissions first
Set<Permission> permissions = role.getPermissions();
Set<String> permissionsStrings = new HashSet<String>();
for (Permission permission : permissions) {
permissionsStrings.add(permission.getelement());
System.out
.println("Permissions " + permission.getelement());
}
info.addStringPermissions(permissionsStrings);
}
It creates five tables as
| permissions |
| roles |
| roles_permissions |
| users |
| users_roles |
And permissions is independent of any other. According to new RBAC you have both ways (explicit and implicit) way of authorising resources.
You need to write the AuthorizationAttributeSourceAdvisor to enable Shiro's annotations bean as per the Shiro documentation
If you have written ShiroConfiguration class, make sure you include this:
#Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
#Bean
#ConditionalOnMissingBean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultSecurityManager securityManager) {
// This is to enable Shiro's security annotations
AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
sourceAdvisor.setSecurityManager(securityManager);
return sourceAdvisor;
}
#ConditionalOnMissingBean
#Bean(name = "defaultAdvisorAutoProxyCreator")
#DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
Example ShiroConfiguration on Github
I had the same problem. My fix was changing my jersey version from 2.2 to 2.22.2 and all #RequiresPermissions worked on my controllers.

Resources