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