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