text: /*
   * Copyright 2002-2017 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.springframework.context.event;
  
  import java.lang.reflect.Constructor;
  
  import org.aopalliance.intercept.MethodInterceptor;
  import org.aopalliance.intercept.MethodInvocation;
  
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.context.ApplicationEvent;
  import org.springframework.context.ApplicationEventPublisher;
  import org.springframework.context.ApplicationEventPublisherAware;
  import org.springframework.lang.Nullable;
  import org.springframework.util.Assert;
  
  /**
   * {@link MethodInterceptor Interceptor} that publishes an
   * {@code ApplicationEvent} to all {@code ApplicationListeners}
   * registered with an {@code ApplicationEventPublisher} after each
   * <i>successful</i> method invocation.
   *
   * <p>Note that this interceptor is only capable of publishing <i>stateless</i>
   * events configured via the
   * {@link #setApplicationEventClass "applicationEventClass"} property.
   *
   * @author Dmitriy Kopylenko
   * @author Juergen Hoeller
   * @author Rick Evans
   * @see #setApplicationEventClass
   * @see org.springframework.context.ApplicationEvent
   * @see org.springframework.context.ApplicationListener
   * @see org.springframework.context.ApplicationEventPublisher
   * @see org.springframework.context.ApplicationContext
   */
  public class EventPublicationInterceptor
  		implements MethodInterceptor, ApplicationEventPublisherAware, InitializingBean {
  
  	@Nullable
  	private Constructor<?> applicationEventClassConstructor;
  
  	@Nullable
  	private ApplicationEventPublisher applicationEventPublisher;
  
  
  	/**
  	 * Set the application event class to publish.
  	 * <p>The event class <b>must</b> have a constructor with a single
  	 * {@code Object} argument for the event source. The interceptor
  	 * will pass in the invoked object.
  	 * @throws IllegalArgumentException if the supplied {@code Class} is
  	 * {@code null} or if it is not an {@code ApplicationEvent} subclass or
  	 * if it does not expose a constructor that takes a single {@code Object} argument
  	 */
  	public void setApplicationEventClass(Class<?> applicationEventClass) {
  		if (ApplicationEvent.class == applicationEventClass ||
  				!ApplicationEvent.class.isAssignableFrom(applicationEventClass)) {
  			throw new IllegalArgumentException("'applicationEventClass' needs to extend ApplicationEvent");
  		}
  		try {
  			this.applicationEventClassConstructor = applicationEventClass.getConstructor(Object.class);
  		}
  		catch (NoSuchMethodException ex) {
  			throw new IllegalArgumentException("ApplicationEvent class [" +
  					applicationEventClass.getName() + "] does not have the required Object constructor: " + ex);
  		}
  	}
  
  	@Override
  	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  		this.applicationEventPublisher = applicationEventPublisher;
  	}
  
  	@Override
  	public void afterPropertiesSet() throws Exception {
  		if (this.applicationEventClassConstructor == null) {
  			throw new IllegalArgumentException("Property 'applicationEventClass' is required");
  		}
  	}
  
  
  	@Override
  	public Object invoke(MethodInvocation invocation) throws Throwable {
  		Object retVal = invocation.proceed();
  
  		Assert.state(this.applicationEventClassConstructor != null, "No ApplicationEvent class set");
  		ApplicationEvent event = (ApplicationEvent)
  				this.applicationEventClassConstructor.newInstance(invocation.getThis());
  
  		Assert.state(this.applicationEventPublisher != null, "No ApplicationEventPublisher available");
  		this.applicationEventPublisher.publishEvent(event);
  
  		return retVal;
  	}
  
  }
  