Spring retry - can #Recover be in standalone class? - spring

I have a Spring Integration app with multiple endpoint that process the same data in different ways.
They all have identical '#Recover' methods which has become boilerplate and seems fragile.
Can you you centralize the #Recover method (e.g. in a standalone class) and/or can you specify how to find this #Recover annotated method?

It's not clear why would one use a #Retryable in Spring Integration when there is that RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain...
Anyway see this option on the #Retryable:
/**
* Retry interceptor bean name to be applied for retryable method. Is mutually
* exclusive with other attributes.
* #return the retry interceptor bean name
*/
String interceptor() default "";
So, instead of #Recover method you provide your own:
#Bean
public MethodInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.maxAttempts(...)
.recoverer(...)
.build();
}
...
#Retryable(interceptor = "retryInterceptor")
public void service() {

Related

Spring Session MapSessionRepository

I am attempting to use a MapSessionRepository and HttpSessionEventPublisher in Spring Session declared like this:
#Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepositoryImpl(new ConcurrentHashMap<>());
}
#Bean
public HttpSessionEventPublisher eventPublisher() {
return new HttpSessionEventPublisher();
}
I also have
In the javadoc for the class, I see the following:
The implementation does NOT support firing {#link SessionDeletedEvent} or {#link SessionExpiredEvent}.
To me, this implies that it should support the basic SessionCreatedEvent and SessionDestroyedEvent, but nothing seems to be published.
Since I'm not trying to use one of the full distributed data stores, I have this in my application.properties:
spring.session.store-type=none
My question is, will the MapSessionRepository support publishing events if it's initialized with a ConcurrentHashMap?

Spring Boot role validation controller using aspect

I have several controller functions separated by role, and instead of doing role validation in each controller method, I found that it seems to be able to get done by using Aspect, however something isn't right in my implementation as the code in Aspect never runs
Annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface ForMerchantOnly {}
Aspect:
#Aspect
#Configuration
public class ForMerchantOnlyAspect {
private static final Logger logger = LogManager.getLogger(ForMerchantOnlyAspect.class);
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && args(request)")
public void before(HttpServletRequest request) throws ServiceException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("request should be HttpServletRequesttype");
}
String domain = request.getServerName();
System.out.println("Aspect showing domain " + domain);
// -- other code
}
}
Controller
#ForMerchantOnly
#GetMapping("/list")
public ResponseEntity<ApiResp> list() {
System.out.println("Show something");
return ResponseEntity.ok().body();
}
I'm assuming when i call controller /list method via chrome browser, it would hit the code in ForMerchantOnlyAspect but it just went into the controller method directly. Am I missing something?
The Aspect was not working as it could not find a matching joinpoint . There are no controller methods that has annotation #ForMerchantOnly and has an argument of type HttpServletRequest
From the documentation :
args: Limits matching to join points (the execution of methods when
using Spring AOP) where the arguments are instances of the given
types.
Following aspect may be used for the requirement . Scoping designator within will set the scope to advice.
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && within(com.example.api..*)")
public void before() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
System.out.println("Aspect showing domain " + request.getServerName());
}
Also note that an Aspect is better annotated with #Component and #Configuration be used for configurations.
You may also have a look at Method Security of Spring security framework , which lets to secure a method with annotations.
From the documentation
From version 2.0 onwards Spring Security has improved support
substantially for adding security to your service layer methods. It
provides support for JSR-250 annotation security as well as the
framework’s original #Secured annotation. From 3.0 you can also make
use of new expression-based annotations. You can apply security to a
single bean, using the intercept-methods element to decorate the bean
declaration, or you can secure multiple beans across the entire
service layer using the AspectJ style pointcuts.

Get annoted method endpoints for JMS

