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 }