001/*
002 * Copyright 2012-2018 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.event;
018
019import org.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021
022import org.springframework.boot.SpringApplication;
023import org.springframework.boot.SpringApplicationRunListener;
024import org.springframework.context.ApplicationContextAware;
025import org.springframework.context.ApplicationListener;
026import org.springframework.context.ConfigurableApplicationContext;
027import org.springframework.context.event.ApplicationEventMulticaster;
028import org.springframework.context.event.SimpleApplicationEventMulticaster;
029import org.springframework.context.support.AbstractApplicationContext;
030import org.springframework.core.Ordered;
031import org.springframework.core.env.ConfigurableEnvironment;
032import org.springframework.util.ErrorHandler;
033
034/**
035 * {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.
036 * <p>
037 * Uses an internal {@link ApplicationEventMulticaster} for the events that are fired
038 * before the context is actually refreshed.
039 *
040 * @author Phillip Webb
041 * @author Stephane Nicoll
042 * @author Andy Wilkinson
043 * @author Artsiom Yudovin
044 */
045public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
046
047        private final SpringApplication application;
048
049        private final String[] args;
050
051        private final SimpleApplicationEventMulticaster initialMulticaster;
052
053        public EventPublishingRunListener(SpringApplication application, String[] args) {
054                this.application = application;
055                this.args = args;
056                this.initialMulticaster = new SimpleApplicationEventMulticaster();
057                for (ApplicationListener<?> listener : application.getListeners()) {
058                        this.initialMulticaster.addApplicationListener(listener);
059                }
060        }
061
062        @Override
063        public int getOrder() {
064                return 0;
065        }
066
067        @Override
068        public void starting() {
069                this.initialMulticaster.multicastEvent(
070                                new ApplicationStartingEvent(this.application, this.args));
071        }
072
073        @Override
074        public void environmentPrepared(ConfigurableEnvironment environment) {
075                this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
076                                this.application, this.args, environment));
077        }
078
079        @Override
080        public void contextPrepared(ConfigurableApplicationContext context) {
081                this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
082                                this.application, this.args, context));
083        }
084
085        @Override
086        public void contextLoaded(ConfigurableApplicationContext context) {
087                for (ApplicationListener<?> listener : this.application.getListeners()) {
088                        if (listener instanceof ApplicationContextAware) {
089                                ((ApplicationContextAware) listener).setApplicationContext(context);
090                        }
091                        context.addApplicationListener(listener);
092                }
093                this.initialMulticaster.multicastEvent(
094                                new ApplicationPreparedEvent(this.application, this.args, context));
095        }
096
097        @Override
098        public void started(ConfigurableApplicationContext context) {
099                context.publishEvent(
100                                new ApplicationStartedEvent(this.application, this.args, context));
101        }
102
103        @Override
104        public void running(ConfigurableApplicationContext context) {
105                context.publishEvent(
106                                new ApplicationReadyEvent(this.application, this.args, context));
107        }
108
109        @Override
110        public void failed(ConfigurableApplicationContext context, Throwable exception) {
111                ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
112                                this.args, context, exception);
113                if (context != null && context.isActive()) {
114                        // Listeners have been registered to the application context so we should
115                        // use it at this point if we can
116                        context.publishEvent(event);
117                }
118                else {
119                        // An inactive context may not have a multicaster so we use our multicaster to
120                        // call all of the context's listeners instead
121                        if (context instanceof AbstractApplicationContext) {
122                                for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
123                                                .getApplicationListeners()) {
124                                        this.initialMulticaster.addApplicationListener(listener);
125                                }
126                        }
127                        this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
128                        this.initialMulticaster.multicastEvent(event);
129                }
130        }
131
132        private static class LoggingErrorHandler implements ErrorHandler {
133
134                private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
135
136                @Override
137                public void handleError(Throwable throwable) {
138                        logger.warn("Error calling ApplicationEventListener", throwable);
139                }
140
141        }
142
143}