]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/LangUtils.java
Introduce always editing CmsEditable.
[lgpl/argeo-commons.git] / org.argeo.util / src / org / argeo / util / LangUtils.java
1 package org.argeo.util;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.io.Writer;
7 import java.nio.file.Files;
8 import java.nio.file.Path;
9 import java.nio.file.StandardOpenOption;
10 import java.time.ZonedDateTime;
11 import java.time.temporal.ChronoUnit;
12 import java.time.temporal.Temporal;
13 import java.util.Dictionary;
14 import java.util.Enumeration;
15 import java.util.HashMap;
16 import java.util.Hashtable;
17 import java.util.Map;
18 import java.util.Properties;
19
20 import javax.naming.InvalidNameException;
21 import javax.naming.ldap.LdapName;
22
23 public class LangUtils {
24 /*
25 * NON-API OSGi
26 */
27 /**
28 * Returns an array with the names of the provided classes. Useful when
29 * registering services with multiple interfaces in OSGi.
30 */
31 public static String[] names(Class<?>... clzz) {
32 String[] res = new String[clzz.length];
33 for (int i = 0; i < clzz.length; i++)
34 res[i] = clzz[i].getName();
35 return res;
36 }
37
38 /*
39 * MAP
40 */
41 /**
42 * Creates a new {@link Dictionary} with one key-value pair. Key should not be
43 * null, but if the value is null, it returns an empty {@link Dictionary}.
44 */
45 public static Map<String, Object> map(String key, Object value) {
46 assert key != null;
47 HashMap<String, Object> props = new HashMap<>();
48 if (value != null)
49 props.put(key, value);
50 return props;
51 }
52
53 /*
54 * DICTIONARY
55 */
56
57 /**
58 * Creates a new {@link Dictionary} with one key-value pair. Key should not be
59 * null, but if the value is null, it returns an empty {@link Dictionary}.
60 */
61 public static Dictionary<String, Object> dict(String key, Object value) {
62 assert key != null;
63 Hashtable<String, Object> props = new Hashtable<>();
64 if (value != null)
65 props.put(key, value);
66 return props;
67 }
68
69 /** @deprecated Use {@link #dict(String, Object)} instead. */
70 @Deprecated
71 public static Dictionary<String, Object> dico(String key, Object value) {
72 return dict(key, value);
73 }
74
75 /** Converts a {@link Dictionary} to a {@link Map} of strings. */
76 public static Map<String, String> dictToStringMap(Dictionary<String, ?> properties) {
77 if (properties == null) {
78 return null;
79 }
80 Map<String, String> res = new HashMap<>(properties.size());
81 Enumeration<String> keys = properties.keys();
82 while (keys.hasMoreElements()) {
83 String key = keys.nextElement();
84 res.put(key, properties.get(key).toString());
85 }
86 return res;
87 }
88
89 /**
90 * Get a string property from this map, expecting to find it, or
91 * <code>null</code> if not found.
92 */
93 public static String get(Map<String, ?> map, String key) {
94 Object res = map.get(key);
95 if (res == null)
96 return null;
97 return res.toString();
98 }
99
100 /**
101 * Get a string property from this map, expecting to find it.
102 *
103 * @throws IllegalArgumentException if the key was not found
104 */
105 public static String getNotNull(Map<String, ?> map, String key) {
106 Object res = map.get(key);
107 if (res == null)
108 throw new IllegalArgumentException("Map " + map + " should contain key " + key);
109 return res.toString();
110 }
111
112 /**
113 * Wraps the keys of the provided {@link Dictionary} as an {@link Iterable}.
114 */
115 public static Iterable<String> keys(Dictionary<String, ?> props) {
116 assert props != null;
117 return new DictionaryKeys(props);
118 }
119
120 static String toJson(Dictionary<String, ?> props) {
121 return toJson(props, false);
122 }
123
124 static String toJson(Dictionary<String, ?> props, boolean pretty) {
125 StringBuilder sb = new StringBuilder();
126 sb.append('{');
127 if (pretty)
128 sb.append('\n');
129 Enumeration<String> keys = props.keys();
130 while (keys.hasMoreElements()) {
131 String key = keys.nextElement();
132 if (pretty)
133 sb.append(' ');
134 sb.append('\"').append(key).append('\"');
135 if (pretty)
136 sb.append(" : ");
137 else
138 sb.append(':');
139 sb.append('\"').append(props.get(key)).append('\"');
140 if (keys.hasMoreElements())
141 sb.append(", ");
142 if (pretty)
143 sb.append('\n');
144 }
145 sb.append('}');
146 return sb.toString();
147 }
148
149 static void storeAsProperties(Dictionary<String, Object> props, Path path) throws IOException {
150 if (props == null)
151 throw new IllegalArgumentException("Props cannot be null");
152 Properties toStore = new Properties();
153 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
154 String key = keys.nextElement();
155 toStore.setProperty(key, props.get(key).toString());
156 }
157 try (OutputStream out = Files.newOutputStream(path)) {
158 toStore.store(out, null);
159 }
160 }
161
162 static void appendAsLdif(String dnBase, String dnKey, Dictionary<String, Object> props, Path path)
163 throws IOException {
164 if (props == null)
165 throw new IllegalArgumentException("Props cannot be null");
166 Object dnValue = props.get(dnKey);
167 String dnStr = dnKey + '=' + dnValue + ',' + dnBase;
168 LdapName dn;
169 try {
170 dn = new LdapName(dnStr);
171 } catch (InvalidNameException e) {
172 throw new IllegalArgumentException("Cannot interpret DN " + dnStr, e);
173 }
174 if (dnValue == null)
175 throw new IllegalArgumentException("DN key " + dnKey + " must have a value");
176 try (Writer writer = Files.newBufferedWriter(path, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
177 writer.append("\ndn: ");
178 writer.append(dn.toString());
179 writer.append('\n');
180 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
181 String key = keys.nextElement();
182 Object value = props.get(key);
183 writer.append(key);
184 writer.append(": ");
185 // FIXME deal with binary and multiple values
186 writer.append(value.toString());
187 writer.append('\n');
188 }
189 }
190 }
191
192 static Dictionary<String, Object> loadFromProperties(Path path) throws IOException {
193 Properties toLoad = new Properties();
194 try (InputStream in = Files.newInputStream(path)) {
195 toLoad.load(in);
196 }
197 Dictionary<String, Object> res = new Hashtable<String, Object>();
198 for (Object key : toLoad.keySet())
199 res.put(key.toString(), toLoad.get(key));
200 return res;
201 }
202
203 /*
204 * EXCEPTIONS
205 */
206 /**
207 * Chain the messages of all causes (one per line, <b>starts with a line
208 * return</b>) without all the stack
209 */
210 public static String chainCausesMessages(Throwable t) {
211 StringBuffer buf = new StringBuffer();
212 chainCauseMessage(buf, t);
213 return buf.toString();
214 }
215
216 /** Recursive chaining of messages */
217 private static void chainCauseMessage(StringBuffer buf, Throwable t) {
218 buf.append('\n').append(' ').append(t.getClass().getCanonicalName()).append(": ").append(t.getMessage());
219 if (t.getCause() != null)
220 chainCauseMessage(buf, t.getCause());
221 }
222
223 /*
224 * TIME
225 */
226 /** Formats time elapsed since start. */
227 public static String since(ZonedDateTime start) {
228 ZonedDateTime now = ZonedDateTime.now();
229 return duration(start, now);
230 }
231
232 /** Formats a duration. */
233 public static String duration(Temporal start, Temporal end) {
234 long count = ChronoUnit.DAYS.between(start, end);
235 if (count != 0)
236 return count > 1 ? count + " days" : count + " day";
237 count = ChronoUnit.HOURS.between(start, end);
238 if (count != 0)
239 return count > 1 ? count + " hours" : count + " hours";
240 count = ChronoUnit.MINUTES.between(start, end);
241 if (count != 0)
242 return count > 1 ? count + " minutes" : count + " minute";
243 count = ChronoUnit.SECONDS.between(start, end);
244 return count > 1 ? count + " seconds" : count + " second";
245 }
246
247 /** Singleton constructor. */
248 private LangUtils() {
249
250 }
251
252 }