001: package org.cougaar.demo.mandelbrot.util;
002:
003: import java.io.Serializable;
004: import java.util.AbstractMap;
005: import java.util.Arrays;
006: import java.util.Iterator;
007: import java.util.LinkedHashMap;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.Set;
011: import java.util.regex.Matcher;
012: import java.util.regex.Pattern;
013:
014: /**
015: * A map of key=value pairs with helper methods.
016: * <p>
017: * TODO merge this back into "org.cougaar.util.Arguments", add support for<pre>
018: * public List getParameterValues(String key) {...}
019: * public Map getParameterMap() {...}
020: * </pre>
021: * as seen in "org.cougaar.core.qos.metrics.ParameterizedPlugin".
022: */
023: public final class Arguments extends AbstractMap implements
024: Serializable {
025:
026: // @see toString(String,String)
027: private static final Pattern PATTERN = Pattern
028: .compile("\\$(key|value|vals|vlist)");
029:
030: // a non-null, *modifiable* map of String keys to a mix of String and
031: // String[] values.
032: private final Map m;
033:
034: /** @see Arguments(Object,Set,Object) Same as Arguments(null, null, null) */
035: public Arguments() {
036: this (null, null, null);
037: }
038:
039: /** @see Arguments(Object,Set,Object) Same as Arguments(o, null, null) */
040: public Arguments(Object o) {
041: this (o, null, null);
042: }
043:
044: /** @see Arguments(Object,Set,Map) Same as Arguments(o, null, deflt) */
045: public Arguments(Object o, Object deflt) {
046: this (o, null, deflt);
047: }
048:
049: /**
050: * @param o the entry data. This can be either<br>
051: * a Map of Strings to Strings/String[]s,<br>
052: * a List of "name=value" Strings,<br>
053: * a String[] of "name=value" Strings,<br>
054: * or null
055: *
056: * @param keys an optional Set of Strings to act as filter on the keySet
057: *
058: * @param deflt the optional default values. The supported object
059: * types are the same as in the "o" parameter.
060: */
061: public Arguments(Object o, Set keys, Object deflt) {
062: Map m2 = toMap(o);
063: Map def = toMap(deflt);
064: this .m = parse(m2, keys, def);
065: }
066:
067: public String getString(String key) {
068: return getString(key, null);
069: }
070:
071: public String getString(String key, String deflt) {
072: Object o = m.get(key);
073: if (o == null) {
074: return deflt;
075: }
076: if (o instanceof String) {
077: return (String) o;
078: }
079: if (o instanceof String[]) {
080: String[] sa = (String[]) o;
081: if (sa.length <= 0)
082: return deflt;
083: return sa[0];
084: }
085: return deflt;
086: }
087:
088: public void setString(String key, String value) {
089: m.put(key, value);
090: }
091:
092: public void swap(String k1, String k2) {
093: Object v1 = m.get(k1);
094: Object v2 = m.get(k2);
095: if (v2 == null) {
096: if (v1 != null) {
097: m.remove(k1);
098: }
099: } else {
100: m.put(k1, v2);
101: }
102: if (v1 == null) {
103: if (v2 != null) {
104: m.remove(k2);
105: }
106: } else {
107: m.put(k2, v1);
108: }
109: }
110:
111: public boolean getBoolean(String key) {
112: return getBoolean(key, false);
113: }
114:
115: public boolean getBoolean(String key, boolean deflt) {
116: String value = getString(key);
117: return (value == null ? deflt : "true".equals(value));
118: }
119:
120: public void setBoolean(String key, boolean value) {
121: setString(key, Boolean.toString(value));
122: }
123:
124: public int getInt(String key) {
125: return getInt(key, -1);
126: }
127:
128: public int getInt(String key, int deflt) {
129: String value = getString(key);
130: if (value == null)
131: return deflt;
132: try {
133: return Integer.parseInt(value);
134: } catch (NumberFormatException nfe) {
135: return deflt;
136: }
137: }
138:
139: public void setInt(String key, int value) {
140: setString(key, Integer.toString(value));
141: }
142:
143: public long getLong(String key) {
144: return getLong(key, -1);
145: }
146:
147: public long getLong(String key, long deflt) {
148: String value = getString(key);
149: if (value == null)
150: return deflt;
151: try {
152: return Long.parseLong(value);
153: } catch (NumberFormatException nfe) {
154: return deflt;
155: }
156: }
157:
158: public void setLong(String key, long value) {
159: setString(key, Long.toString(value));
160: }
161:
162: public double getDouble(String key) {
163: return getDouble(key, -1.0);
164: }
165:
166: public double getDouble(String key, double deflt) {
167: String value = getString(key);
168: if (value == null)
169: return deflt;
170: try {
171: return Double.parseDouble(value);
172: } catch (NumberFormatException nfe) {
173: return deflt;
174: }
175: }
176:
177: public void setDouble(String key, double value) {
178: setString(key, Double.toString(value));
179: }
180:
181: /**
182: * @return a modifiable set of Map.Entry elements.
183: */
184: public Set entrySet() {
185: // RFE wrap to ensure that modifications are String->String/String[].
186: return m.entrySet();
187: }
188:
189: /**
190: * Create a string representation of this map using the given format.
191: * <pre>
192: * For example, if our map contains:
193: * A=B
194: * X=V0,V1,V2
195: * then:
196: * toString("the_$key is the_$value\n");
197: * would return:
198: * the_A is the_B
199: * the_X is the_V0
200: * </pre>
201: * The supported variables are:<ul>
202: * <li>"$key" is the string key name (e.g. "X")</li>
203: * <li>"$value" is the first value (e.g. "V0"), as defined in
204: * {@link #getString(String)}</li>
205: * <li>"$vals" is the first value if there is only one value (e.g. "B"),
206: * otherwise the list of values prefixed with "[" and "]" if there
207: * are multiple values (e.g. "[V0,V1,V2]").</li>
208: * <li>"$vlist" is the "[]" wrapped list (e.g. "[B]" or "[V0,V1,V2]")</li>
209: * </ul>
210: *
211: * @return a string with each entry in the given format, where every "$key"
212: * is replaced with the map key and every "$value" is replaced with the map
213: * value.
214: */
215: public String toString(String format) {
216: return toString(format, null);
217: }
218:
219: /**
220: * @param format optional format, defaults to "$key=$vals"
221: * @param separator optional separator, e.g. ", "
222: * @see #toString(String) similar string formatter
223: */
224: public String toString(String format, String separator) {
225: String f = format;
226: if (f == null) {
227: f = "$key=$vals";
228: }
229:
230: boolean firstTime = false;
231: StringBuffer buf = new StringBuffer();
232: for (Iterator iter = m.entrySet().iterator(); iter.hasNext();) {
233: Map.Entry me = (Map.Entry) iter.next();
234:
235: if (firstTime) {
236: if (separator != null) {
237: buf.append(separator);
238: }
239: } else {
240: firstTime = true;
241: }
242:
243: String k = (String) me.getKey();
244: Object o = me.getValue();
245: String v0;
246: String va;
247: int n;
248: if (o instanceof String) {
249: v0 = (String) o;
250: va = v0;
251: n = 1;
252: } else if (o instanceof String[]) {
253: String[] sa = (String[]) o;
254: n = sa.length;
255: if (n <= 0)
256: continue;
257: v0 = sa[0];
258: if (n == 1) {
259: va = v0;
260: } else {
261: StringBuffer x = new StringBuffer();
262: for (int i = 0; i < n; i++) {
263: if (i > 0)
264: x.append(",");
265: x.append(sa[i]);
266: }
267: va = x.toString();
268: }
269: } else {
270: continue;
271: }
272:
273: Matcher x = PATTERN.matcher(format);
274: while (x.find()) {
275: String tag = x.group(1);
276: String value = ("key".equals(tag) ? k : "value"
277: .equals(tag) ? v0
278: : "vals".equals(tag) ? (n == 1 ? v0
279: : ("[" + va + "]")) : "vlist"
280: .equals(tag) ? va : "InternalError!");
281: x.appendReplacement(buf, value);
282: }
283: x.appendTail(buf);
284: }
285: return buf.toString();
286: }
287:
288: public String toString() {
289: return "[" + toString("$key=$vals", ", ") + "]";
290: }
291:
292: //
293: // constructor helper methods:
294: //
295:
296: /**
297: * @return null or a non-empty, modifiable, ordered map
298: */
299: private static final Map toMap(Object object) {
300: Object o = object;
301: if (o == null) {
302: return null;
303: }
304: if (o instanceof Map) {
305: Map m2 = (Map) o;
306: if (m2.isEmpty()) {
307: return null;
308: }
309: // copy
310: Map m = new LinkedHashMap(m2);
311: // validate
312: for (Iterator iter = m.entrySet().iterator(); iter
313: .hasNext();) {
314: Map.Entry me = (Map.Entry) iter.next();
315: Object k = me.getKey();
316: if (!(k instanceof String)) {
317: throw new IllegalArgumentException(
318: "Expecting a Map with String keys, not "
319: + (k == null ? "null" : (k
320: .getClass().getName()
321: + " " + k)));
322: }
323: Object v = me.getValue();
324: if (v instanceof String)
325: continue;
326: if (v instanceof String[]) {
327: String[] sa = (String[]) v;
328: for (int i = 0; i < sa.length; i++) {
329: if (sa[i] != null)
330: continue;
331: throw new IllegalArgumentException(
332: "Map contains String[] value with null element for key "
333: + k);
334: }
335: continue;
336: }
337: throw new IllegalArgumentException(
338: "Expecting a Map with String or String[] values, not "
339: + (v == null ? "null" : (v.getClass()
340: .getName())
341: + " " + v));
342: }
343: return m;
344: }
345: if (o instanceof String[]) {
346: o = Arrays.asList((String[]) o);
347: }
348: if (!(o instanceof List)) {
349: throw new IllegalArgumentException(
350: "Expecting a Map, String[], or List, not "
351: + (o == null ? "null" : o.getClass()
352: .getName()));
353: }
354: List l = (List) o;
355: Map m = null;
356: for (int i = 0, n = l.size(); i < n; i++) {
357: Object oi = l.get(i);
358: if (!(oi instanceof String)) {
359: throw new IllegalArgumentException(
360: "Expecting a List of Strings, not "
361: + (oi == null ? "null" : (oi.getClass()
362: .getName()
363: + " " + oi)));
364: }
365: String s = (String) oi;
366: int sep = s.indexOf('=');
367: if (sep <= 0)
368: continue;
369: String key = s.substring(0, sep).trim();
370: String value = s.substring(sep + 1).trim();
371: if (key.length() <= 0)
372: continue;
373: if (m == null) {
374: m = new LinkedHashMap();
375: }
376: m.put(key, value);
377: }
378: return m;
379: }
380:
381: /**
382: * @param m a map created by "toMap()"
383: * @param deflt a map created by "toMap()"
384: * @return a non-null, modifiable, ordered map
385: */
386: private static final Map parse(Map m, Set keys, Map deflt) {
387: Map m2 = new LinkedHashMap();
388: if (m != null) {
389: if (keys == null) {
390: m2.putAll(m);
391: } else {
392: for (Iterator iter = keys.iterator(); iter.hasNext();) {
393: Object o = iter.next();
394: if (!(o instanceof String)) {
395: throw new IllegalArgumentException(
396: "Invalid keys set, expecting Strings, not "
397: + (o == null ? "null" : (o
398: .getClass().getName()
399: + " " + o)));
400: }
401: String key = (String) o;
402: if (!m.containsKey(key))
403: continue;
404: m2.put(key, m.get(key));
405: }
406: }
407: }
408: if (deflt != null) {
409: for (Iterator iter = deflt.entrySet().iterator(); iter
410: .hasNext();) {
411: Map.Entry me = (Map.Entry) iter.next();
412: String key = (String) me.getKey();
413: if (m2.containsKey(key))
414: continue;
415: if (keys != null && !keys.contains(key))
416: continue;
417: m2.put(key, me.getValue());
418: }
419: }
420: return m2;
421: }
422: }
|