View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2008 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  
18  package ch.elca.el4j.core.context;
19  
20  import java.io.BufferedReader;
21  import java.io.IOException;
22  import java.io.InputStreamReader;
23  import java.util.Collection;
24  
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
28  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
29  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
30  import org.springframework.context.ApplicationContext;
31  import org.springframework.context.support.AbstractXmlApplicationContext;
32  import org.springframework.core.Ordered;
33  import org.springframework.core.io.Resource;
34  import org.springframework.core.io.support.ResourcePatternResolver;
35  import org.springframework.util.Assert;
36  import org.springframework.util.StringUtils;
37  
38  import ch.elca.el4j.core.io.support.ListResourcePatternResolverDecorator;
39  import ch.elca.el4j.core.io.support.ManifestOrderedConfigLocationProvider;
40  import ch.elca.el4j.util.codingsupport.annotations.FindBugsSuppressWarnings;
41  
42  /**
43   * <p>
44   * Class that loads the ApplicationContext given an array of config files and an
45   * array of exclusion config files. The files can be declared via classpath or
46   * filepath.
47   * </p>
48   * <p>
49   * Classpath files can be declared by the following two patterns:
50   * "ch/elca/.../x.xml" or by "classpath:ch/elca/.../x.xml".
51   * </p>
52   * <p>
53   * Filepath files have to be declared in the following way:
54   * "file:C:/folder/.../x.xml".
55   * </p>
56   * <p>
57   * Classpath and filepath files can be declared via ant-style pattern. For
58   * instance "classpath:ch/elca/el4j/*.xml" will be resolved into all xml files
59   * in the specified classpath. If there is more than one file having the same
60   * classpath in two different jars, then you have to change classpath:folder/...
61   * into classpath*:folder/... Otherwise, only the file(s) from the first jar is
62   * loaded.
63   * </p>
64   *
65   * Additional features:
66   * <ul>
67   * <li>
68   *    PropertyPlaceholder/ PropertyOverride configurers (actually all
69   *    {@link BeanFactoryPostProcessor}) can override properties of
70   *    {@link BeanFactoryPostProcessor}s that come later in the order
71   *    (see {@link Ordered} for more details).
72   * </li>
73   * <li>
74   *    Exclusion lists (config files to explicitly exclude from the
75   *    configuration)
76   * </li>
77   * <li>
78   *    One can define (constructor argument) whether we allow bean-definitions
79   *    to silently overwrite earlier configuration settings.
80   * </li>
81   * <li>
82   *    The order of underlying resources is better conserved than with pure
83   *    spring
84   * </li>
85   * <li>
86   *    More configuration info is available in JMX (only when the jmx module is
87   *    active)
88   * </li>
89   * </ul>
90   *
91   * @see ModuleWebApplicationContext
92   *
93   * @svnLink $Revision: 4204 $;$Date: 2010-11-02 11:44:37 +0100 (Di, 02. Nov 2010) $;$Author: swisswheel $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/core/src/main/java/ch/elca/el4j/core/context/ModuleApplicationContext.java $
94   *
95   * @author Raphael Boog (RBO)
96   * @author Andreas Bur (ABU)
97   * @author Martin Zeltner (MZE)
98   */
99  public class ModuleApplicationContext extends AbstractXmlApplicationContext
100 	implements RefreshableModuleApplicationContext {
101 	/**
102 	 * The common debugging logger for EL4J.
103 	 */
104 	public static final String EL4J_DEBUGGING_LOGGER = "el4j.debugging";
105 	
106 	/**
107 	 * This logger is used to print out some global debugging info.
108 	 * Consult it for info what is going on.
109 	 */
110 	protected static final Logger s_el4jLogger
111 		= LoggerFactory.getLogger(EL4J_DEBUGGING_LOGGER);
112 	
113 	/**
114 	 * Inclusive config locations.
115 	 */
116 	private final String[] m_inclusiveConfigLocations;
117 
118 	/**
119 	 * Exclusive config locations.
120 	 */
121 	private final String[] m_exclusiveConfigLocations;
122 
123 	/**
124 	 * Config locations.
125 	 */
126 	private final String[] m_configLocations;
127 
128 	/**
129 	 * Indicates if bean definition overriding is enabled.
130 	 */
131 	private final boolean m_allowBeanDefinitionOverriding;
132 	
133 	/**
134 	 * Indicates if unordered/unknown resource should be used.
135 	 */
136 	private final boolean m_mergeWithOuterResources;
137 	
138 	/**
139 	 * Indicates if the most specific resource should be the last resource
140 	 * in the fetched resource array. If its value is set to <code>true</code>
141 	 * and only one resource is requested the least specific resource will be
142 	 * returned. Default is set to <code>false</code>.
143 	 */
144 	private final boolean m_mostSpecificResourceLast;
145 	
146 	/**
147 	 * Indicates if the most specific bean definition counts.
148 	 */
149 	private final boolean m_mostSpecificBeanDefinitionCounts;
150 	
151 	/**
152 	 * The resource pattern resolver.
153 	 */
154 	private ListResourcePatternResolverDecorator m_patternResolver;
155 	
156 	/**
157 	 * Is context refreshed i.e. fully initialized?
158 	 */
159 	private boolean m_refreshed = false;
160 	
161 	/**
162 	 * Synchronization monitor for the "refreshed" flag.
163 	 */
164 	private final Object m_refreshedMonitor = new Object();
165 
166 	/**
167 	 * Creation listener for the application context.
168 	 */
169 	private final ModuleApplicationContextCreationListener m_creationListener;
170 	
171 	/**
172 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
173 	 *      String[], boolean)
174 	 */
175 	public ModuleApplicationContext(String inclusiveConfigLocation,
176 			boolean allowBeanDefinitionOverriding) {
177 		this(new String[] {inclusiveConfigLocation},
178 				allowBeanDefinitionOverriding);
179 	}
180 
181 	/**
182 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
183 	 *      String[], String[], boolean, ApplicationContext)
184 	 */
185 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
186 			boolean allowBeanDefinitionOverriding) {
187 		this(inclusiveConfigLocations, new String[] {},
188 				allowBeanDefinitionOverriding, null);
189 	}
190 
191 	/**
192 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
193 	 *      String[], String[], boolean, ApplicationContext)
194 	 */
195 	public ModuleApplicationContext(String inclusiveConfigLocation,
196 			String exclusiveConfigLocation,
197 			boolean allowBeanDefinitionOverriding) {
198 		this(new String[] {inclusiveConfigLocation},
199 				new String[] {exclusiveConfigLocation},
200 				allowBeanDefinitionOverriding, null);
201 	}
202 
203 	/**
204 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
205 	 *      String[], String[], boolean, ApplicationContext)
206 	 */
207 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
208 			String exclusiveConfigLocation,
209 			boolean allowBeanDefinitionOverriding) {
210 		this(inclusiveConfigLocations,
211 				new String[] {exclusiveConfigLocation},
212 				allowBeanDefinitionOverriding, null);
213 	}
214 
215 	/**
216 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
217 	 *      String[], String[], boolean, ApplicationContext)
218 	 */
219 	public ModuleApplicationContext(String inclusiveConfigLocation,
220 			String[] exclusiveConfigLocations,
221 			boolean allowBeanDefinitionOverriding) {
222 		this(new String[] {inclusiveConfigLocation},
223 				exclusiveConfigLocations, allowBeanDefinitionOverriding, null);
224 	}
225 
226 	/**
227 	 * <ul>
228 	 * <li>Merge with outer resources is set to <code>true</code>.</li>
229 	 * </ul>
230 	 *
231 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
232 	 *      String[], String[], boolean, ApplicationContext, boolean)
233 	 */
234 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
235 			String[] exclusiveConfigLocations,
236 			boolean allowBeanDefinitionOverriding, ApplicationContext parent) {
237 		this(inclusiveConfigLocations, exclusiveConfigLocations,
238 				allowBeanDefinitionOverriding, parent, true);
239 	}
240 	
241 	/**
242 	 * <ul>
243 	 * <li>Most specific resource last is set to <code>false</code>.</li>
244 	 * <li>Most specific bean definition counts is set to
245 	 * <code>true</code>.</li>
246 	 * </ul>
247 	 *
248 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
249 	 *      String[], String[], boolean, ApplicationContext, boolean, boolean, 
250 	 *      boolean, ModuleApplicationContextCreationListener)
251 	 */
252 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
253 		String[] exclusiveConfigLocations,
254 		boolean allowBeanDefinitionOverriding, ApplicationContext parent,
255 		boolean mergeWithOuterResources) {
256 		this(inclusiveConfigLocations, exclusiveConfigLocations,
257 				allowBeanDefinitionOverriding, parent, mergeWithOuterResources,
258 				false, true, null);
259 	}
260 
261 	/**
262 	 * With this constructor we use no app context creation listener.
263 	 * 
264 	 * @see ch.elca.el4j.core.context.ModuleApplicationContext#ModuleApplicationContext(
265 	 *      String[], String[], boolean, ApplicationContext, boolean, boolean, 
266 	 *      boolean, ModuleApplicationContextCreationListener)
267 	 */
268 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
269 		String[] exclusiveConfigLocations,
270 		boolean allowBeanDefinitionOverriding, ApplicationContext parent,
271 		boolean mergeWithOuterResources,
272 		boolean mostSpecificResourceLast,
273 		boolean mostSpecificBeanDefinitionCounts) {
274 		this(inclusiveConfigLocations, exclusiveConfigLocations,
275 			allowBeanDefinitionOverriding, parent, mergeWithOuterResources,
276 			mostSpecificResourceLast, mostSpecificBeanDefinitionCounts, null);
277 	}
278 	
279 	/**
280 	 * Create a new ModuleApplicationContext with the given parent, loading the
281 	 * definitions from the given XML files in "inclusiveConfigLocations"
282 	 * excluded the XML files defined in "exclusiveConfigLocations". If the
283 	 * parameter "allowBeanDefinitionOverriding" is set to true then the
284 	 * BeanFactory is allowed to override a bean if there is another one with
285 	 * the same name.
286 	 *
287 	 * @param inclusiveConfigLocations
288 	 *            array of file paths
289 	 * @param exclusiveConfigLocations
290 	 *            array of file paths which are excluded
291 	 * @param allowBeanDefinitionOverriding
292 	 *            a boolean which defines if overriding of bean definitions is
293 	 *            allowed
294 	 * @param parent
295 	 *            the parent context
296 	 * @param mergeWithOuterResources
297 	 *            a boolean which defines if the resources retrieved by the
298 	 *            configuration files section of the manifest files should be
299 	 *            merged with resources found by searching in the file system.
300 	 * @param mostSpecificResourceLast
301 	 *            Indicates if the most specific resource should be the last
302 	 *            resource in the fetched resource array. If its value is set to
303 	 *            <code>true</code> and only one resource is requested the
304 	 *            least specific resource will be returned.
305 	 * @param mostSpecificBeanDefinitionCounts
306 	 *            Indicates that the most specific bean definition is used.
307 	 * @param creationListener
308 	 *            Is the listener to hock in while creation of the application context.
309 	 */
310 	@FindBugsSuppressWarnings(value = "UR_UNINIT_READ", 
311 		justification = "Pattern resolver initialized by a super class.")
312 	public ModuleApplicationContext(String[] inclusiveConfigLocations,
313 			String[] exclusiveConfigLocations,
314 			boolean allowBeanDefinitionOverriding, ApplicationContext parent,
315 			boolean mergeWithOuterResources,
316 			boolean mostSpecificResourceLast,
317 			boolean mostSpecificBeanDefinitionCounts,
318 			ModuleApplicationContextCreationListener creationListener) {
319 		super(parent);
320 		m_inclusiveConfigLocations = inclusiveConfigLocations;
321 		m_exclusiveConfigLocations = exclusiveConfigLocations;
322 		m_allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
323 		m_mergeWithOuterResources = mergeWithOuterResources;
324 		m_mostSpecificResourceLast = mostSpecificResourceLast;
325 		m_mostSpecificBeanDefinitionCounts = mostSpecificBeanDefinitionCounts;
326 		m_creationListener = creationListener;
327 		
328 		/**
329 		 * HACK: The pattern resolver is initialized by a super class
330 		 * via method <code>getResourcePatternResolver</code>.
331 		 */
332 		Assert.notNull(m_patternResolver);
333 		Assert.isInstanceOf(ListResourcePatternResolverDecorator.class,
334 			m_patternResolver);
335 		ListResourcePatternResolverDecorator listResourcePatternResolver
336 			= (ListResourcePatternResolverDecorator) m_patternResolver;
337 		listResourcePatternResolver.setMostSpecificResourceLast(
338 			isMostSpecificResourceLast());
339 		listResourcePatternResolver.setMergeWithOuterResources(
340 			isMergeWithOuterResources());
341 
342 		ModuleApplicationContextUtils utils
343 			= new ModuleApplicationContextUtils(this);
344 		utils.setReverseConfigLocationResourceArray(
345 			isMostSpecificResourceLast()
346 				!= isMostSpecificBeanDefinitionCounts());
347 		
348 		m_configLocations = utils.calculateInputFiles(inclusiveConfigLocations,
349 				exclusiveConfigLocations, allowBeanDefinitionOverriding);
350 		
351 		additionalLoggingOutput(allowBeanDefinitionOverriding,
352 			mergeWithOuterResources, mostSpecificResourceLast,
353 			mostSpecificBeanDefinitionCounts);
354 		
355 		refresh();
356 	}
357 
358 	/**
359 	 * Constructor to create a module application context by using the given
360 	 * configurations.
361 	 *
362 	 * @param config Is the used configuration.
363 	 */
364 	public ModuleApplicationContext(
365 		ModuleApplicationContextConfiguration config) {
366 		this(config.getInclusiveConfigLocations(),
367 			config.getExclusiveConfigLocations(),
368 			config.isAllowBeanDefinitionOverriding(),
369 			config.getParent(),
370 			config.isMergeWithOuterResources(),
371 			config.isMostSpecificResourceLast(),
372 			config.isMostSpecificBeanDefinitionCounts(),
373 			config.getModuleApplicationContextCreationListener());
374 	}
375 	
376 	/**
377 	 * {@inheritDoc}
378 	 */
379 	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
380 		if (m_creationListener != null) {
381 			m_creationListener.postProcessBeanFactory(beanFactory);
382 		}
383 	}
384 	
385 	/**
386 	 * Logger some interesting values.
387 	 *
388 	 * Not nice: Code duplication between the 2 ModuleApplicationContext
389 	 *           classes!
390 	 *
391 	 * @param allowBeanDefinitionOverriding
392 	 *            a boolean which defines if overriding of bean definitions is
393 	 *            allowed
394 	 * @param mergeWithOuterResources
395 	 *            a boolean which defines if the resources retrieved by the
396 	 *            configuration files section of the manifest files should be
397 	 *            merged with resources found by searching in the file system.
398 	 * @param mostSpecificResourceLast
399 	 *            Indicates if the most specific resource should be the last
400 	 *            resource in the fetched resource array. If its value is set to
401 	 *            <code>true</code> and only one resource is requested the
402 	 *            least specific resource will be returned.
403 	 * @param mostSpecificBeanDefinitionCounts
404 	 *            Indicates that the most specific bean definition is used.
405 	 */
406 	private void additionalLoggingOutput(boolean allowBeanDefinitionOverriding,
407 		boolean mergeWithOuterResources, boolean mostSpecificResourceLast,
408 		boolean mostSpecificBeanDefinitionCounts) {
409 
410 		s_el4jLogger.info(
411 			"Starting up ModuleApplicationContext. configLocations :"
412 			+ StringUtils.arrayToDelimitedString(m_configLocations, ", "));
413 		if (s_el4jLogger.isDebugEnabled()) {
414 			s_el4jLogger.debug("inclusiveLocation:"
415 				+ StringUtils.arrayToDelimitedString(
416 					m_inclusiveConfigLocations, ", "));
417 			s_el4jLogger.debug("exclusiveLocation:"
418 				+ StringUtils.arrayToDelimitedString(
419 					m_exclusiveConfigLocations, ", "));
420 			s_el4jLogger.debug("allowBeanDefinitionOverriding:"
421 				+ allowBeanDefinitionOverriding);
422 			s_el4jLogger.debug("mergeWithOuterResources:"
423 				+ mergeWithOuterResources);
424 			s_el4jLogger.debug("mostSpecificResourceLast:"
425 				+ mostSpecificResourceLast);
426 			s_el4jLogger.debug("mostSpecificBeanDefinitionCounts:"
427 				+ mostSpecificBeanDefinitionCounts);
428 
429 			// Prevent a NPE here if nothing is resolved.
430 			if (m_configLocations == null) {
431 				return;
432 			}
433 			for (String configLocation : m_configLocations) {
434 				Resource res = getResource(configLocation);
435 				BufferedReader reader = null;
436 				try {
437 					reader = new BufferedReader(new InputStreamReader(res
438 						.getInputStream()));
439 					StringBuffer buf = new StringBuffer();
440 					while (reader.ready()) {
441 						buf.append(reader.readLine());
442 						buf.append("\n");
443 					}
444 					s_el4jLogger.debug("Content of " + configLocation + " : "
445 						+ buf.toString() + "\n---");
446 				} catch (IOException e) {
447 					// deliberately ignore exception
448 					s_el4jLogger.debug(
449 						"Error during printing of config location "
450 							+ configLocation, e);
451 				} finally {
452 					if (reader != null) {
453 						try {
454 							reader.close();
455 						} catch (IOException e) {
456 							s_el4jLogger.debug(
457 								"Error during printing of config location "
458 									+ configLocation, e);
459 						}
460 					}
461 				}
462 			}
463 		}
464 	}
465 	
466 	/**
467 	 * @return Returns the ConfigLocations.
468 	 */
469 	@Override
470 	public String[] getConfigLocations() {
471 		return m_configLocations;
472 	}
473 
474 	/**
475 	 * @return Returns the exclusiveConfigLocations.
476 	 */
477 	public String[] getExclusiveConfigLocations() {
478 		return m_exclusiveConfigLocations;
479 	}
480 
481 	/**
482 	 * @return Returns the inclusiveConfigLocations.
483 	 */
484 	public String[] getInclusiveConfigLocations() {
485 		return m_inclusiveConfigLocations;
486 	}
487 
488 	/**
489 	 * @return Returns the allowBeanDefinitionOverriding.
490 	 */
491 	public boolean isAllowBeanDefinitionOverriding() {
492 		return m_allowBeanDefinitionOverriding;
493 	}
494 
495 	/**
496 	 * @return Returns the mergeWithOuterResources.
497 	 */
498 	public boolean isMergeWithOuterResources() {
499 		return m_mergeWithOuterResources;
500 	}
501 
502 	/**
503 	 * @return Returns the mostSpecificResourceLast.
504 	 */
505 	public boolean isMostSpecificResourceLast() {
506 		return m_mostSpecificResourceLast;
507 	}
508 
509 	/**
510 	 * @return Returns the mostSpecificBeanDefinitionCounts.
511 	 */
512 	public boolean isMostSpecificBeanDefinitionCounts() {
513 		return m_mostSpecificBeanDefinitionCounts;
514 	}
515 	
516 	/**
517 	 * {@inheritDoc}
518 	 */
519 	@Override
520 	public Resource getResource(String location) {
521 		return m_patternResolver.getResource(location);
522 	}
523 
524 	/**
525 	 * {@inheritDoc}
526 	 */
527 	@Override
528 	public Resource[] getResources(String locationPattern) throws IOException {
529 		return m_patternResolver.getResources(locationPattern);
530 	}
531 	
532 	/**
533 	 * Override method createBeanFactory() in class
534 	 * AbstractRefreshableApplicationContext. The property
535 	 * m_allowBeanDefinitionOverriding can be set and is handed over to the
536 	 * DefaultListableBeanFactory which creates the BeanFactory.
537 	 *
538 	 * @return the DefaultListableBeanFactory
539 	 */
540 	@Override
541 	protected DefaultListableBeanFactory createBeanFactory() {
542 		DefaultListableBeanFactory dlbf = new DefaultListableBeanFactory(
543 				getInternalParentBeanFactory());
544 		dlbf.setAllowBeanDefinitionOverriding(
545 			isAllowBeanDefinitionOverriding());
546 		return dlbf;
547 	}
548 
549 	/**
550 	 * {@inheritDoc}
551 	 */
552 	@Override
553 	protected ResourcePatternResolver getResourcePatternResolver() {
554 		ListResourcePatternResolverDecorator patternResolver
555 			= new ListResourcePatternResolverDecorator(
556 				new ManifestOrderedConfigLocationProvider());
557 		patternResolver.setMostSpecificResourceLast(
558 			isMostSpecificResourceLast());
559 		patternResolver.setMergeWithOuterResources(
560 			isMergeWithOuterResources());
561 		m_patternResolver = patternResolver;
562 		return m_patternResolver;
563 	}
564 	
565 	/**
566 	 * Not just method {@link BeanFactoryPostProcessor#postProcessBeanFactory(
567 	 * ConfigurableListableBeanFactory)} is invoked ordered but also the
568 	 * creation of the factory post processor beans!
569 	 *
570 	 * {@inheritDoc}
571 	 */
572 	protected void invokeBeanFactoryPostProcessors(
573 		ConfigurableListableBeanFactory beanFactory) {
574 		ModuleApplicationContextUtils ctxUtil
575 			= new ModuleApplicationContextUtils(this);
576 		ctxUtil.invokeBeanFactoryPostProcessorsStrictlyOrdered(beanFactory);
577 	}
578 	
579 	
580 	/** {@inheritDoc} */
581 	@Override
582 	protected void prepareRefresh() {
583 		synchronized (m_refreshedMonitor) {
584 			m_refreshed = false;
585 		}
586 		
587 		super.prepareRefresh();
588 	}
589 	
590 	/**
591 	 * Notify all {@link ModuleApplicationListener}s that context has been refreshed.
592 	 * 
593 	 * {@inheritDoc}
594 	 */
595 	@SuppressWarnings("unchecked")
596 	@Override
597 	protected void finishRefresh() {
598 		synchronized (m_refreshedMonitor) {
599 			m_refreshed = true;
600 		}
601 		
602 		Collection<ModuleApplicationListener> listeners = getBeansOfType(
603 			ModuleApplicationListener.class, true, false).values();
604 		for (ModuleApplicationListener listener : listeners) {
605 			listener.onContextRefreshed();
606 		}
607 		super.finishRefresh();
608 		
609 		if (m_creationListener != null) {
610 			m_creationListener.finishRefresh(this);
611 		}
612 	}
613 	
614 	/** {@inheritDoc} */
615 	public boolean isRefreshed() {
616 		synchronized (m_refreshedMonitor) {
617 			return m_refreshed;
618 		}
619 	}
620 }