001package org.kuali.common.util.spring.event; 002 003import static com.google.common.base.Preconditions.checkArgument; 004import static com.google.common.base.Preconditions.checkNotNull; 005 006import org.kuali.common.util.execute.Executable; 007import org.kuali.common.util.log.LoggerUtils; 008import org.slf4j.Logger; 009import org.springframework.context.ApplicationEvent; 010import org.springframework.context.event.SmartApplicationListener; 011 012/** 013 * <p> 014 * Associate an executable with a Spring framework application event. 015 * </p> 016 * 017 * <p> 018 * If the application event gets fired {@code onApplicationEvent} invokes the executable. 019 * </p> 020 */ 021public final class ExecutableApplicationEventListener<T extends ApplicationEvent> implements SmartApplicationListener { 022 023 private static final Logger logger = LoggerUtils.make(); 024 025 private final Executable executable; 026 private final int order; 027 private final Class<T> supportedEventType; 028 029 @Override 030 public void onApplicationEvent(ApplicationEvent event) { 031 checkEvent(event); 032 logger.info("Received event: [{}]", event.getClass().getCanonicalName()); 033 executable.execute(); 034 } 035 036 @Override 037 public int getOrder() { 038 return order; 039 } 040 041 @Override 042 public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { 043 return supportedEventType == eventType; 044 } 045 046 @Override 047 public boolean supportsSourceType(Class<?> sourceType) { 048 return true; 049 } 050 051 private void checkEvent(ApplicationEvent event) { 052 boolean expression = supportedEventType == event.getClass(); 053 String errorMessage = "[%s] is the only supported event type. Events of type [%s] should not be getting passed to this listener"; 054 Object[] args = { supportedEventType.getCanonicalName(), event.getClass().getCanonicalName() }; 055 checkArgument(expression, errorMessage, args); 056 } 057 058 private ExecutableApplicationEventListener(Builder<T> builder) { 059 this.executable = builder.executable; 060 this.order = builder.order; 061 this.supportedEventType = builder.supportedEventType; 062 } 063 064 public static <T extends ApplicationEvent> Builder<T> builder(Executable executable, Class<T> supportedEventType) { 065 return new Builder<T>(executable, supportedEventType); 066 } 067 068 public static class Builder<T extends ApplicationEvent> { 069 070 // Required 071 private final Executable executable; 072 private final Class<T> supportedEventType; 073 074 // Optional 075 private int order = 0; // Lower values mean higher priority, higher values mean lower priority 076 077 public Builder(Executable executable, Class<T> supportedEventType) { 078 this.executable = executable; 079 this.supportedEventType = supportedEventType; 080 } 081 082 public ExecutableApplicationEventListener<T> build() { 083 ExecutableApplicationEventListener<T> instance = new ExecutableApplicationEventListener<T>(this); 084 validate(instance); 085 return instance; 086 } 087 088 private void validate(ExecutableApplicationEventListener<T> instance) { 089 checkNotNull(instance.getExecutable(), "'executable' cannot be null"); 090 checkNotNull(instance.getSupportedEventType(), "'supportedEventType' cannot be null"); 091 } 092 093 public Builder<T> order(int order) { 094 this.order = order; 095 return this; 096 } 097 098 public int getOrder() { 099 return order; 100 } 101 102 public void setOrder(int order) { 103 this.order = order; 104 } 105 106 public Executable getExecutable() { 107 return executable; 108 } 109 } 110 111 public Executable getExecutable() { 112 return executable; 113 } 114 115 public Class<T> getSupportedEventType() { 116 return supportedEventType; 117 } 118 119}