001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache 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 *      https://www.apache.org/licenses/LICENSE-2.0
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 */
016
017package org.springframework.context.event;
018
019import java.lang.reflect.Constructor;
020
021import org.aopalliance.intercept.MethodInterceptor;
022import org.aopalliance.intercept.MethodInvocation;
023
024import org.springframework.beans.factory.InitializingBean;
025import org.springframework.context.ApplicationEvent;
026import org.springframework.context.ApplicationEventPublisher;
027import org.springframework.context.ApplicationEventPublisherAware;
028
029/**
030 * {@link MethodInterceptor Interceptor} that publishes an
031 * {@code ApplicationEvent} to all {@code ApplicationListeners}
032 * registered with an {@code ApplicationEventPublisher} after each
033 * <i>successful</i> method invocation.
034 *
035 * <p>Note that this interceptor is only capable of publishing <i>stateless</i>
036 * events configured via the
037 * {@link #setApplicationEventClass "applicationEventClass"} property.
038 *
039 * @author Dmitriy Kopylenko
040 * @author Juergen Hoeller
041 * @author Rick Evans
042 * @see #setApplicationEventClass
043 * @see org.springframework.context.ApplicationEvent
044 * @see org.springframework.context.ApplicationListener
045 * @see org.springframework.context.ApplicationEventPublisher
046 * @see org.springframework.context.ApplicationContext
047 */
048public class EventPublicationInterceptor
049                implements MethodInterceptor, ApplicationEventPublisherAware, InitializingBean {
050
051        private Constructor<?> applicationEventClassConstructor;
052
053        private ApplicationEventPublisher applicationEventPublisher;
054
055
056        /**
057         * Set the application event class to publish.
058         * <p>The event class <b>must</b> have a constructor with a single
059         * {@code Object} argument for the event source. The interceptor
060         * will pass in the invoked object.
061         * @throws IllegalArgumentException if the supplied {@code Class} is
062         * {@code null} or if it is not an {@code ApplicationEvent} subclass or
063         * if it does not expose a constructor that takes a single {@code Object} argument
064         */
065        public void setApplicationEventClass(Class<?> applicationEventClass) {
066                if (ApplicationEvent.class == applicationEventClass ||
067                                !ApplicationEvent.class.isAssignableFrom(applicationEventClass)) {
068                        throw new IllegalArgumentException("'applicationEventClass' needs to extend ApplicationEvent");
069                }
070                try {
071                        this.applicationEventClassConstructor = applicationEventClass.getConstructor(Object.class);
072                }
073                catch (NoSuchMethodException ex) {
074                        throw new IllegalArgumentException("ApplicationEvent class [" +
075                                        applicationEventClass.getName() + "] does not have the required Object constructor: " + ex);
076                }
077        }
078
079        @Override
080        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
081                this.applicationEventPublisher = applicationEventPublisher;
082        }
083
084        @Override
085        public void afterPropertiesSet() throws Exception {
086                if (this.applicationEventClassConstructor == null) {
087                        throw new IllegalArgumentException("Property 'applicationEventClass' is required");
088                }
089        }
090
091
092        @Override
093        public Object invoke(MethodInvocation invocation) throws Throwable {
094                Object retVal = invocation.proceed();
095
096                ApplicationEvent event = (ApplicationEvent)
097                                this.applicationEventClassConstructor.newInstance(invocation.getThis());
098                this.applicationEventPublisher.publishEvent(event);
099
100                return retVal;
101        }
102
103}