Source Code Cross Referenced for AbstractMessageSource.java in  » J2EE » spring-framework-2.5 » org » springframework » context » support » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.5 » org.springframework.context.support 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.context.support;
018:
019:        import java.text.MessageFormat;
020:        import java.util.ArrayList;
021:        import java.util.HashMap;
022:        import java.util.List;
023:        import java.util.Locale;
024:        import java.util.Map;
025:
026:        import org.apache.commons.logging.Log;
027:        import org.apache.commons.logging.LogFactory;
028:
029:        import org.springframework.context.HierarchicalMessageSource;
030:        import org.springframework.context.MessageSource;
031:        import org.springframework.context.MessageSourceResolvable;
032:        import org.springframework.context.NoSuchMessageException;
033:        import org.springframework.util.ObjectUtils;
034:
035:        /**
036:         * Abstract implementation of the {@link HierarchicalMessageSource} interface,
037:         * implementing common handling of message variants, making it easy
038:         * to implement a specific strategy for a concrete MessageSource.
039:         *
040:         * <p>Subclasses must implement the abstract {@link #resolveCode}
041:         * method. For efficient resolution of messages without arguments, the
042:         * {@link #resolveCodeWithoutArguments} method should be overridden
043:         * as well, resolving messages without a MessageFormat being involved.
044:         *
045:         * <p><b>Note:</b> By default, message texts are only parsed through
046:         * MessageFormat if arguments have been passed in for the message. In case
047:         * of no arguments, message texts will be returned as-is. As a consequence,
048:         * you should only use MessageFormat escaping for messages with actual
049:         * arguments, and keep all other messages unescaped. If you prefer to
050:         * escape all messages, set the "alwaysUseMessageFormat" flag to "true".
051:         *
052:         * <p>Supports not only MessageSourceResolvables as primary messages
053:         * but also resolution of message arguments that are in turn
054:         * MessageSourceResolvables themselves.
055:         *
056:         * <p>This class does not implement caching of messages per code, thus
057:         * subclasses can dynamically change messages over time. Subclasses are
058:         * encouraged to cache their messages in a modification-aware fashion,
059:         * allowing for hot deployment of updated messages.
060:         *
061:         * @author Juergen Hoeller
062:         * @author Rod Johnson
063:         * @see #resolveCode(String, java.util.Locale)
064:         * @see #resolveCodeWithoutArguments(String, java.util.Locale)
065:         * @see #setAlwaysUseMessageFormat
066:         * @see java.text.MessageFormat
067:         */
068:        public abstract class AbstractMessageSource implements 
069:                HierarchicalMessageSource {
070:
071:            /** Logger available to subclasses */
072:            protected final Log logger = LogFactory.getLog(getClass());
073:
074:            private MessageSource parentMessageSource;
075:
076:            private boolean useCodeAsDefaultMessage = false;
077:
078:            private boolean alwaysUseMessageFormat = false;
079:
080:            /**
081:             * Cache to hold already generated MessageFormats per message.
082:             * Used for passed-in default messages. MessageFormats for resolved
083:             * codes are cached on a specific basis in subclasses.
084:             */
085:            private final Map cachedMessageFormats = new HashMap();
086:
087:            public void setParentMessageSource(MessageSource parent) {
088:                this .parentMessageSource = parent;
089:            }
090:
091:            public MessageSource getParentMessageSource() {
092:                return this .parentMessageSource;
093:            }
094:
095:            /**
096:             * Set whether to use the message code as default message instead of
097:             * throwing a NoSuchMessageException. Useful for development and debugging.
098:             * Default is "false".
099:             * <p>Note: In case of a MessageSourceResolvable with multiple codes
100:             * (like a FieldError) and a MessageSource that has a parent MessageSource,
101:             * do <i>not</i> activate "useCodeAsDefaultMessage" in the <i>parent</i>:
102:             * Else, you'll get the first code returned as message by the parent,
103:             * without attempts to check further codes.
104:             * <p>To be able to work with "useCodeAsDefaultMessage" turned on in the parent,
105:             * AbstractMessageSource and AbstractApplicationContext contain special checks
106:             * to delegate to the internal <code>getMessageInternal</code> method if available.
107:             * In general, it is recommended to just use "useCodeAsDefaultMessage" during
108:             * development and not rely on it in production in the first place, though.
109:             * @see #getMessage(String, Object[], Locale)
110:             * @see #getMessageInternal
111:             * @see org.springframework.validation.FieldError
112:             */
113:            public void setUseCodeAsDefaultMessage(
114:                    boolean useCodeAsDefaultMessage) {
115:                this .useCodeAsDefaultMessage = useCodeAsDefaultMessage;
116:            }
117:
118:            /**
119:             * Return whether to use the message code as default message instead of
120:             * throwing a NoSuchMessageException. Useful for development and debugging.
121:             * Default is "false".
122:             * <p>Alternatively, consider overriding the <code>getDefaultMessage</code>
123:             * method to return a custom fallback message for an unresolvable code.
124:             * @see #getDefaultMessage(String)
125:             */
126:            protected boolean isUseCodeAsDefaultMessage() {
127:                return this .useCodeAsDefaultMessage;
128:            }
129:
130:            /**
131:             * Set whether to always apply the MessageFormat rules, parsing even
132:             * messages without arguments.
133:             * <p>Default is "false": Messages without arguments are by default
134:             * returned as-is, without parsing them through MessageFormat.
135:             * Set this to "true" to enforce MessageFormat for all messages,
136:             * expecting all message texts to be written with MessageFormat escaping.
137:             * <p>For example, MessageFormat expects a single quote to be escaped
138:             * as "''". If your message texts are all written with such escaping,
139:             * even when not defining argument placeholders, you need to set this
140:             * flag to "true". Else, only message texts with actual arguments
141:             * are supposed to be written with MessageFormat escaping.
142:             * @see java.text.MessageFormat
143:             */
144:            public void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {
145:                this .alwaysUseMessageFormat = alwaysUseMessageFormat;
146:            }
147:
148:            /**
149:             * Return whether to always apply the MessageFormat rules, parsing even
150:             * messages without arguments.
151:             */
152:            protected boolean isAlwaysUseMessageFormat() {
153:                return this .alwaysUseMessageFormat;
154:            }
155:
156:            public final String getMessage(String code, Object[] args,
157:                    String defaultMessage, Locale locale) {
158:                String msg = getMessageInternal(code, args, locale);
159:                if (msg != null) {
160:                    return msg;
161:                }
162:                if (defaultMessage == null) {
163:                    String fallback = getDefaultMessage(code);
164:                    if (fallback != null) {
165:                        return fallback;
166:                    }
167:                }
168:                return renderDefaultMessage(defaultMessage, args, locale);
169:            }
170:
171:            public final String getMessage(String code, Object[] args,
172:                    Locale locale) throws NoSuchMessageException {
173:                String msg = getMessageInternal(code, args, locale);
174:                if (msg != null) {
175:                    return msg;
176:                }
177:                String fallback = getDefaultMessage(code);
178:                if (fallback != null) {
179:                    return fallback;
180:                }
181:                throw new NoSuchMessageException(code, locale);
182:            }
183:
184:            public final String getMessage(MessageSourceResolvable resolvable,
185:                    Locale locale) throws NoSuchMessageException {
186:
187:                String[] codes = resolvable.getCodes();
188:                if (codes == null) {
189:                    codes = new String[0];
190:                }
191:                for (int i = 0; i < codes.length; i++) {
192:                    String msg = getMessageInternal(codes[i], resolvable
193:                            .getArguments(), locale);
194:                    if (msg != null) {
195:                        return msg;
196:                    }
197:                }
198:                if (resolvable.getDefaultMessage() != null) {
199:                    return renderDefaultMessage(resolvable.getDefaultMessage(),
200:                            resolvable.getArguments(), locale);
201:                }
202:                if (codes.length > 0) {
203:                    String fallback = getDefaultMessage(codes[0]);
204:                    if (fallback != null) {
205:                        return fallback;
206:                    }
207:                }
208:                throw new NoSuchMessageException(
209:                        codes.length > 0 ? codes[codes.length - 1] : null,
210:                        locale);
211:            }
212:
213:            /**
214:             * Resolve the given code and arguments as message in the given Locale,
215:             * returning null if not found. Does <i>not</i> fall back to the code
216:             * as default message. Invoked by getMessage methods.
217:             * @param code the code to lookup up, such as 'calculator.noRateSet'
218:             * @param args array of arguments that will be filled in for params
219:             * within the message
220:             * @param locale the Locale in which to do the lookup
221:             * @return the resolved message, or <code>null</code> if not found
222:             * @see #getMessage(String, Object[], String, Locale)
223:             * @see #getMessage(String, Object[], Locale)
224:             * @see #getMessage(MessageSourceResolvable, Locale)
225:             * @see #setUseCodeAsDefaultMessage
226:             */
227:            protected String getMessageInternal(String code, Object[] args,
228:                    Locale locale) {
229:                if (code == null) {
230:                    return null;
231:                }
232:                if (locale == null) {
233:                    locale = Locale.getDefault();
234:                }
235:                Object[] argsToUse = args;
236:
237:                if (!isAlwaysUseMessageFormat() && ObjectUtils.isEmpty(args)) {
238:                    // Optimized resolution: no arguments to apply,
239:                    // therefore no MessageFormat needs to be involved.
240:                    // Note that the default implementation still uses MessageFormat;
241:                    // this can be overridden in specific subclasses.
242:                    String message = resolveCodeWithoutArguments(code, locale);
243:                    if (message != null) {
244:                        return message;
245:                    }
246:                }
247:
248:                else {
249:                    // Resolve arguments eagerly, for the case where the message
250:                    // is defined in a parent MessageSource but resolvable arguments
251:                    // are defined in the child MessageSource.
252:                    argsToUse = resolveArguments(args, locale);
253:
254:                    MessageFormat messageFormat = resolveCode(code, locale);
255:                    if (messageFormat != null) {
256:                        synchronized (messageFormat) {
257:                            return messageFormat.format(argsToUse);
258:                        }
259:                    }
260:                }
261:
262:                // Not found -> check parent, if any.
263:                return getMessageFromParent(code, argsToUse, locale);
264:            }
265:
266:            /**
267:             * Try to retrieve the given message from the parent MessageSource, if any.
268:             * @param code the code to lookup up, such as 'calculator.noRateSet'
269:             * @param args array of arguments that will be filled in for params
270:             * within the message
271:             * @param locale the Locale in which to do the lookup
272:             * @return the resolved message, or <code>null</code> if not found
273:             * @see #getParentMessageSource()
274:             */
275:            protected String getMessageFromParent(String code, Object[] args,
276:                    Locale locale) {
277:                MessageSource parent = getParentMessageSource();
278:                if (parent != null) {
279:                    if (parent instanceof  AbstractMessageSource) {
280:                        // Call internal method to avoid getting the default code back
281:                        // in case of "useCodeAsDefaultMessage" being activated.
282:                        return ((AbstractMessageSource) parent)
283:                                .getMessageInternal(code, args, locale);
284:                    } else {
285:                        // Check parent MessageSource, returning null if not found there.
286:                        return parent.getMessage(code, args, null, locale);
287:                    }
288:                }
289:                // Not found in parent either.
290:                return null;
291:            }
292:
293:            /**
294:             * Return a fallback default message for the given code, if any.
295:             * <p>Default is to return the code itself if "useCodeAsDefaultMessage"
296:             * is activated, or return no fallback else. In case of no fallback,
297:             * the caller will usually receive a NoSuchMessageException from
298:             * <code>getMessage</code>.
299:             * @param code the message code that we couldn't resolve
300:             * and that we didn't receive an explicit default message for
301:             * @return the default message to use, or <code>null</code> if none
302:             * @see #setUseCodeAsDefaultMessage
303:             */
304:            protected String getDefaultMessage(String code) {
305:                if (isUseCodeAsDefaultMessage()) {
306:                    return code;
307:                }
308:                return null;
309:            }
310:
311:            /**
312:             * Render the given default message String. The default message is
313:             * passed in as specified by the caller and can be rendered into
314:             * a fully formatted default message shown to the user.
315:             * <p>Default implementation passes the String to <code>formatMessage</code>,
316:             * resolving any argument placeholders found in them. Subclasses may override
317:             * this method to plug in custom processing of default messages.
318:             * @param defaultMessage the passed-in default message String
319:             * @param args array of arguments that will be filled in for params within
320:             * the message, or <code>null</code> if none.
321:             * @param locale the Locale used for formatting
322:             * @return the rendered default message (with resolved arguments)
323:             * @see #formatMessage(String, Object[], java.util.Locale)
324:             */
325:            protected String renderDefaultMessage(String defaultMessage,
326:                    Object[] args, Locale locale) {
327:                return formatMessage(defaultMessage, args, locale);
328:            }
329:
330:            /**
331:             * Format the given message String, using cached MessageFormats.
332:             * By default invoked for passed-in default messages, to resolve
333:             * any argument placeholders found in them.
334:             * @param msg the message to format
335:             * @param args array of arguments that will be filled in for params within
336:             * the message, or <code>null</code> if none.
337:             * @param locale the Locale used for formatting
338:             * @return the formatted message (with resolved arguments)
339:             */
340:            protected String formatMessage(String msg, Object[] args,
341:                    Locale locale) {
342:                if (msg == null
343:                        || (!this .alwaysUseMessageFormat && (args == null || args.length == 0))) {
344:                    return msg;
345:                }
346:                MessageFormat messageFormat = null;
347:                synchronized (this .cachedMessageFormats) {
348:                    messageFormat = (MessageFormat) this .cachedMessageFormats
349:                            .get(msg);
350:                    if (messageFormat == null) {
351:                        messageFormat = createMessageFormat(msg, locale);
352:                        this .cachedMessageFormats.put(msg, messageFormat);
353:                    }
354:                }
355:                synchronized (messageFormat) {
356:                    return messageFormat.format(resolveArguments(args, locale));
357:                }
358:            }
359:
360:            /**
361:             * Create a MessageFormat for the given message and Locale.
362:             * <p>This implementation creates an empty MessageFormat first,
363:             * populating it with Locale and pattern afterwards, to stay
364:             * compatible with J2SE 1.3.
365:             * @param msg the message to create a MessageFormat for
366:             * @param locale the Locale to create a MessageFormat for
367:             * @return the MessageFormat instance
368:             */
369:            protected MessageFormat createMessageFormat(String msg,
370:                    Locale locale) {
371:                if (logger.isDebugEnabled()) {
372:                    logger.debug("Creating MessageFormat for pattern [" + msg
373:                            + "] and locale '" + locale + "'");
374:                }
375:                MessageFormat messageFormat = new MessageFormat("");
376:                messageFormat.setLocale(locale);
377:                if (msg != null) {
378:                    messageFormat.applyPattern(msg);
379:                }
380:                return messageFormat;
381:            }
382:
383:            /**
384:             * Search through the given array of objects, find any
385:             * MessageSourceResolvable objects and resolve them.
386:             * <p>Allows for messages to have MessageSourceResolvables as arguments.
387:             * @param args array of arguments for a message
388:             * @param locale the locale to resolve through
389:             * @return an array of arguments with any MessageSourceResolvables resolved
390:             */
391:            protected Object[] resolveArguments(Object[] args, Locale locale) {
392:                if (args == null) {
393:                    return new Object[0];
394:                }
395:                List resolvedArgs = new ArrayList(args.length);
396:                for (int i = 0; i < args.length; i++) {
397:                    if (args[i] instanceof  MessageSourceResolvable) {
398:                        resolvedArgs.add(getMessage(
399:                                (MessageSourceResolvable) args[i], locale));
400:                    } else {
401:                        resolvedArgs.add(args[i]);
402:                    }
403:                }
404:                return resolvedArgs.toArray(new Object[resolvedArgs.size()]);
405:            }
406:
407:            /**
408:             * Subclasses can override this method to resolve a message without
409:             * arguments in an optimized fashion, that is, to resolve a message
410:             * without involving a MessageFormat.
411:             * <p>The default implementation <i>does</i> use MessageFormat,
412:             * through delegating to the <code>resolveCode</code> method.
413:             * Subclasses are encouraged to replace this with optimized resolution.
414:             * <p>Unfortunately, <code>java.text.MessageFormat</code> is not
415:             * implemented in an efficient fashion. In particular, it does not
416:             * detect that a message pattern doesn't contain argument placeholders
417:             * in the first place. Therefore, it's advisable to circumvent
418:             * MessageFormat completely for messages without arguments.
419:             * @param code the code of the message to resolve
420:             * @param locale the Locale to resolve the code for
421:             * (subclasses are encouraged to support internationalization)
422:             * @return the message String, or <code>null</code> if not found
423:             * @see #resolveCode
424:             * @see java.text.MessageFormat
425:             */
426:            protected String resolveCodeWithoutArguments(String code,
427:                    Locale locale) {
428:                MessageFormat messageFormat = resolveCode(code, locale);
429:                if (messageFormat != null) {
430:                    synchronized (messageFormat) {
431:                        return messageFormat.format(new Object[0]);
432:                    }
433:                }
434:                return null;
435:            }
436:
437:            /**
438:             * Subclasses must implement this method to resolve a message.
439:             * <p>Returns a MessageFormat instance rather than a message String,
440:             * to allow for appropriate caching of MessageFormats in subclasses.
441:             * <p><b>Subclasses are encouraged to provide optimized resolution
442:             * for messages without arguments, not involving MessageFormat.</b>
443:             * See <code>resolveCodeWithoutArguments</code> javadoc for details.
444:             * @param code the code of the message to resolve
445:             * @param locale the Locale to resolve the code for
446:             * (subclasses are encouraged to support internationalization)
447:             * @return the MessageFormat for the message, or <code>null</code> if not found
448:             * @see #resolveCodeWithoutArguments(String, java.util.Locale)
449:             */
450:            protected abstract MessageFormat resolveCode(String code,
451:                    Locale locale);
452:
453:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.