diff --git a/tesler-core/src/main/java/io/tesler/core/autoconfigure/AutoConfiguration.java b/tesler-core/src/main/java/io/tesler/core/autoconfigure/AutoConfiguration.java new file mode 100644 index 0000000000..c5efc143c5 --- /dev/null +++ b/tesler-core/src/main/java/io/tesler/core/autoconfigure/AutoConfiguration.java @@ -0,0 +1,43 @@ +/*- + * #%L + * IO Tesler - Core + * %% + * Copyright (C) 2018 - 2019 Tesler Contributors + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package io.tesler.core.autoconfigure; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AliasFor; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Configuration +public @interface AutoConfiguration { + + @AliasFor(annotation = Configuration.class, attribute = "proxyBeanMethods") + boolean proxyBeanMethods() default true; + + @AliasFor(annotation = Configuration.class, attribute = "proxyBeanMethods") + String value() default ""; + +} diff --git a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheAutoConfiguration.java b/tesler-core/src/main/java/io/tesler/core/autoconfigure/cache/TeslerCacheAutoConfiguration.java similarity index 73% rename from tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheAutoConfiguration.java rename to tesler-core/src/main/java/io/tesler/core/autoconfigure/cache/TeslerCacheAutoConfiguration.java index de0ededcd1..eb7d0e98ed 100644 --- a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheAutoConfiguration.java +++ b/tesler-core/src/main/java/io/tesler/core/autoconfigure/cache/TeslerCacheAutoConfiguration.java @@ -18,11 +18,20 @@ * #L% */ -package io.tesler.core.config.cache; - +package io.tesler.core.autoconfigure.cache; + +import com.google.common.collect.ImmutableList; +import io.tesler.core.autoconfigure.AutoConfiguration; +import io.tesler.core.config.cache.CacheConfig; +import io.tesler.core.config.cache.CacheManagerBasedCacheResolver; +import io.tesler.core.config.cache.TeslerCaches; +import io.tesler.core.config.cache.TeslerRequestAwareCacheHolder; import io.tesler.core.metahotreload.MetaHotReloadService; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import javax.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; -import org.jetbrains.annotations.NotNull; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.autoconfigure.cache.CacheProperties; @@ -42,16 +51,22 @@ import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.web.context.annotation.RequestScope; import org.springframework.web.context.request.RequestContextHolder; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.stream.Collectors; -@Configuration +/** + *

Auto-configuration class which declares "teslerCacheResolver" bean of type CacheResolver.

+ *

As it says in the Spring documentation:

+ *

Auto-configuration is non-invasive. At any point, you can start to define your own configuration to replace specific parts of the auto-configuration.

+ *

It follows that if you declare a bean with name "teslerCacheResolver" and type {@link CacheResolver CacheResolver} in a project, which defines dependency on Tesler, this autoconfiguration will be ignored, otherwise it will create the "teslerCacheResolver" bean {@link #teslerCacheResolver defined below}. + * A bean named "teslerCacheResolver" is used by Tesler in all annotations which are related to Spring cache abstraction.

+ *

{@link AutoConfiguration @AutoConfiguration} is nothing but alias for {@link org.springframework.context.annotation.Configuration @Configuration}, + * it is used to exclude a class from component scanning (see {@link io.tesler.core.config.BeanScan @BeanScan}).

+ * + * @see CacheManagerBasedCacheResolver + */ +@AutoConfiguration @ConditionalOnClass({CacheManager.class}) @ConditionalOnMissingBean(name = "teslerCacheResolver") @ConditionalOnBean({CacheAspectSupport.class}) @@ -67,17 +82,12 @@ public class TeslerCacheAutoConfiguration { public CacheResolver teslerCacheResolver(MetaHotReloadService metaHotReloadService) { metaHotReloadService.loadMeta(); if (CacheType.NONE.equals(cacheProperties.getType())) { - return new TeslerCacheResolver(new NoOpCacheManager()); + return new CacheManagerBasedCacheResolver(new NoOpCacheManager()); } CompositeCacheManager compositeCacheManager = new CompositeCacheManager(); compositeCacheManager.setCacheManagers(buildCacheManagers()); compositeCacheManager.setFallbackToNoOpCache(true); - return new TeslerCacheResolver(compositeCacheManager); - } - - @Bean - public TeslerRequestAwareCacheHolder userCache() { - return new TeslerRequestAwareCacheHolder(new ConcurrentMapCache(CacheConfig.USER_CACHE)); + return new CacheManagerBasedCacheResolver(compositeCacheManager); } @Bean @@ -86,13 +96,12 @@ public TeslerRequestAwareCacheHolder requestCache() { return new TeslerRequestAwareCacheHolder(new ConcurrentMapCache(CacheConfig.REQUEST_CACHE)); } - protected List buildCacheManagers() { List result = new ArrayList<>(); result.add(buildUnExpirableCacheManager( TeslerCaches.getSimpleCacheNames().toArray(new String[0]) )); - result.add(buildRequestAwareCacheManager(TeslerCaches.getRequestCaches())); + result.add(buildRequestAwareCacheManager(TeslerCaches.getRequestCacheName())); return result; } @@ -100,11 +109,10 @@ protected CacheManager buildUnExpirableCacheManager(String... names) { return new ConcurrentMapCacheManager(names); } - protected CacheManager buildRequestAwareCacheManager(List cacheNames) { + protected CacheManager buildRequestAwareCacheManager(String cacheName) { SimpleCacheManager simpleCacheManager = new SimpleCacheManager(); - simpleCacheManager.setCaches(cacheNames.stream() - .map(RequestAwareCacheDecorator::new) - .collect(Collectors.toList()) + simpleCacheManager.setCaches( + ImmutableList.of(new RequestAwareCacheDecorator(cacheName)) ); simpleCacheManager.initializeCaches(); return simpleCacheManager; diff --git a/tesler-core/src/main/java/io/tesler/core/config/BeanScan.java b/tesler-core/src/main/java/io/tesler/core/config/BeanScan.java index 69c027a306..e8c67f153e 100644 --- a/tesler-core/src/main/java/io/tesler/core/config/BeanScan.java +++ b/tesler-core/src/main/java/io/tesler/core/config/BeanScan.java @@ -21,6 +21,7 @@ package io.tesler.core.config; import io.tesler.api.util.spring.ServiceBasedComponentExcludeFilter; +import io.tesler.core.autoconfigure.AutoConfiguration; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -45,6 +46,7 @@ @Filter(value = {Aspect.class}, type = FilterType.ANNOTATION) }, excludeFilters = { + @Filter(value = {AutoConfiguration.class}, type = FilterType.ANNOTATION), @Filter(value = {Controller.class, ControllerAdvice.class}, type = FilterType.ANNOTATION), @Filter(value = { WebMvcConfigurer.class, diff --git a/tesler-core/src/main/java/io/tesler/core/config/CoreApplicationConfig.java b/tesler-core/src/main/java/io/tesler/core/config/CoreApplicationConfig.java index abce3342f0..5cb761bcb1 100644 --- a/tesler-core/src/main/java/io/tesler/core/config/CoreApplicationConfig.java +++ b/tesler-core/src/main/java/io/tesler/core/config/CoreApplicationConfig.java @@ -29,18 +29,18 @@ import io.tesler.model.core.dao.JpaDao; import io.tesler.model.core.service.BaseEntityListenerDelegate; import io.tesler.model.core.service.TeslerBaseEntityListenerDelegate; -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.aspectj.EnableSpringConfigured; @EnableAspectJAutoProxy @BeanScan({"io.tesler"}) @EnableSpringConfigured -@ImportAutoConfiguration({ +@Import({ MetaHotReloadConfiguration.class, TeslerFileConfiguration.class }) @@ -58,4 +58,5 @@ public ResponsibilitiesService responsibilitiesService(JpaDao jpaDao) { public BaseEntityListenerDelegate baseEntityListenerDelegate(CurrentUserAware currentUserAware) { return new TeslerBaseEntityListenerDelegate(currentUserAware); } + } diff --git a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheResolver.java b/tesler-core/src/main/java/io/tesler/core/config/cache/CacheManagerBasedCacheResolver.java similarity index 93% rename from tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheResolver.java rename to tesler-core/src/main/java/io/tesler/core/config/cache/CacheManagerBasedCacheResolver.java index 9ec03aef8a..90891d5579 100644 --- a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCacheResolver.java +++ b/tesler-core/src/main/java/io/tesler/core/config/cache/CacheManagerBasedCacheResolver.java @@ -25,9 +25,9 @@ import java.util.Collections; import java.util.List; import java.util.Set; +import javax.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.interceptor.CacheOperationInvocationContext; @@ -35,7 +35,7 @@ @Slf4j @RequiredArgsConstructor -public class TeslerCacheResolver implements CacheResolver { +public class CacheManagerBasedCacheResolver implements CacheResolver { private final CacheManager teslerCachesManager; diff --git a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCaches.java b/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCaches.java index d60e4f1079..f205bc551f 100644 --- a/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCaches.java +++ b/tesler-core/src/main/java/io/tesler/core/config/cache/TeslerCaches.java @@ -20,13 +20,11 @@ package io.tesler.core.config.cache; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.experimental.UtilityClass; - import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import lombok.Getter; +import lombok.experimental.UtilityClass; @UtilityClass public class TeslerCaches { @@ -38,24 +36,30 @@ public static List getSimpleCacheNames() { .collect(Collectors.toList()); } - public static List getRequestCaches() { - return Arrays.stream(Caches.values()) - .filter(Caches::isRequestScope) - .map(Caches::name) - .collect(Collectors.toList()); + public static String getRequestCacheName() { + return Caches.requestCache.name(); } - @AllArgsConstructor + @Getter public enum Caches { - linkedDictionaryRules(false), - specifications(false), - widgetcache(false), - notificationSettings(false), - workflow(false), + linkedDictionaryRules, + specifications, + widgetcache, + notificationSettings, + workflow, requestCache(true), - userCache(true); + userCache; private final boolean requestScope; + + Caches(boolean requestScope) { + this.requestScope = requestScope; + } + + Caches() { + this.requestScope = false; + } } + } diff --git a/tesler-core/src/main/java/io/tesler/core/file/service/TeslerFileServiceSimple.java b/tesler-core/src/main/java/io/tesler/core/file/service/TeslerFileServiceSimple.java index e6a4bcc655..cc580d03f8 100644 --- a/tesler-core/src/main/java/io/tesler/core/file/service/TeslerFileServiceSimple.java +++ b/tesler-core/src/main/java/io/tesler/core/file/service/TeslerFileServiceSimple.java @@ -25,10 +25,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.UUID; +import javax.annotation.Nullable; import lombok.NonNull; import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.stereotype.Service; import org.springframework.util.FileCopyUtils; diff --git a/tesler-core/src/main/resources/META-INF/spring.factories b/tesler-core/src/main/resources/META-INF/spring.factories index 192c4c7cff..60d5cc1533 100644 --- a/tesler-core/src/main/resources/META-INF/spring.factories +++ b/tesler-core/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -io.tesler.core.config.cache.TeslerCacheAutoConfiguration \ No newline at end of file +io.tesler.core.autoconfigure.cache.TeslerCacheAutoConfiguration \ No newline at end of file