]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.util/src/org/argeo/util/LangUtils.java
Fix issue with CMS deployment marked twice as available when state has
[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.Hashtable;
16 import java.util.Properties;
17
18 import javax.naming.InvalidNameException;
19 import javax.naming.ldap.LdapName;
20
21 public class LangUtils {
22 /*
23 * NON-API OSGi
24 */
25 /**
26 * Returns an array with the names of the provided classes. Useful when
27 * registering services with multiple interfaces in OSGi.
28 */
29 public static String[] names(Class<?>... clzz) {
30 String[] res = new String[clzz.length];
31 for (int i = 0; i < clzz.length; i++)
32 res[i] = clzz[i].getName();
33 return res;
34 }
35
36 /*
37 * DICTIONARY
38 */
39
40 /**
41 * Creates a new {@link Dictionary} with one key-value pair (neither key not
42 * value should be null)
43 */
44 public static Dictionary<String, Object> dico(String key, Object value) {
45 assert key != null;
46 assert value != null;
47 Hashtable<String, Object> props = new Hashtable<>();
48 props.put(key, value);
49 return props;
50 }
51
52 /**
53 * Wraps the keys of the provided {@link Dictionary} as an {@link Iterable}.
54 */
55 public static Iterable<String> keys(Dictionary<String, ?> props) {
56 assert props != null;
57 return new DictionaryKeys(props);
58 }
59
60 static String toJson(Dictionary<String, ?> props) {
61 return toJson(props, false);
62 }
63
64 static String toJson(Dictionary<String, ?> props, boolean pretty) {
65 StringBuilder sb = new StringBuilder();
66 sb.append('{');
67 if (pretty)
68 sb.append('\n');
69 Enumeration<String> keys = props.keys();
70 while (keys.hasMoreElements()) {
71 String key = keys.nextElement();
72 if (pretty)
73 sb.append(' ');
74 sb.append('\"').append(key).append('\"');
75 if (pretty)
76 sb.append(" : ");
77 else
78 sb.append(':');
79 sb.append('\"').append(props.get(key)).append('\"');
80 if (keys.hasMoreElements())
81 sb.append(", ");
82 if (pretty)
83 sb.append('\n');
84 }
85 sb.append('}');
86 return sb.toString();
87 }
88
89 static void storeAsProperties(Dictionary<String, Object> props, Path path) throws IOException {
90 if (props == null)
91 throw new IllegalArgumentException("Props cannot be null");
92 Properties toStore = new Properties();
93 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
94 String key = keys.nextElement();
95 toStore.setProperty(key, props.get(key).toString());
96 }
97 try (OutputStream out = Files.newOutputStream(path)) {
98 toStore.store(out, null);
99 }
100 }
101
102 static void appendAsLdif(String dnBase, String dnKey, Dictionary<String, Object> props, Path path)
103 throws IOException {
104 if (props == null)
105 throw new IllegalArgumentException("Props cannot be null");
106 Object dnValue = props.get(dnKey);
107 String dnStr = dnKey + '=' + dnValue + ',' + dnBase;
108 LdapName dn;
109 try {
110 dn = new LdapName(dnStr);
111 } catch (InvalidNameException e) {
112 throw new IllegalArgumentException("Cannot interpret DN " + dnStr, e);
113 }
114 if (dnValue == null)
115 throw new IllegalArgumentException("DN key " + dnKey + " must have a value");
116 try (Writer writer = Files.newBufferedWriter(path, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) {
117 writer.append("\ndn: ");
118 writer.append(dn.toString());
119 writer.append('\n');
120 for (Enumeration<String> keys = props.keys(); keys.hasMoreElements();) {
121 String key = keys.nextElement();
122 Object value = props.get(key);
123 writer.append(key);
124 writer.append(": ");
125 // FIXME deal with binary and multiple values
126 writer.append(value.toString());
127 writer.append('\n');
128 }
129 }
130 }
131
132 static Dictionary<String, Object> loadFromProperties(Path path) throws IOException {
133 Properties toLoad = new Properties();
134 try (InputStream in = Files.newInputStream(path)) {
135 toLoad.load(in);
136 }
137 Dictionary<String, Object> res = new Hashtable<String, Object>();
138 for (Object key : toLoad.keySet())
139 res.put(key.toString(), toLoad.get(key));
140 return res;
141 }
142
143 /*
144 * EXCEPTIONS
145 */
146 /**
147 * Chain the messages of all causes (one per line, <b>starts with a line
148 * return</b>) without all the stack
149 */
150 public static String chainCausesMessages(Throwable t) {
151 StringBuffer buf = new StringBuffer();
152 chainCauseMessage(buf, t);
153 return buf.toString();
154 }
155
156 /** Recursive chaining of messages */
157 private static void chainCauseMessage(StringBuffer buf, Throwable t) {
158 buf.append('\n').append(' ').append(t.getClass().getCanonicalName()).append(": ").append(t.getMessage());
159 if (t.getCause() != null)
160 chainCauseMessage(buf, t.getCause());
161 }
162
163 /*
164 * TIME
165 */
166 /** Formats time elapsed since start. */
167 public static String since(ZonedDateTime start) {
168 ZonedDateTime now = ZonedDateTime.now();
169 return duration(start, now);
170 }
171
172 /** Formats a duration. */
173 public static String duration(Temporal start, Temporal end) {
174 long count = ChronoUnit.DAYS.between(start, end);
175 if (count != 0)
176 return count > 1 ? count + " days" : count + " day";
177 count = ChronoUnit.HOURS.between(start, end);
178 if (count != 0)
179 return count > 1 ? count + " hours" : count + " hours";
180 count = ChronoUnit.MINUTES.between(start, end);
181 if (count != 0)
182 return count > 1 ? count + " minutes" : count + " minute";
183 count = ChronoUnit.SECONDS.between(start, end);
184 return count > 1 ? count + " seconds" : count + " second";
185 }
186
187 /** Singleton constructor. */
188 private LangUtils() {
189
190 }
191
192 }