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 java.util.List;
007
008import org.kuali.common.util.execute.Executable;
009import org.kuali.common.util.log.LoggerUtils;
010import org.slf4j.Logger;
011import org.springframework.context.ApplicationEvent;
012import org.springframework.context.event.SmartApplicationListener;
013
014import com.google.common.collect.ImmutableList;
015
016/**
017 * <p>
018 * Associate an executable with one or more Spring framework application events.
019 * </p>
020 * 
021 * <p>
022 * If an application event gets fired where both {@code supportsEventType} and {@code supportsSourceType} return {@code true}, {@code onApplicationEvent} invokes the executable.
023 * </p>
024 * 
025 * <p>
026 * The default behavior of {@code supportsEventType} and {@code supportsSourceType} is to always return true irrespective of what application event was fired.
027 * </p>
028 * 
029 * <p>
030 * To be more discriminatory, provide values for {@code supportedSourceTypes} and {@code supportedEventTypes}.
031 * </p>
032 * 
033 * <p>
034 * To limit execution to a specific event type, eg {@code ContextRefreshedEvent}:
035 * </p>
036 * 
037 * <pre>
038 * ExecutableApplicationListener.builder(executable).supportedEventType(ContextRefreshedEvent.class).build()
039 * </pre>
040 */
041public final class GenericExecutableApplicationListener implements SmartApplicationListener {
042
043        private static final Logger logger = LoggerUtils.make();
044
045        private final Executable executable;
046        private final int order;
047        private final List<Class<?>> supportedSourceTypes;
048        private final List<Class<? extends ApplicationEvent>> supportedEventTypes;
049
050        @Override
051        public void onApplicationEvent(ApplicationEvent event) {
052                logger.info("Received event: [{}]", event.getClass().getCanonicalName());
053                executable.execute();
054        }
055
056        @Override
057        public int getOrder() {
058                return order;
059        }
060
061        @Override
062        public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
063                return supportedEventTypes.isEmpty() || supportedEventTypes.contains(eventType);
064        }
065
066        @Override
067        public boolean supportsSourceType(Class<?> sourceType) {
068                return supportedSourceTypes.isEmpty() || supportedSourceTypes.contains(sourceType);
069        }
070
071        private GenericExecutableApplicationListener(Builder builder) {
072                this.executable = builder.executable;
073                this.order = builder.order;
074                this.supportedSourceTypes = builder.supportedSourceTypes;
075                this.supportedEventTypes = builder.supportedEventTypes;
076        }
077
078        public static Builder builder(Executable executable) {
079                return new Builder(executable);
080        }
081
082        public static class Builder {
083
084                // Required
085                private final Executable executable;
086
087                // Optional
088                private int order = 0; // Lower values mean higher priority, higher values mean lower priority
089                private List<Class<?>> supportedSourceTypes = ImmutableList.of();
090                private List<Class<? extends ApplicationEvent>> supportedEventTypes = ImmutableList.of();
091
092                public Builder(Executable executable) {
093                        this.executable = executable;
094                }
095
096                public GenericExecutableApplicationListener build() {
097                        this.supportedEventTypes = ImmutableList.copyOf(supportedEventTypes);
098                        this.supportedSourceTypes = ImmutableList.copyOf(supportedSourceTypes);
099                        GenericExecutableApplicationListener instance = new GenericExecutableApplicationListener(this);
100                        validate(instance);
101                        return instance;
102                }
103
104                private void validate(GenericExecutableApplicationListener instance) {
105                        checkNotNull(instance.getExecutable(), "executable cannot be null");
106                        checkNotNull(instance.getSupportedEventTypes(), "supportedEventTypes cannot be null");
107                        checkNotNull(instance.getSupportedSourceTypes(), "supportedSourceTypes cannot be null");
108                        checkArgument(ImmutableList.class.isAssignableFrom(instance.getSupportedEventTypes().getClass()), "supportedEventTypes must be immutable");
109                        checkArgument(ImmutableList.class.isAssignableFrom(instance.getSupportedSourceTypes().getClass()), "supportedSourceTypes must be immutable");
110                }
111
112                public Builder order(int order) {
113                        this.order = order;
114                        return this;
115                }
116
117                public Builder supportedSourceTypes(List<Class<?>> supportedSourceTypes) {
118                        this.supportedSourceTypes = supportedSourceTypes;
119                        return this;
120                }
121
122                public Builder supportedSourceType(Class<?> supportedSourceType) {
123                        return supportedSourceTypes(ImmutableList.<Class<?>> of(supportedSourceType));
124                }
125
126                public Builder supportedEventTypes(List<Class<? extends ApplicationEvent>> supportedEventTypes) {
127                        this.supportedEventTypes = supportedEventTypes;
128                        return this;
129                }
130
131                public Builder supportedEventType(Class<? extends ApplicationEvent> supportedEventType) {
132                        return supportedEventTypes(ImmutableList.<Class<? extends ApplicationEvent>> of(supportedEventType));
133                }
134
135                public int getOrder() {
136                        return order;
137                }
138
139                public void setOrder(int order) {
140                        this.order = order;
141                }
142
143                public List<Class<?>> getSupportedSourceTypes() {
144                        return supportedSourceTypes;
145                }
146
147                public void setSupportedSourceTypes(List<Class<?>> supportedSourceTypes) {
148                        this.supportedSourceTypes = supportedSourceTypes;
149                }
150
151                public List<Class<? extends ApplicationEvent>> getSupportedEventTypes() {
152                        return supportedEventTypes;
153                }
154
155                public void setSupportedEventTypes(List<Class<? extends ApplicationEvent>> supportedEventTypes) {
156                        this.supportedEventTypes = supportedEventTypes;
157                }
158
159                public Executable getExecutable() {
160                        return executable;
161                }
162        }
163
164        public Executable getExecutable() {
165                return executable;
166        }
167
168        public List<Class<?>> getSupportedSourceTypes() {
169                return supportedSourceTypes;
170        }
171
172        public List<Class<? extends ApplicationEvent>> getSupportedEventTypes() {
173                return supportedEventTypes;
174        }
175
176}