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.support;
018
019import org.springframework.beans.factory.BeanNameAware;
020import org.springframework.beans.factory.InitializingBean;
021import org.springframework.context.ApplicationContext;
022import org.springframework.lang.Nullable;
023import org.springframework.util.Assert;
024import org.springframework.util.StringUtils;
025
026/**
027 * {@link AbstractRefreshableApplicationContext} subclass that adds common handling
028 * of specified config locations. Serves as base class for XML-based application
029 * context implementations such as {@link ClassPathXmlApplicationContext} and
030 * {@link FileSystemXmlApplicationContext}, as well as
031 * {@link org.springframework.web.context.support.XmlWebApplicationContext}.
032 *
033 * @author Juergen Hoeller
034 * @since 2.5.2
035 * @see #setConfigLocation
036 * @see #setConfigLocations
037 * @see #getDefaultConfigLocations
038 */
039public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
040                implements BeanNameAware, InitializingBean {
041
042        @Nullable
043        private String[] configLocations;
044
045        private boolean setIdCalled = false;
046
047
048        /**
049         * Create a new AbstractRefreshableConfigApplicationContext with no parent.
050         */
051        public AbstractRefreshableConfigApplicationContext() {
052        }
053
054        /**
055         * Create a new AbstractRefreshableConfigApplicationContext with the given parent context.
056         * @param parent the parent context
057         */
058        public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {
059                super(parent);
060        }
061
062
063        /**
064         * Set the config locations for this application context in init-param style,
065         * i.e. with distinct locations separated by commas, semicolons or whitespace.
066         * <p>If not set, the implementation may use a default as appropriate.
067         */
068        public void setConfigLocation(String location) {
069                setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
070        }
071
072        /**
073         * Set the config locations for this application context.
074         * <p>If not set, the implementation may use a default as appropriate.
075         */
076        public void setConfigLocations(@Nullable String... locations) {
077                if (locations != null) {
078                        Assert.noNullElements(locations, "Config locations must not be null");
079                        this.configLocations = new String[locations.length];
080                        for (int i = 0; i < locations.length; i++) {
081                                this.configLocations[i] = resolvePath(locations[i]).trim();
082                        }
083                }
084                else {
085                        this.configLocations = null;
086                }
087        }
088
089        /**
090         * Return an array of resource locations, referring to the XML bean definition
091         * files that this context should be built with. Can also include location
092         * patterns, which will get resolved via a ResourcePatternResolver.
093         * <p>The default implementation returns {@code null}. Subclasses can override
094         * this to provide a set of resource locations to load bean definitions from.
095         * @return an array of resource locations, or {@code null} if none
096         * @see #getResources
097         * @see #getResourcePatternResolver
098         */
099        @Nullable
100        protected String[] getConfigLocations() {
101                return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
102        }
103
104        /**
105         * Return the default config locations to use, for the case where no
106         * explicit config locations have been specified.
107         * <p>The default implementation returns {@code null},
108         * requiring explicit config locations.
109         * @return an array of default config locations, if any
110         * @see #setConfigLocations
111         */
112        @Nullable
113        protected String[] getDefaultConfigLocations() {
114                return null;
115        }
116
117        /**
118         * Resolve the given path, replacing placeholders with corresponding
119         * environment property values if necessary. Applied to config locations.
120         * @param path the original file path
121         * @return the resolved file path
122         * @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
123         */
124        protected String resolvePath(String path) {
125                return getEnvironment().resolveRequiredPlaceholders(path);
126        }
127
128
129        @Override
130        public void setId(String id) {
131                super.setId(id);
132                this.setIdCalled = true;
133        }
134
135        /**
136         * Sets the id of this context to the bean name by default,
137         * for cases where the context instance is itself defined as a bean.
138         */
139        @Override
140        public void setBeanName(String name) {
141                if (!this.setIdCalled) {
142                        super.setId(name);
143                        setDisplayName("ApplicationContext '" + name + "'");
144                }
145        }
146
147        /**
148         * Triggers {@link #refresh()} if not refreshed in the concrete context's
149         * constructor already.
150         */
151        @Override
152        public void afterPropertiesSet() {
153                if (!isActive()) {
154                        refresh();
155                }
156        }
157
158}