001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.ui.context.support;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import org.springframework.context.HierarchicalMessageSource;
027: import org.springframework.context.MessageSource;
028: import org.springframework.context.support.ResourceBundleMessageSource;
029: import org.springframework.ui.context.HierarchicalThemeSource;
030: import org.springframework.ui.context.Theme;
031: import org.springframework.ui.context.ThemeSource;
032:
033: /**
034: * {@link ThemeSource} implementation that looks up an individual
035: * {@link java.util.ResourceBundle} per theme. The theme name gets
036: * interpreted as ResourceBundle basename, supporting a common
037: * basename prefix for all themes.
038: *
039: * @author Jean-Pierre Pawlak
040: * @author Juergen Hoeller
041: * @see #setBasenamePrefix
042: * @see java.util.ResourceBundle
043: * @see org.springframework.context.support.ResourceBundleMessageSource
044: */
045: public class ResourceBundleThemeSource implements
046: HierarchicalThemeSource {
047:
048: protected final Log logger = LogFactory.getLog(getClass());
049:
050: private ThemeSource parentThemeSource;
051:
052: private String basenamePrefix = "";
053:
054: /** Map from theme name to Theme instance */
055: private final Map themeCache = new HashMap();
056:
057: public void setParentThemeSource(ThemeSource parent) {
058: this .parentThemeSource = parent;
059:
060: // Update existing Theme objects.
061: // Usually there shouldn't be any at the time of this call.
062: synchronized (this .themeCache) {
063: Iterator it = this .themeCache.values().iterator();
064: while (it.hasNext()) {
065: initParent((Theme) it.next());
066: }
067: }
068: }
069:
070: public ThemeSource getParentThemeSource() {
071: return this .parentThemeSource;
072: }
073:
074: /**
075: * Set the prefix that gets applied to the ResourceBundle basenames,
076: * i.e. the theme names.
077: * E.g.: basenamePrefix="test.", themeName="theme" -> basename="test.theme".
078: * <p>Note that ResourceBundle names are effectively classpath locations: As a
079: * consequence, the JDK's standard ResourceBundle treats dots as package separators.
080: * This means that "test.theme" is effectively equivalent to "test/theme",
081: * just like it is for programmatic <code>java.util.ResourceBundle</code> usage.
082: * @see java.util.ResourceBundle#getBundle(String)
083: */
084: public void setBasenamePrefix(String basenamePrefix) {
085: this .basenamePrefix = (basenamePrefix != null ? basenamePrefix
086: : "");
087: }
088:
089: /**
090: * This implementation returns a SimpleTheme instance, holding a
091: * ResourceBundle-based MessageSource whose basename corresponds to
092: * the given theme name (prefixed by the configured "basenamePrefix").
093: * <p>SimpleTheme instances are cached per theme name. Use a reloadable
094: * MessageSource if themes should reflect changes to the underlying files.
095: * @see #setBasenamePrefix
096: * @see #createMessageSource
097: */
098: public Theme getTheme(String themeName) {
099: if (themeName == null) {
100: return null;
101: }
102: synchronized (this .themeCache) {
103: Theme theme = (Theme) this .themeCache.get(themeName);
104: if (theme == null) {
105: String basename = this .basenamePrefix + themeName;
106: MessageSource messageSource = createMessageSource(basename);
107: theme = new SimpleTheme(themeName, messageSource);
108: initParent(theme);
109: this .themeCache.put(themeName, theme);
110: if (logger.isDebugEnabled()) {
111: logger.debug("Theme created: name '" + themeName
112: + "', basename [" + basename + "]");
113: }
114: }
115: return theme;
116: }
117: }
118:
119: /**
120: * Create a MessageSource for the given basename,
121: * to be used as MessageSource for the corresponding theme.
122: * <p>Default implementation creates a ResourceBundleMessageSource.
123: * for the given basename. A subclass could create a specifically
124: * configured ReloadableResourceBundleMessageSource, for example.
125: * @param basename the basename to create a MessageSource for
126: * @return the MessageSource
127: * @see org.springframework.context.support.ResourceBundleMessageSource
128: * @see org.springframework.context.support.ReloadableResourceBundleMessageSource
129: */
130: protected MessageSource createMessageSource(String basename) {
131: ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
132: messageSource.setBasename(basename);
133: return messageSource;
134: }
135:
136: /**
137: * Initialize the MessageSource of the given theme with the
138: * one from the corresponding parent of this ThemeSource.
139: * @param theme the Theme to (re-)initialize
140: */
141: protected void initParent(Theme theme) {
142: if (theme.getMessageSource() instanceof HierarchicalMessageSource) {
143: HierarchicalMessageSource messageSource = (HierarchicalMessageSource) theme
144: .getMessageSource();
145: if (getParentThemeSource() != null
146: && messageSource.getParentMessageSource() == null) {
147: Theme parentTheme = getParentThemeSource().getTheme(
148: theme.getName());
149: if (parentTheme != null) {
150: messageSource.setParentMessageSource(parentTheme
151: .getMessageSource());
152: }
153: }
154: }
155: }
156:
157: }
|