001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.internal.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
018:
019: import java.util.Collection;
020: import java.util.Locale;
021: import java.util.Map;
022:
023: import org.apache.tapestry.internal.events.UpdateListener;
024: import org.apache.tapestry.internal.util.URLChangeTracker;
025: import org.apache.tapestry.ioc.MessageFormatter;
026: import org.apache.tapestry.ioc.Messages;
027: import org.apache.tapestry.ioc.Resource;
028: import org.apache.tapestry.services.ValidationMessagesSource;
029:
030: public class ValidationMessagesSourceImpl implements
031: ValidationMessagesSource, UpdateListener {
032: private final MessagesSource _messagesSource;
033:
034: private final MessagesBundle _bundle;
035:
036: private final Map<Locale, Messages> _cache = newConcurrentMap();
037:
038: private class ValidationMessagesBundle implements MessagesBundle {
039: private final Resource _baseResource;
040:
041: private final MessagesBundle _parent;
042:
043: public ValidationMessagesBundle(final Resource baseResource,
044: final MessagesBundle parent) {
045: _baseResource = baseResource;
046: _parent = parent;
047: }
048:
049: public Resource getBaseResource() {
050: return _baseResource;
051: }
052:
053: public Object getId() {
054: return _baseResource.getPath();
055: }
056:
057: public MessagesBundle getParent() {
058: return _parent;
059: }
060:
061: };
062:
063: /**
064: * Delegates to a {@link Messages} instance obtained from the {@link MessagesSource}. This
065: * ensures that changes to the underlying properties files will be reflected.
066: */
067: private class ValidationMessages implements Messages {
068: private final Locale _locale;
069:
070: public ValidationMessages(final Locale locale) {
071: _locale = locale;
072: }
073:
074: private Messages messages() {
075: // The MessagesSource caches the value returned, until any underlying file is touched,
076: // at which point an updated Messages will be returned.
077:
078: return _messagesSource.getMessages(_bundle, _locale);
079: }
080:
081: public boolean contains(String key) {
082: return messages().contains(key);
083: }
084:
085: public String format(String key, Object... args) {
086: return messages().format(key, args);
087: }
088:
089: public String get(String key) {
090: return messages().get(key);
091: }
092:
093: public MessageFormatter getFormatter(String key) {
094: // Ideally, there would be a MessageFormatterImpl that would delegate to a fresh copy
095: // of a MessageFormatter obtained from the source, but that's probably overkill.
096:
097: return messages().getFormatter(key);
098: }
099: }
100:
101: public ValidationMessagesSourceImpl(Collection<String> bundles,
102: Resource classpathRoot) {
103: this (bundles, classpathRoot, new URLChangeTracker());
104: }
105:
106: ValidationMessagesSourceImpl(Collection<String> bundles,
107: Resource classpathRoot, URLChangeTracker tracker) {
108: _messagesSource = new MessagesSourceImpl(tracker);
109:
110: MessagesBundle parent = null;
111:
112: for (String bundle : bundles) {
113: Resource bundleResource = classpathRoot.forFile(bundle);
114:
115: parent = new ValidationMessagesBundle(bundleResource,
116: parent);
117: }
118:
119: _bundle = parent;
120: }
121:
122: public Messages getValidationMessages(Locale locale) {
123: Messages result = _cache.get(locale);
124:
125: if (result == null) {
126: result = new ValidationMessages(locale);
127: _cache.put(locale, result);
128: }
129:
130: return result;
131: }
132:
133: public void checkForUpdates() {
134: // When there are changes, the Messages cached inside the MessagesSource will be discarded
135: // and will be rebuilt on demand by the ValidatonMessages instances.
136:
137: _messagesSource.checkForUpdates();
138: }
139:
140: }
|