1 /*
2 * *************************************************************************************************************************************************************
3 *
4 * TheseFoolishThings: Miscellaneous utilities
5 * http://tidalwave.it/projects/thesefoolishthings
6 *
7 * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8 *
9 * *************************************************************************************************************************************************************
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18 *
19 * *************************************************************************************************************************************************************
20 *
21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.util.impl;
27
28 import jakarta.annotation.Nonnull;
29 import java.util.HashMap;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.io.IOException;
35 import java.nio.file.Files;
36 import java.nio.file.Path;
37 import it.tidalwave.util.Key;
38 import it.tidalwave.util.PreferencesHandler;
39 import lombok.Getter;
40 import lombok.RequiredArgsConstructor;
41
42 /***************************************************************************************************************************************************************
43 *
44 * @author Fabrizio Giudici
45 *
46 **************************************************************************************************************************************************************/
47 @RequiredArgsConstructor
48 // PreferencesHandler can be used to programmatically set the log folder, so don't inject logger
49 public class DefaultPreferencesHandler implements PreferencesHandler
50 {
51 @Getter
52 private final Path appFolder;
53
54 @Getter
55 private final Path logFolder;
56
57 private final Map<Key<?>, Object> properties = new HashMap<>();
58
59 public DefaultPreferencesHandler()
60 {
61 try
62 {
63 final var appName = System.getProperty(PROP_APP_NAME);
64 Objects.requireNonNull(appName, "You must call PreferencesHandler.setAppName(\"...\") before getting here");
65
66 final var osName = System.getProperty("os.name").toLowerCase(Locale.getDefault());
67 var pattern = "";
68
69 switch (osName)
70 {
71 case "linux":
72 pattern = "%s/.%s/";
73 break;
74
75 case "mac os x":
76 pattern = "%s/Library/Application Support/%s/";
77 break;
78
79 case "windows":
80 pattern = "%s/AppData/Local/%s/";
81 break;
82
83 default:
84 throw new ExceptionInInitializerError("Unknown o.s.: " + osName);
85 }
86
87 final var home = System.getProperty("user.home", "/tmp");
88 appFolder = Path.of(String.format(pattern, home, appName)).toAbsolutePath();
89 logFolder = appFolder.resolve("logs").toAbsolutePath();
90 Files.createDirectories(logFolder);
91 // PreferencesHandler can be used to programmatically set the log folder, so don't log yet
92 if (!Boolean.getBoolean(PROP_SUPPRESS_CONSOLE))
93 {
94 System.out.printf("App folder: %s%n", appFolder);
95 System.out.printf("Logging folder: %s%n", logFolder);
96 }
97 }
98 catch (IOException e)
99 {
100 throw new RuntimeException(e);
101 }
102 }
103
104 @Override @Nonnull
105 public <T> Optional<T> getProperty (@Nonnull final Key<T> name)
106 {
107 return Optional.ofNullable((T)properties.get(name));
108 }
109
110 @Override
111 public <T> void setProperty (@Nonnull final Key<T> name, @Nonnull final T value)
112 {
113 properties.put(name, value);
114 // FIXME: should be made persistent (JSON?)
115 }
116
117 @Override
118 public <T> void setDefaultProperty (@Nonnull final Key<T> name, @Nonnull final T value)
119 {
120 if (!properties.containsKey(name))
121 {
122 setProperty(name, value);
123 }
124 }
125 }