1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.common.config;
20
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25 import java.io.StringWriter;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.regex.Pattern;
30 import java.util.stream.Collectors;
31
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.mycore.common.MCRException;
35 import org.mycore.common.MCRPropertiesResolver;
36
37 public final class MCRConfigurationBase {
38 static final Pattern PROPERTY_SPLITTER = Pattern.compile(",");
39
40
41
42
43
44 private static MCRProperties baseProperties = new MCRProperties();
45
46
47
48
49 private static MCRProperties resolvedProperties = new MCRProperties();
50
51
52
53
54 private static MCRProperties deprecatedProperties = new MCRProperties();
55
56 private static File lastModifiedFile;
57
58 static {
59 try {
60 createLastModifiedFile();
61 } catch (IOException e) {
62 throw new MCRConfigurationException("Could not initialize MyCoRe configuration", e);
63 }
64 }
65
66 private MCRConfigurationBase() {
67 }
68
69
70
71
72
73
74
75 public static long getSystemLastModified() {
76 return lastModifiedFile.lastModified();
77 }
78
79
80
81
82 public static void systemModified() {
83 if (!lastModifiedFile.exists()) {
84 try {
85 createLastModifiedFile();
86 } catch (IOException ioException) {
87 throw new MCRException("Could not change modify date of file " + lastModifiedFile.getAbsolutePath(),
88 ioException);
89 }
90 } else if (!lastModifiedFile.setLastModified(System.currentTimeMillis())) {
91
92
93
94
95
96
97
98 FileOutputStream fout = null;
99 try {
100 try {
101 fout = new FileOutputStream(lastModifiedFile);
102 fout.write(new byte[0]);
103 lastModifiedFile.setWritable(true, false);
104 } finally {
105 if (fout != null) {
106 fout.close();
107 }
108 }
109 } catch (IOException e) {
110 throw new MCRException("Could not change modify date of file " + lastModifiedFile.getAbsolutePath(), e);
111 }
112 }
113 }
114
115
116
117
118 private static synchronized void createLastModifiedFile() throws IOException {
119 final String dataDirKey = "MCR.datadir";
120 if (getResolvedProperties().containsKey(dataDirKey)) {
121 Optional<File> dataDir = getString(dataDirKey)
122 .map(File::new);
123 if (dataDir.filter(File::exists)
124 .filter(File::isDirectory).isPresent()) {
125 lastModifiedFile = dataDir.map(p -> new File(p, ".systemTime")).get();
126 } else {
127 dataDir
128 .ifPresent(d -> System.err.println("WARNING: MCR.dataDir does not exist: " + d.getAbsolutePath()));
129 }
130 }
131 if (lastModifiedFile == null) {
132 try {
133 lastModifiedFile = File.createTempFile("MyCoRe", ".systemTime");
134 lastModifiedFile.deleteOnExit();
135 } catch (IOException e) {
136 throw new MCRException("Could not create temporary file, please set property MCR.datadir");
137 }
138 }
139 if (!lastModifiedFile.exists()) {
140 FileOutputStream fout = null;
141 try {
142 fout = new FileOutputStream(lastModifiedFile);
143 fout.write(new byte[0]);
144 } finally {
145 if (fout != null) {
146 fout.close();
147 }
148 }
149
150 lastModifiedFile.setWritable(true, false);
151 }
152 }
153
154 private static void debug() {
155 String comments = "Active mycore properties";
156 File resolvedPropertiesFile = MCRConfigurationDir.getConfigFile("mycore.resolved.properties");
157 if (resolvedPropertiesFile != null) {
158 try (FileOutputStream fout = new FileOutputStream(resolvedPropertiesFile)) {
159 getResolvedProperties().store(fout, comments + "\nDo NOT edit this file!");
160 } catch (IOException e) {
161 LogManager.getLogger()
162 .warn("Could not store resolved properties to {}", resolvedPropertiesFile.getAbsolutePath(),
163 e);
164 }
165 }
166
167 Logger logger = LogManager.getLogger();
168 if (logger.isDebugEnabled()) {
169 try (StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw)) {
170 getResolvedProperties().store(out, comments);
171 out.flush();
172 sw.flush();
173 logger.debug(sw.toString());
174 } catch (IOException e) {
175 logger.debug("Error while debugging mycore properties.", e);
176 }
177 }
178 }
179
180
181
182
183 protected static synchronized void resolveProperties() {
184 MCRProperties tmpProperties = MCRProperties.copy(getBaseProperties());
185 MCRPropertiesResolver resolver = new MCRPropertiesResolver(tmpProperties);
186 resolvedProperties = MCRProperties.copy(resolver.resolveAll(tmpProperties));
187 }
188
189 private static void checkForDeprecatedProperties(Map<String, String> props) {
190 Map<String, String> depUsedProps = props.entrySet().stream()
191 .filter(e -> getDeprecatedProperties().containsKey(e.getKey()))
192 .collect(Collectors.toMap(Map.Entry::getKey, e -> getDeprecatedProperties().getAsMap().get(e.getKey())));
193 if (!depUsedProps.isEmpty()) {
194 throw new MCRConfigurationException(
195 depUsedProps.entrySet().stream().map(e -> e.getKey() + " ==> " + e.getValue())
196 .collect(Collectors.joining("\n",
197 "Found deprecated properties that are defined but will NOT BE USED. "
198 + "Please use the replacements:\n",
199 "\n")));
200 }
201 }
202
203 private static void checkForDeprecatedProperty(String name) throws MCRConfigurationException {
204 if (getDeprecatedProperties().containsKey(name)) {
205 throw new MCRConfigurationException("Cannot set deprecated property " + name + ". Please use "
206 + getDeprecatedProperties().getProperty(name) + " instead.");
207 }
208 }
209
210 protected static MCRProperties getResolvedProperties() {
211 return resolvedProperties;
212 }
213
214 protected static MCRProperties getBaseProperties() {
215 return baseProperties;
216 }
217
218 protected static MCRProperties getDeprecatedProperties() {
219 return deprecatedProperties;
220 }
221
222
223
224
225
226
227
228
229
230
231 public static Optional<String> getString(String name) {
232 if (Objects.requireNonNull(name, "MyCoRe property name must not be null.").trim().isEmpty()) {
233 throw new MCRConfigurationException("MyCoRe property name must not be empty.");
234 }
235 if (name.trim() != name) {
236 throw new MCRConfigurationException(
237 "MyCoRe property name must not contain trailing or leading whitespaces: '" + name + "'");
238 }
239 if (getBaseProperties().isEmpty()) {
240 throw new MCRConfigurationException("MCRConfiguration is still not initialized");
241 }
242 return getStringUnchecked(name);
243 }
244
245 static Optional<String> getStringUnchecked(String name) {
246 checkForDeprecatedProperty(name);
247 return Optional.ofNullable(getResolvedProperties().getProperty(name, null));
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261 static void set(String name, String value) {
262 checkForDeprecatedProperty(name);
263 if (value == null) {
264 getBaseProperties().remove(name);
265 } else {
266 getBaseProperties().setProperty(name, value);
267 }
268 resolveProperties();
269 }
270
271 public static synchronized void initialize(Map<String, String> deprecated, Map<String, String> props,
272 boolean clear) {
273 if (clear) {
274 deprecatedProperties.clear();
275 }
276 deprecatedProperties.putAll(deprecated);
277 checkForDeprecatedProperties(props);
278 if (clear) {
279 getBaseProperties().clear();
280 } else {
281 getBaseProperties().entrySet()
282 .removeIf(e -> props.containsKey(e.getKey()) && props.get(e.getKey()) == null);
283 }
284 getBaseProperties().putAll(
285 props.entrySet()
286 .stream()
287 .filter(e -> e.getKey() != null)
288 .filter(e -> e.getValue() != null)
289 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
290 resolveProperties();
291 debug();
292 }
293
294 }