001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.spring.event;
017
018import static com.google.common.base.Preconditions.checkArgument;
019import static com.google.common.base.Preconditions.checkNotNull;
020
021import org.kuali.common.util.execute.Executable;
022import org.kuali.common.util.log.LoggerUtils;
023import org.slf4j.Logger;
024import org.springframework.context.ApplicationEvent;
025import org.springframework.context.event.SmartApplicationListener;
026
027/**
028 * <p>
029 * Associate an executable with a Spring framework application event.
030 * </p>
031 * 
032 * <p>
033 * If the application event gets fired {@code onApplicationEvent} invokes the executable.
034 * </p>
035 */
036public final class ExecutableApplicationEventListener<T extends ApplicationEvent> implements SmartApplicationListener {
037
038        private static final Logger logger = LoggerUtils.make();
039
040        private final Executable executable;
041        private final int order;
042        private final Class<T> supportedEventType;
043
044        @Override
045        public void onApplicationEvent(ApplicationEvent event) {
046                checkEvent(event);
047                logger.info("Received event: [{}]", event.getClass().getCanonicalName());
048                executable.execute();
049        }
050
051        @Override
052        public int getOrder() {
053                return order;
054        }
055
056        @Override
057        public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
058                return supportedEventType == eventType;
059        }
060
061        @Override
062        public boolean supportsSourceType(Class<?> sourceType) {
063                return true;
064        }
065
066        private void checkEvent(ApplicationEvent event) {
067                boolean expression = supportedEventType == event.getClass();
068                String errorMessage = "[%s] is the only supported event type.  Events of type [%s] should not be getting passed to this listener";
069                Object[] args = { supportedEventType.getCanonicalName(), event.getClass().getCanonicalName() };
070                checkArgument(expression, errorMessage, args);
071        }
072
073        private ExecutableApplicationEventListener(Builder<T> builder) {
074                this.executable = builder.executable;
075                this.order = builder.order;
076                this.supportedEventType = builder.supportedEventType;
077        }
078
079        public static <T extends ApplicationEvent> Builder<T> builder(Executable executable, Class<T> supportedEventType) {
080                return new Builder<T>(executable, supportedEventType);
081        }
082
083        public static class Builder<T extends ApplicationEvent> {
084
085                // Required
086                private final Executable executable;
087                private final Class<T> supportedEventType;
088
089                // Optional
090                private int order = 0; // Lower values mean higher priority, higher values mean lower priority
091
092                public Builder(Executable executable, Class<T> supportedEventType) {
093                        this.executable = executable;
094                        this.supportedEventType = supportedEventType;
095                }
096
097                public ExecutableApplicationEventListener<T> build() {
098                        ExecutableApplicationEventListener<T> instance = new ExecutableApplicationEventListener<T>(this);
099                        validate(instance);
100                        return instance;
101                }
102
103                private void validate(ExecutableApplicationEventListener<T> instance) {
104                        checkNotNull(instance.getExecutable(), "'executable' cannot be null");
105                        checkNotNull(instance.getSupportedEventType(), "'supportedEventType' cannot be null");
106                }
107
108                public Builder<T> order(int order) {
109                        this.order = order;
110                        return this;
111                }
112
113                public int getOrder() {
114                        return order;
115                }
116
117                public void setOrder(int order) {
118                        this.order = order;
119                }
120
121                public Executable getExecutable() {
122                        return executable;
123                }
124        }
125
126        public Executable getExecutable() {
127                return executable;
128        }
129
130        public Class<T> getSupportedEventType() {
131                return supportedEventType;
132        }
133
134}