001/*
002 * Copyright 2012-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 *      http://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.boot.context.config;
018
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.List;
022
023import org.springframework.beans.BeanUtils;
024import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
025import org.springframework.context.ApplicationContextException;
026import org.springframework.context.ApplicationEvent;
027import org.springframework.context.ApplicationListener;
028import org.springframework.context.event.SimpleApplicationEventMulticaster;
029import org.springframework.core.Ordered;
030import org.springframework.core.annotation.AnnotationAwareOrderComparator;
031import org.springframework.core.env.ConfigurableEnvironment;
032import org.springframework.util.Assert;
033import org.springframework.util.ClassUtils;
034import org.springframework.util.StringUtils;
035
036/**
037 * {@link ApplicationListener} that delegates to other listeners that are specified under
038 * a {@literal context.listener.classes} environment property.
039 *
040 * @author Dave Syer
041 * @author Phillip Webb
042 */
043public class DelegatingApplicationListener
044                implements ApplicationListener<ApplicationEvent>, Ordered {
045
046        // NOTE: Similar to org.springframework.web.context.ContextLoader
047
048        private static final String PROPERTY_NAME = "context.listener.classes";
049
050        private int order = 0;
051
052        private SimpleApplicationEventMulticaster multicaster;
053
054        @Override
055        public void onApplicationEvent(ApplicationEvent event) {
056                if (event instanceof ApplicationEnvironmentPreparedEvent) {
057                        List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
058                                        ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
059                        if (delegates.isEmpty()) {
060                                return;
061                        }
062                        this.multicaster = new SimpleApplicationEventMulticaster();
063                        for (ApplicationListener<ApplicationEvent> listener : delegates) {
064                                this.multicaster.addApplicationListener(listener);
065                        }
066                }
067                if (this.multicaster != null) {
068                        this.multicaster.multicastEvent(event);
069                }
070        }
071
072        @SuppressWarnings("unchecked")
073        private List<ApplicationListener<ApplicationEvent>> getListeners(
074                        ConfigurableEnvironment environment) {
075                if (environment == null) {
076                        return Collections.emptyList();
077                }
078                String classNames = environment.getProperty(PROPERTY_NAME);
079                List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<>();
080                if (StringUtils.hasLength(classNames)) {
081                        for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
082                                try {
083                                        Class<?> clazz = ClassUtils.forName(className,
084                                                        ClassUtils.getDefaultClassLoader());
085                                        Assert.isAssignable(ApplicationListener.class, clazz, "class ["
086                                                        + className + "] must implement ApplicationListener");
087                                        listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils
088                                                        .instantiateClass(clazz));
089                                }
090                                catch (Exception ex) {
091                                        throw new ApplicationContextException(
092                                                        "Failed to load context listener class [" + className + "]",
093                                                        ex);
094                                }
095                        }
096                }
097                AnnotationAwareOrderComparator.sort(listeners);
098                return listeners;
099        }
100
101        public void setOrder(int order) {
102                this.order = order;
103        }
104
105        @Override
106        public int getOrder() {
107                return this.order;
108        }
109
110}