View Javadoc
1   /*
2    * Copyright 2019 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.context;
18  
19  import java.nio.charset.StandardCharsets;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Locale;
24  import java.util.Map;
25  import java.util.TimeZone;
26  import javax.validation.constraints.NotNull;
27  import lombok.EqualsAndHashCode;
28  import lombok.Getter;
29  import lombok.Setter;
30  import lombok.ToString;
31  import org.bremersee.common.model.JavaLocale;
32  import org.springframework.boot.context.properties.ConfigurationProperties;
33  import org.springframework.util.StringUtils;
34  import org.springframework.validation.annotation.Validated;
35  
36  /**
37   * The message source properties.
38   *
39   * @author Christian Bremer
40   */
41  @ConfigurationProperties("bremersee.messages")
42  @Getter
43  @Setter
44  @ToString
45  @EqualsAndHashCode
46  @Validated
47  public class MessageSourceProperties {
48  
49    /**
50     * Set whether to always apply the {@code MessageFormat} rules, parsing even messages without arguments.
51     *
52     * <p>Default is "false": Messages without arguments are by default
53     * returned as-is, without parsing them through MessageFormat. Set this to "true" to enforce MessageFormat for all
54     * messages, expecting all message texts to be written with MessageFormat escaping.
55     *
56     * <p>For example, MessageFormat expects a single quote to be escaped
57     * as "''". If your message texts are all written with such escaping, even when not defining argument placeholders,
58     * you need to set this flag to "true". Else, only message texts with actual arguments are supposed to be written with
59     * MessageFormat escaping.
60     *
61     * @see java.text.MessageFormat
62     */
63    private boolean alwaysUseMessageFormat = false; // from MessageSourceSupport
64  
65    /**
66     * Set whether to use the message code as default message instead of throwing a NoSuchMessageException. Useful for
67     * development and debugging. Default is "false".
68     */
69    private boolean useCodeAsDefaultMessage = false; // from AbstractMessageSource
70  
71    /**
72     * Set an list of basenames, each following the basic ResourceBundle convention of not specifying file extension or
73     * language codes. The resource location format is up to the specific {@code MessageSource} implementation.
74     *
75     * <p>Regular and XMl properties files are supported: e.g. "messages" will find
76     * a "messages.properties", "messages_en.properties" etc arrangement as well as "messages.xml", "messages_en.xml"
77     * etc.
78     *
79     * <p>The associated resource bundles will be checked sequentially when resolving
80     * a message code. Note that message definitions in a <i>previous</i> resource bundle will override ones in a later
81     * bundle, due to the sequential lookup.
82     */
83    private List<String> baseNames = new ArrayList<>(); // from AbstractResourceBasedMessageSource
84  
85    /**
86     * Set the number of seconds to cache loaded properties files.
87     * <ul>
88     * <li>Default is "-1", indicating to cache forever (just like
89     * {@code java.util.ResourceBundle}).
90     * <li>A positive number will cache loaded properties files for the given
91     * number of seconds. This is essentially the interval between refresh checks.
92     * Note that a refresh attempt will first check the last-modified timestamp
93     * of the file before actually reloading it; so if files don't change, this
94     * interval can be set rather low, as refresh attempts will not actually reload.
95     * <li>A value of "0" will check the last-modified timestamp of the file on
96     * every message access. <b>Do not use this in a production environment!</b>
97     * </ul>
98     */
99    private int cacheSeconds = -1; // from AbstractResourceBasedMessageSource
100 
101   /**
102    * Set the default charset to use for parsing properties files. Used if no file-specific charset is specified for a
103    * file.
104    *
105    * <p>The effective default is the {@code java.util.Properties}
106    * default encoding: ISO-8859-1. A {@code null} value indicates the platform default encoding.
107    *
108    * <p>Only applies to classic properties files, not to XML files.
109    */
110   private String defaultEncoding = StandardCharsets.UTF_8.name(); // from AbstractResourceBasedM.
111 
112   /**
113    * Set whether to fall back to the system Locale if no files for a specific Locale have been found. Default is "true";
114    * if this is turned off, the only fallback will be the default file (e.g. "messages.properties" for basename
115    * "messages").
116    *
117    * <p>Falling back to the system Locale is the default behavior of
118    * {@code java.util.ResourceBundle}. However, this is often not desirable in an application server environment, where
119    * the system Locale is not relevant to the application at all: set this flag to "false" in such a scenario.
120    */
121   private boolean fallbackToSystemLocale = true;
122 
123   /**
124    * Specify a default Locale to fall back to, as an alternative to falling back to the system Locale.
125    *
126    * <p>Default is to fall back to the system Locale. You may override this with
127    * a locally specified default Locale here, or enforce no fallback locale at all through disabling.
128    */
129   private String defaultLocale = "de-DE";
130 
131   /**
132    * Specify a default time zone to fall back to.
133    */
134   private String defaultTimeZone = "Europe/Berlin";
135 
136   /**
137    * Specifies whether the resource bundles are reloadable or not.
138    */
139   private boolean useReloadableMessageSource = false;
140 
141   /**
142    * Specify whether to allow for concurrent refresh behavior, i.e. one thread locked in a refresh attempt for a
143    * specific cached properties file whereas other threads keep returning the old properties for the time being, until
144    * the refresh attempt has completed.
145    *
146    * <p>Default is "true": this behavior is new as of Spring Framework 4.1,
147    * minimizing contention between threads. If you prefer the old behavior, i.e. to fully block on refresh, switch this
148    * flag to "false".
149    */
150   private boolean concurrentRefresh = true; // ReloadableResourceBundleMessageSource
151 
152   /**
153    * Set per-file charsets to use for parsing properties files.
154    *
155    * <p>Only applies to classic properties files, not to XML files.
156    */
157   private Map<String, String> fileEncodings = new HashMap<>(); // ReloadableResourceBundleMessageS.
158 
159   /**
160    * Default locale.
161    *
162    * @return the locale
163    */
164   @NotNull
165   public Locale defaultLocale() {
166     return StringUtils.hasText(getDefaultLocale())
167         ? JavaLocale.fromValue(getDefaultLocale()).toLocale(Locale.getDefault())
168         : Locale.getDefault();
169   }
170 
171   /**
172    * Default time zone.
173    *
174    * @return the time zone
175    */
176   @NotNull
177   public TimeZone defaultTimeZone() {
178     return StringUtils.hasText(getDefaultTimeZone())
179         ? TimeZone.getTimeZone(getDefaultTimeZone())
180         : TimeZone.getDefault();
181   }
182 }