001/*
002 * Copyright 2002-2012 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.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021
022import org.springframework.beans.BeansException;
023import org.springframework.context.ApplicationContext;
024import org.springframework.context.ApplicationContextAware;
025import org.springframework.context.ApplicationContextException;
026
027/**
028 * Convenient superclass for application objects that want to be aware of
029 * the application context, e.g. for custom lookup of collaborating beans
030 * or for context-specific resource access. It saves the application
031 * context reference and provides an initialization callback method.
032 * Furthermore, it offers numerous convenience methods for message lookup.
033 *
034 * <p>There is no requirement to subclass this class: It just makes things
035 * a little easier if you need access to the context, e.g. for access to
036 * file resources or to the message source. Note that many application
037 * objects do not need to be aware of the application context at all,
038 * as they can receive collaborating beans via bean references.
039 *
040 * <p>Many framework classes are derived from this class, particularly
041 * within the web support.
042 *
043 * @author Rod Johnson
044 * @author Juergen Hoeller
045 * @see org.springframework.web.context.support.WebApplicationObjectSupport
046 */
047public abstract class ApplicationObjectSupport implements ApplicationContextAware {
048
049        /** Logger that is available to subclasses */
050        protected final Log logger = LogFactory.getLog(getClass());
051
052        /** ApplicationContext this object runs in */
053        private ApplicationContext applicationContext;
054
055        /** MessageSourceAccessor for easy message access */
056        private MessageSourceAccessor messageSourceAccessor;
057
058
059        @Override
060        public final void setApplicationContext(ApplicationContext context) throws BeansException {
061                if (context == null && !isContextRequired()) {
062                        // Reset internal context state.
063                        this.applicationContext = null;
064                        this.messageSourceAccessor = null;
065                }
066                else if (this.applicationContext == null) {
067                        // Initialize with passed-in context.
068                        if (!requiredContextClass().isInstance(context)) {
069                                throw new ApplicationContextException(
070                                                "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
071                        }
072                        this.applicationContext = context;
073                        this.messageSourceAccessor = new MessageSourceAccessor(context);
074                        initApplicationContext(context);
075                }
076                else {
077                        // Ignore reinitialization if same context passed in.
078                        if (this.applicationContext != context) {
079                                throw new ApplicationContextException(
080                                                "Cannot reinitialize with different application context: current one is [" +
081                                                this.applicationContext + "], passed-in one is [" + context + "]");
082                        }
083                }
084        }
085
086        /**
087         * Determine whether this application object needs to run in an ApplicationContext.
088         * <p>Default is "false". Can be overridden to enforce running in a context
089         * (i.e. to throw IllegalStateException on accessors if outside a context).
090         * @see #getApplicationContext
091         * @see #getMessageSourceAccessor
092         */
093        protected boolean isContextRequired() {
094                return false;
095        }
096
097        /**
098         * Determine the context class that any context passed to
099         * {@code setApplicationContext} must be an instance of.
100         * Can be overridden in subclasses.
101         * @see #setApplicationContext
102         */
103        protected Class<?> requiredContextClass() {
104                return ApplicationContext.class;
105        }
106
107        /**
108         * Subclasses can override this for custom initialization behavior.
109         * Gets called by {@code setApplicationContext} after setting the context instance.
110         * <p>Note: Does </i>not</i> get called on reinitialization of the context
111         * but rather just on first initialization of this object's context reference.
112         * <p>The default implementation calls the overloaded {@link #initApplicationContext()}
113         * method without ApplicationContext reference.
114         * @param context the containing ApplicationContext
115         * @throws ApplicationContextException in case of initialization errors
116         * @throws BeansException if thrown by ApplicationContext methods
117         * @see #setApplicationContext
118         */
119        protected void initApplicationContext(ApplicationContext context) throws BeansException {
120                initApplicationContext();
121        }
122
123        /**
124         * Subclasses can override this for custom initialization behavior.
125         * <p>The default implementation is empty. Called by
126         * {@link #initApplicationContext(org.springframework.context.ApplicationContext)}.
127         * @throws ApplicationContextException in case of initialization errors
128         * @throws BeansException if thrown by ApplicationContext methods
129         * @see #setApplicationContext
130         */
131        protected void initApplicationContext() throws BeansException {
132        }
133
134
135        /**
136         * Return the ApplicationContext that this object is associated with.
137         * @throws IllegalStateException if not running in an ApplicationContext
138         */
139        public final ApplicationContext getApplicationContext() throws IllegalStateException {
140                if (this.applicationContext == null && isContextRequired()) {
141                        throw new IllegalStateException(
142                                        "ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
143                }
144                return this.applicationContext;
145        }
146
147        /**
148         * Return a MessageSourceAccessor for the application context
149         * used by this object, for easy message access.
150         * @throws IllegalStateException if not running in an ApplicationContext
151         */
152        protected final MessageSourceAccessor getMessageSourceAccessor() throws IllegalStateException {
153                if (this.messageSourceAccessor == null && isContextRequired()) {
154                        throw new IllegalStateException(
155                                        "ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
156                }
157                return this.messageSourceAccessor;
158        }
159
160}