Is there any way through which I can find all the configured MethodJmsListenerEndpoint's through annotations?
I want to register all these end points with different message listener containers.
#JmsListener(destination = "TestQueue")
public void process(String msg) {
System.out.println(msg);
}
//TODO for all connections
foreach(connections){
//TODO get all annotated endpoints as prototype
foreach(endpoint){
MethodJmsListenerEndpoint processEndpoint = endpoint;
registrar.registerEndpoint(processEndpoint,containerFactory(connection));
}
}
Depends on your provider you can use configuration customizer bean like HornetQConfigurationCustomizer to manipulate any settings during this bean initialization.
If your configuration should be really adoptive and manageable in runtime then you should not use #JmsListener annotation at all. Just register them all in your code like Spring advises: JMS

Event Listeners in spring is called twice

I am an issue with Spring Event Listeners In my Web app, Any immediate help will be appreciated.
Event Listeners is registered and called twice, If I have cyclic dependency.
I have service class, this has #transaction annotation on another methods
#Service(PBSTaskService.BEAN_NAME)
public class PBSTaskServiceImpl extends StandardServiceImpl<ITask> implements PBSTaskService,ApplicationListener<SurveyDefinitionPublishedEvent>
{
#Autowired
private AutoSelectTaskSliceRouteSyncService autoSelectTaskSliceRouteSyncService; // CYCLIC Dependency
#Override
public void onApplicationEvent(SurveyDefinitionPublishedEvent event)
{
System.out.println("PBSTSImpl"); // THIS IS CALLED TWICE
}
... Other method with #Transaction Annotation
}
#Service(AutoSelectTaskSliceRouteSyncService.BEAN_NAME)
public class AutoSelectTaskSliceRouteSyncServiceImpl implements AutoSelectTaskSliceRouteSyncService
{
#Autowired private PBSTaskService pbsTaskService; // CYCLIC dependency
}
Now If I remove AutoSelectTaskSliceRouteSyncService dependency from First Class, OnApplicationEvent is called once, else twice.
I debugged and found out that
SimpleApplicationEventMulticaster.getApplicationListeners(myEvent) : Has two proxy object, one wrapped with Cglib and another default one. But it has two only in case if it has cyclic dependency. If I remove Cyclic dependency, it has only one proxy object and that one is enahnces by CGLIB.
my Tx annotation :
I had tried it with proxy-target-class="true or false" but no luck.
You may want to have a look on
https://jira.springsource.org/browse/SPR-7940?focusedCommentId=98988&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-98988
Since Spring 4.2 you can do away with implementing ApplicationListener and use the new #EventListener annotation on methods in any managed bean. This should help you avoid any conflicts.
Below is an example from https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
#Component
public class MyListener {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
ApplicationEvent Listeners are called twice at many more places in our web app. This is one of scenarios that we caught up.
Reason :
Listeners are registered twice. Two proxy are returned wrapped over one instance of listeners. Proxy returned are 1. Dynamic Jdk Interface proxy 2. Cglib Proxy, when we have #transactions annotations.
To recreate these three point are must:
Your listeners must implements ApplicationListener 2. Your listeners must have cyclic dependency with another class 3.Your listeners must have one method annotated with #Transaction.
I have created a separate project where I am able to reproduce it with spring and hibernate. If 2 and 3 are not present together, then we are safe.
Solution
I tried many tweaks with spring and transaction configuration but no luck. Then finally with my demo project when I moved the transaction code to another class, so that the listeners do not have any #transaction annotations then it worked for me.
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events. To resolve the issue, to only receive single events, just remove the #Service or #Compontent annotation.
In a case of circular dependency between Spring beans, Spring Beans machinery might (under certain circumstances) place two versions of a same bean, the bean itself and its Advised wrapper into the list of ApplicationListeners handled by an ApplicationEventMulticaster.
You could, however, implement your custom ApplicationEventMulticaster and fix this bug (it looks like a bug to me).
In a snippet below a custom implementation subclasses Spring's SimpleApplicationEventMulticaster, ignores non-Advised duplicate of a bean, and leaves Advised version of it in the list of ApplicationListeners (most likely you would want an Advised version of your onApplicationEvent method to be called - in a case it is annotated with #Transactional or AOP-advised, but if you need otherwise, the change of algorithm is trivial)
#Component
public class AdviceAwareApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
#Override
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Map<ApplicationListener<?>, ApplicationListener<?>> listenersByNakedInstances = new LinkedHashMap<>();// because superclass returns sorted listeners
Collection<ApplicationListener<?>> applicationListeners = super.getApplicationListeners(event, eventType);
for (ApplicationListener<?> listener : applicationListeners) {
boolean advised = false;
ApplicationListener<?> nakedListener = null;
if (listener instanceof Advised) {
try {
nakedListener = (ApplicationListener<?>) ((Advised)listener).getTargetSource().getTarget();
} catch (Exception e) {
// TODO
}
advised = true;
} else
nakedListener = listener;
if (advised || !listenersByNakedInstances.containsKey(nakedListener))
listenersByNakedInstances.put(nakedListener, listener);
}
return listenersByNakedInstances.values();
}
}
You don't need to anyhow make your custom implementation known to Spring, it's enough to have it as a Spring bean and Spring Application Context will pick it up.
Also, don't forget that if there are more one Spring Application Contexts in the application, your Listener might be called for each of those, but it's altogether different story.
I was running into the same issue with one of my services, created another listner with the same event that was only called once.
So what #SimonH wrote is not always the case, only in some circumstances I could not reproduce:
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events.
In my case this lead to a double call of the onApplicationEvent method.
#Service
public class TestClass implements ApplicationListener<MyEvent>{
#Override
public void onApplicationEvent(MyEvent event){
// called twice
}
}
Instead of the code above, I could solve it by creating the Event Listener as an inner class and then call the event method of the parent.
#Service
public class TestClass {
#Component
private class MyListener implements ApplicationListener<MyEvent> {
#Override
public void onApplicationEvent(MyEvent event) {
TestClass.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(MyEvent event){
//Have fun with a single event here
}
}

What does the #Secure annotation do and what package is it apart of

I'm writing an API using Java EE, JAX-RS, Jersey. In doing this I've implemented my own security context and security filter.
Looking at questions like this one (How to get MIME type of uploaded file in Jersey) I've seen the #Secure annotation but what does it do? My hope was that is was an annotation that queries the isSecure method of the security context in the same way that #RolesAllowed does for checking if a user has the right to access a particular method. If so is there such a way of doing so with annotations or am I stuck to using the #Context to get the security context and just from that.
The #Secure annotation seems to be a custom one. JAX-RS/Jersey does not support such feature out-of-the-box but it's not that hard to implement. Lets say you have your own #Secure annotation and you want to do checks whether a communication channel is secure for methods annotated with this annotation. You need to create a custom ResourceFilterFactory in which you'll assign a special filter for such methods:
public class IsSecureResourceFilterFactory implements ResourceFilterFactory {
private class IsSecureFilter implements ResourceFilter, ContainerRequestFilter {
// ResourceFilter
#Override
public ContainerRequestFilter getRequestFilter() {
return this;
}
#Override
public ContainerResponseFilter getResponseFilter() {
return null;
}
// ContainerRequestFilter
#Override
public ContainerRequest filter(final ContainerRequest request) {
// Check whether the channel is secure.
if (request.isSecure()) {
return request;
}
// Throw an exception if it's not.
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
}
#Override
public List<ResourceFilter> create(final AbstractMethod abstractMethod) {
// Add IsSecureFilter for resource methods annotated with #Secure annotation (ignore other resource methods).
return abstractMethod.isAnnotationPresent(Secure.class)
? Collections.<ResourceFilter>singletonList(new IsSecureFilter()): null;
}
}
Now you need to tell Jersey about this ResourceFilterFactory. There are 2 ways:
via web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>my.package.IsSecureResourceFilterFactory</param-value>
</init-param>
or via META-INF/services mechanism - you need to create a file called META-INF/services/com.sun.jersey.spi.container.ResourceFilterFactory which would contain a fully qualified name of your factory (in this case my.package.IsSecureResourceFilterFactory) and make sure this file is on the class-path of your application.

Resources