]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/LangUtils.java
Improve systemd deployment.
[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 * DICTIONARY
40 */
41
42 /**
43 * Creates a new {@link Dictionary} with one key-value pair (neither key not
44 * value should be null)
45 */
46 public static Dictionary<String, Object> dict(String key, Object value) {
47 assert key != null;
48 assert value != null;
49 Hashtable<String, Object> props = new Hashtable<>();
50 props.put(key, value);
51 return props;
52 }
53
54 /**@deprecated Use {@link #dict(String, Object)} instead.*/
55 @Deprecated
56 public static Dictionary<String, Object> dico(String key, Object value) {
57 return dict(key, value);
58 }
59
60 /** Converts a {@link Dictionary} to a {@link Map} of strings. */
61 public static Map<String, String> dictToStringMap(Dictionary<String, ?> properties) {
62 if (properties == null) {
63 return null;
64 }
65 Map<String, String> res = new HashMap<>(properties.size());
66 Enumeration<String> keys = properties.keys();
67 while (keys.hasMoreElements()) {
68 String key = keys.nextElement();
69 res.put(key, properties.get(key).toString());
70 }
71 return res;
72 }
73
74 /**
75 * Wraps the keys of the provided {@link Dictionary} as an {@link Iterable}.
76 */
77 public static Iterable<String> keys(Dictionary<String, ?> props) {
78 assert props != null;
79 return new DictionaryKeys(props);
80 }
81
82 static String toJson(Dictionary<String, ?> props) {
83 return toJson(props, false);
84 }
85
86 static String toJson(Dictionary<String, ?> props, boolean pretty) {
87 StringBuilder sb = new StringBuilder();
88 sb.append('{');
89 if (pretty)
90 sb.append('\n');
91 Enumeration<String> keys = props.keys();
92 while (keys.hasMoreElements()) {
93 String key = keys.nextElement();
94 if (pretty)
95 sb.append(' ');
96 sb.append('\"').append(key).append('\"');
97 if (pretty)
98 sb.append(" : ");
99 else
100 sb.append(':');
101 sb.append('\"').append(props.get(key)).append('\"');
102 if (keys.hasMoreElements())
103 sb.append(", ");
104 if (pretty)
105 sb.append('\n');
106 }
107 sb.append('}');
108 return sb.toString();
109 }
110
111 static void storeAsProperties(Dictionary<String, Object> props, Path path) throws IOException {
112 if (props == null)
113 throw new IllegalArgumentException("Props cannot be null");
114 Properties toStore = new Properties();
115 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
116 String key = keys.nextElement();
117 toStore.setProperty(key, props.get(key).toString());
118 }
119 try (OutputStream out = Files.newOutputStream(path)) {
120 toStore.store(out, null);
121 }
122 }
123
124 static void appendAsLdif(String dnBase, String dnKey, Dictionary<String, Object> props, Path path)
125 throws IOException {
126 if (props == null)
127 throw new IllegalArgumentException("Props cannot be null");
128 Object dnValue = props.get(dnKey);
129 String dnStr = dnKey + '=' + dnValue + ',' + dnBase;
130 LdapName dn;
131 try {
132 dn = new LdapName(dnStr);
133 } catch (InvalidNameException e) {
134 throw new IllegalArgumentException("Cannot interpret DN " + dnStr, e);
135 }
136 if (dnValue == null)
137 throw new IllegalArgumentException("DN key " + dnKey + " must have a value");
138 try (Writer writer = Files.newBufferedWriter(path, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
139 writer.append("\ndn: ");
140 writer.append(dn.toString());
141 writer.append('\n');
142 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
143 String key = keys.nextElement();
144 Object value = props.get(key);
145 writer.append(key);
146 writer.append(": ");
147 // FIXME deal with binary and multiple values
148 writer.append(value.toString());
149 writer.append('\n');
150 }
151 }
152 }
153
154 static Dictionary<String, Object> loadFromProperties(Path path) throws IOException {
155 Properties toLoad = new Properties();
156 try (InputStream in = Files.newInputStream(path)) {
157 toLoad.load(in);
158 }
159 Dictionary<String, Object> res = new Hashtable<String, Object>();
160 for (Object key : toLoad.keySet())
161 res.put(key.toString(), toLoad.get(key));
162 return res;
163 }
164
165 /*
166 * EXCEPTIONS
167 */
168 /**
169 * Chain the messages of all causes (one per line, <b>starts with a line
170 * return</b>) without all the stack
171 */
172 public static String chainCausesMessages(Throwable t) {
173 StringBuffer buf = new StringBuffer();
174 chainCauseMessage(buf, t);
175 return buf.toString();
176 }
177
178 /** Recursive chaining of messages */
179 private static void chainCauseMessage(StringBuffer buf, Throwable t) {
180 buf.append('\n').append(' ').append(t.getClass().getCanonicalName()).append(": ").append(t.getMessage());
181 if (t.getCause() != null)
182 chainCauseMessage(buf, t.getCause());
183 }
184
185 /*
186 * TIME
187 */
188 /** Formats time elapsed since start. */
189 public static String since(ZonedDateTime start) {
190 ZonedDateTime now = ZonedDateTime.now();
191 return duration(start, now);
192 }
193
194 /** Formats a duration. */
195 public static String duration(Temporal start, Temporal end) {
196 long count = ChronoUnit.DAYS.between(start, end);
197 if (count != 0)
198 return count > 1 ? count + " days" : count + " day";
199 count = ChronoUnit.HOURS.between(start, end);
200 if (count != 0)
201 return count > 1 ? count + " hours" : count + " hours";
202 count = ChronoUnit.MINUTES.between(start, end);
203 if (count != 0)
204 return count > 1 ? count + " minutes" : count + " minute";
205 count = ChronoUnit.SECONDS.between(start, end);
206 return count > 1 ? count + " seconds" : count + " second";
207 }
208
209 /** Singleton constructor. */
210 private LangUtils() {
211
212 }
213
214 }