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}