PageRenderTime 70ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/tufts/Util.java

https://bitbucket.org/elloyd/cnpvue
Java | 2943 lines | 2035 code | 399 blank | 509 comment | 382 complexity | 2b4672dcddb0d4a661f9aa9b6c212404 MD5 | raw file
  1. /*
  2. * Copyright 2003-2010 Tufts University Licensed under the
  3. * Educational Community License, Version 2.0 (the "License"); you may
  4. * not use this file except in compliance with the License. You may
  5. * obtain a copy of the License at
  6. *
  7. * http://www.osedu.org/licenses/ECL-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing,
  10. * software distributed under the License is distributed on an "AS IS"
  11. * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  12. * or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. package tufts;
  16. import java.awt.Color;
  17. import java.awt.Shape;
  18. import java.awt.Transparency;
  19. import java.awt.geom.Point2D;
  20. import java.awt.geom.Rectangle2D;
  21. import java.awt.geom.CubicCurve2D;
  22. import java.awt.geom.QuadCurve2D;
  23. import java.awt.image.BufferedImage;
  24. import java.io.BufferedReader;
  25. import java.io.File;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.io.InputStreamReader;
  29. import java.io.PrintWriter;
  30. import java.io.StringWriter;
  31. import java.io.Writer;
  32. import java.lang.ref.Reference;
  33. import java.lang.ref.SoftReference;
  34. import java.net.InetAddress;
  35. import java.net.NetworkInterface;
  36. import java.net.URLEncoder;
  37. import java.text.BreakIterator;
  38. import java.util.AbstractList;
  39. import java.util.ArrayList;
  40. import java.util.Arrays;
  41. import java.util.Collection;
  42. import java.util.Enumeration;
  43. import java.util.HashMap;
  44. import java.util.Hashtable;
  45. import java.util.Iterator;
  46. import java.util.List;
  47. import java.util.Locale;
  48. import java.util.Map;
  49. import java.util.NoSuchElementException;
  50. import java.util.RandomAccess;
  51. import java.util.jar.JarEntry;
  52. import java.util.jar.JarFile;
  53. import javax.swing.JComponent;
  54. import javax.swing.JFrame;
  55. import javax.swing.JLabel;
  56. import javax.swing.JPanel;
  57. import javax.swing.border.LineBorder;
  58. import tufts.macosx.MacOSX;
  59. /**
  60. * Utility class. Provides code for determining what platform we're on,
  61. * platform-specific code for opening URL's, as well as various convenience
  62. * functions.
  63. *
  64. * @version $Revision: $ / $Date: $ / $Author: sfraize $
  65. */
  66. public class Util
  67. {
  68. private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(Util.class);
  69. private static boolean WindowsPlatform = false;
  70. private static boolean MacPlatform = false;
  71. private static boolean MacAquaLAF = false;
  72. private static boolean MacAquaLAF_set = false;
  73. private static boolean UnixPlatform = false;
  74. private static final String PlatformName;
  75. private static final String OSVersion;
  76. private static final boolean OSisMacLeopard;
  77. private static float javaVersion = 1.0f;
  78. private static int MacMRJVersion = -1;
  79. private static boolean DEBUG = false;
  80. private static String PlatformEncoding;
  81. private static boolean JVM_is_64_bit;
  82. static {
  83. if (!DEBUG)
  84. DEBUG = System.getProperty("tufts.Util.debug") != null;
  85. final String osName = System.getProperty("os.name");
  86. final String osArch = System.getProperty("os.arch");
  87. OSVersion = System.getProperty("os.version");
  88. final String javaSpec = System.getProperty("java.specification.version");
  89. final String bits = System.getProperty("sun.arch.data.model");
  90. if (bits.equals("64"))
  91. JVM_is_64_bit = true;
  92. else
  93. JVM_is_64_bit = false;
  94. PlatformName = osName + " " + OSVersion + " " + osArch;
  95. if (DEBUG) out(String.format("Platform: %s / %s / %s", osName, OSVersion, osArch));
  96. //if (DEBUG) out(String.format("Platform: %s / %s / %s; Leopard=%s", osName, OSVersion, osArch, OSisMacLeopard));
  97. try {
  98. javaVersion = Float.parseFloat(javaSpec);
  99. if (DEBUG) out("Java Version: " + javaVersion + "; JVM-bits=" + bits + "; 64bit=" + JVM_is_64_bit);
  100. } catch (Exception e) {
  101. errorOut("couldn't parse java.specifcaion.version: [" + javaSpec + "]");
  102. errorOut(e.toString());
  103. }
  104. final String osn = osName.toUpperCase();
  105. /*
  106. * fix for forums problem. one of the strangest bugs i've seen in a while.
  107. * something to keep in mind for future, calling toUpperCase() in a
  108. * locale that uses diacritics will add diacritics to a string that
  109. * did not originally contain them. so, "windows vista" gets
  110. * diacritics on the i in both words, the fix is so put the match
  111. * we're looking for as the lower case word mac and winodws, and call
  112. * toUpperCase on them so both sides of the comparison are always being
  113. * processed the same way. note that if you call to upper on a string
  114. * that is already upper case it does not place in the diacritic characters.
  115. */
  116. if (osn.startsWith("mac".toUpperCase())) {
  117. MacPlatform = true;
  118. OSisMacLeopard =
  119. OSVersion.startsWith("10.5") || // Leopard
  120. OSVersion.startsWith("10.6"); // Snow Leopard
  121. if (DEBUG) out(String.format("Mac: Leopard/Snow-Leopard=%s", OSisMacLeopard));
  122. String mrj = System.getProperty("mrj.version");
  123. int i = 0;
  124. while (i < mrj.length()) {
  125. if (!Character.isDigit(mrj.charAt(i)))
  126. break;
  127. i++;
  128. }
  129. try {
  130. MacMRJVersion = Integer.parseInt(mrj.substring(0, i));
  131. } catch (NumberFormatException e) {
  132. errorOut("couldn't parse mrj.version: " + e);
  133. errorOut(e.toString());
  134. }
  135. if (DEBUG) out("Mac mrj.version: \"" + mrj + "\" = " + MacMRJVersion);
  136. } else if (osn.indexOf("windows".toUpperCase()) >= 0) {
  137. WindowsPlatform = true;
  138. OSisMacLeopard = false;
  139. //if (DEBUG) out("Windows Platform: " + PlatformName);
  140. } else {
  141. UnixPlatform = true;
  142. OSisMacLeopard = false;
  143. }
  144. if (DEBUG) out(String.format("OSFlags: isWin=%b; isMac=%b(leopard=%b); isUnix=%b;", WindowsPlatform, MacPlatform, OSisMacLeopard, UnixPlatform));
  145. String term = System.getenv("TERM");
  146. boolean allowColor = false;
  147. if (term == null)
  148. term = "";
  149. allowColor = term.indexOf("color") >= 0;
  150. if (!allowColor) {
  151. term = System.getenv("SSH_TERM");
  152. if (term != null && term.indexOf("color") >= 0)
  153. allowColor = true;
  154. }
  155. if (allowColor) {
  156. TERM_RED = "\033[1;31m";
  157. TERM_GREEN = "\033[1;32m";
  158. TERM_YELLOW = "\033[1;33m";
  159. TERM_BLUE = "\033[1;34m";
  160. TERM_PURPLE = "\033[1;35m";
  161. TERM_CYAN = "\033[1;36m";
  162. TERM_CLEAR = "\033[m";
  163. } else {
  164. TERM_RED = TERM_GREEN = TERM_YELLOW = TERM_BLUE = TERM_PURPLE = TERM_CYAN = TERM_CLEAR = "";
  165. }
  166. //printStackTrace("TERM[" + term + "]");
  167. }
  168. /** Common escape codes for terminal text colors. Set to empty string unless on a color terminal */
  169. public static final String TERM_RED, TERM_GREEN, TERM_YELLOW, TERM_BLUE, TERM_PURPLE, TERM_CYAN, TERM_CLEAR;
  170. private static void out(String s) {
  171. if (Log.isDebugEnabled())
  172. Log.debug(s);
  173. else
  174. System.out.println("tufts.Util: " + s);
  175. }
  176. private static void errorOut(String s) {
  177. System.err.println("tufts.Util: " + s);
  178. Log.error(s);
  179. }
  180. public static String formatLines(String target, int maxLength)
  181. {
  182. Locale currentLocale = new Locale ("en","US");
  183. return formatLines(target,maxLength,currentLocale);
  184. }
  185. public static String formatLines(String target, int maxLength,
  186. Locale locale)
  187. {
  188. if (target == null) {
  189. Log.warn("attempt to line-break null string");
  190. return null;
  191. }
  192. try {
  193. target = breakLines(target, maxLength, locale);
  194. } catch (Throwable t) {
  195. Log.error("failed to line-break [" + target + "]; ", t);
  196. }
  197. return target;
  198. }
  199. public static String maxDisplay(final String s, int len) {
  200. if (s == null)
  201. return null;
  202. if (len < 4)
  203. len = 4;
  204. if (s.length() > len) {
  205. return s.substring(0,len-3) + "...";
  206. } else {
  207. return s;
  208. }
  209. }
  210. private static String breakLines(final String target, int maxLength, Locale currentLocale)
  211. {
  212. final StringBuilder s = new StringBuilder(target.length() + 4);
  213. final BreakIterator boundary = BreakIterator.getLineInstance(currentLocale);
  214. boundary.setText(target);
  215. int start = boundary.first();
  216. int end = boundary.next();
  217. int lineLength = 0;
  218. boolean didBreak = false;
  219. while (end != BreakIterator.DONE) {
  220. final String word = target.substring(start,end);
  221. lineLength += word.length();
  222. // Log.debug(String.format("len: %2d, word %s%s",
  223. // lineLength,
  224. // tags(word),
  225. // atExistingNewline ? ", @newline" : ""));
  226. if (lineLength >= maxLength) {
  227. final boolean atExistingNewline =
  228. s.length() > 1 && s.charAt(s.length() - 1) == '\n';
  229. if (!atExistingNewline) {
  230. //Log.debug("adding newline");
  231. s.append('\n');
  232. didBreak = true;
  233. }
  234. lineLength = word.length();
  235. }
  236. //Log.debug("adding word " + tags(word));
  237. s.append(word);
  238. start = end;
  239. end = boundary.next();
  240. }
  241. return didBreak ? s.toString() : target;
  242. }
  243. /*
  244. * Be sure to compare this value to a constant *float*
  245. * value -- e.g. "1.4f" -- just "1.4" as double value may
  246. * actually appear to be less than 1.4, as that can't
  247. * be exactly represented by a double.
  248. */
  249. public static float getJavaVersion() {
  250. return javaVersion;
  251. }
  252. /** return mac runtime for java version. Will return -1 if we're not running on mac platform. */
  253. public static int getMacMRJVersion() {
  254. return MacMRJVersion;
  255. }
  256. public static String getPlatformName() {
  257. return PlatformName == null ? (System.getProperty("os.name") + "?") : PlatformName;
  258. }
  259. public static String getOSVersion() {
  260. return OSVersion;
  261. }
  262. public static boolean isMacLeopard() {
  263. return OSisMacLeopard;
  264. }
  265. public static boolean isMacTiger() {
  266. return MacPlatform && !OSisMacLeopard;
  267. }
  268. /** @return true if we're running on a version Microsoft Windows */
  269. public static boolean isWindowsPlatform() {
  270. return WindowsPlatform;
  271. }
  272. /** @return true if we're running on an Apple Mac OS */
  273. public static boolean isMacPlatform() {
  274. return MacPlatform;
  275. }
  276. /** @return true if we're running on unix only platform (e.g., Linux -- Mac OS X not included) */
  277. public static boolean isUnixPlatform(){
  278. return UnixPlatform;
  279. }
  280. /**
  281. * @return true of Mac Cocoa extensions are supported.
  282. * Currently only true if running in a 32bit Java 1.5 VM.
  283. */
  284. public static boolean isMacCocoaSupported()
  285. {
  286. return isMacPlatform() && !JVM_is_64_bit && javaVersion < 1.6;
  287. }
  288. public static String getDefaultPlatformEncoding() {
  289. if (PlatformEncoding == null)
  290. PlatformEncoding = (new java.io.OutputStreamWriter(new java.io.ByteArrayOutputStream())).getEncoding();
  291. return PlatformEncoding;
  292. }
  293. /** @return true if the current Look & Feel is Mac Aqua (not always true just because you're on a mac)
  294. * Note: do NOT call this from any static initializers the result may be changed by application startup
  295. * code. */
  296. public static boolean isMacAquaLookAndFeel()
  297. {
  298. // we can't set this at static init time because the LAF can be set after that
  299. if (MacAquaLAF_set == false) {
  300. MacAquaLAF =
  301. isMacPlatform() &&
  302. javax.swing.UIManager.getLookAndFeel().getName().toLowerCase().indexOf("aqua") >= 0;
  303. MacAquaLAF_set = true;
  304. }
  305. return MacAquaLAF;
  306. }
  307. /** @param url -- a url assumed to be in the platform default format (e.g., it may be
  308. * formatted in a way only understood on the current platform).
  309. */
  310. public static void openURL(String url)
  311. throws java.io.IOException
  312. {
  313. // TODO: isLocalFile should check for inital '\' also (File.separator) -- but follow-on code will now need re-testing
  314. boolean isLocalFile = (url.length() >= 5 && "file:".equalsIgnoreCase(url.substring(0,5))) || url.startsWith("/");
  315. boolean isMailTo = url.length() >= 7 && "mailto:".equalsIgnoreCase(url.substring(0,7));
  316. if (DEBUG) System.err.println("openURL_PLAT [" + url + "] isLocalFile=" + isLocalFile + " isMailTo=" + isMailTo);
  317. if (isMacPlatform())
  318. openURL_Mac(url, isLocalFile, isMailTo);
  319. else if (isUnixPlatform())
  320. openURL_Unix(url, isLocalFile, isMailTo);
  321. else // default is a windows platform
  322. openURL_Windows(url, isLocalFile, isMailTo);
  323. }
  324. private static final String PC_OPENURL_CMD = "rundll32 url.dll,FileProtocolHandler";
  325. private static void openURL_Windows(String url, boolean isLocalFile, boolean isMailTo)
  326. throws java.io.IOException
  327. {
  328. System.err.println("openURL_Win [" + url + "]");
  329. // On at least Windows 2000, %20's don't work when given to url.dll FileProtocolHandler
  330. // (Should be using some kind of URLProtocolHanlder ?)
  331. // Also at least Win2K: file:///C:/foo/bar.html works, but start that with file:/ or file://
  332. // and it DOES NOT work -- you MUST have the three slashes, OR, you can have NO SLASHES,
  333. // and it will work... (file:C:/foo/bar.html)
  334. // ALSO, file:// or // file:/// works BY ITSELF (file:/ by itself still doesn't work).
  335. //url = url.replaceAll("%20", " ");
  336. if (!isMailTo) {
  337. url = decodeURL(url);
  338. url = decodeURL(url); // run twice in case any %2520 double encoded spaces
  339. }
  340. if (isLocalFile) {
  341. // below works, but we're doing a full conversion to windows path names now
  342. //url = url.replaceFirst("^file:/+", "file:");
  343. url = url.replaceFirst("^file:/+", "");
  344. url = url.replace('/', '\\');
  345. System.err.println("openURL_patch[" + url + "]");
  346. char c1 = 0;
  347. try { c1 = url.charAt(1); } catch (StringIndexOutOfBoundsException e) {}
  348. if (c1 == ':' || c1 == '|') {
  349. // Windows drive letter specification, e.g., "C:".
  350. // Also, I've seen D|/dir/file.txt in a shortcut file, so we allow that too.
  351. // In any case, we do noting: this string should be workable to url.dll
  352. } else {
  353. if (url.startsWith("file:")) {
  354. // DO NOTHING.
  355. // If we had "file:" above and NOT "file:/", we need this check here.
  356. // This suggests this code needs refactoring. SMF 2008-04-02
  357. } else {
  358. // if this does NOT start with a drive specification, assume
  359. // the first component is a host for a windows network
  360. // drive, and thus we have to pre-pend \\ to it, to get \\host\file
  361. url = "\\\\" + url;
  362. }
  363. }
  364. // at this point, "url" is really just a local windows file
  365. // in full windows syntax (backslashes, drive specs, etc)
  366. System.err.println("openURL_WinLF[" + url + "]");
  367. }
  368. String cmd = PC_OPENURL_CMD + " " + url;
  369. final int sizeURL = url.length();
  370. final int sizeCommand = cmd.length();
  371. final int sizeWinArgs = sizeCommand - 17; // subtract "rundll32 url.dll,"
  372. boolean debug = DEBUG;
  373. if (sizeURL > 2027 || sizeCommand > 2064 || sizeWinArgs >= 2048) {
  374. System.err.println("\nWarning: WinXP buffer lengths likely exceeded: command not likely to run (arglen=" + sizeWinArgs + ")");
  375. debug = true;
  376. } else {
  377. System.err.println();
  378. }
  379. if (debug) {
  380. System.err.println("exec url length: " + sizeURL);
  381. System.err.println("exec command length: " + sizeCommand);
  382. System.err.println("exec url.dll args len: " + sizeWinArgs);
  383. }
  384. if (sizeCommand > 2064) {
  385. System.err.println("exec: truncating command and hoping for the best...");
  386. cmd = cmd.substring(0,2063);
  387. }
  388. System.err.println("exec[" + cmd + "]");
  389. Runtime.getRuntime().exec(cmd);
  390. // final String mailto = "mailto:"
  391. // + "foo@bar.com?"
  392. // + "subject=TestSubject"
  393. // + "&attachment="
  394. // //+ "&Attach="
  395. // + "\""
  396. // + "c:\\\\foo.txt"
  397. // + "\""
  398. // ;
  399. // System.err.println("MAILTO: ["+mailto+"]");
  400. // Runtime.getRuntime().exec(new String[] {"rundll32", "url.dll,FileProtocolHandler", mailto
  401. // "mailto:"
  402. // + "&subject=TestSubject"
  403. // + "&attachment=" + "\"" + "c:\\\\foo.txt" + "\""
  404. // },
  405. // null);
  406. // if (false) {
  407. // Process p = Runtime.getRuntime().exec(cmd);
  408. // try {
  409. // System.err.println("waiting...");
  410. // p.waitFor();
  411. // } catch (Exception ex) {
  412. // System.err.println(ex);
  413. // }
  414. // System.err.println("exit value=" + p.exitValue());
  415. // }
  416. }
  417. /**
  418. * Call a named static method with the given args.
  419. * The method signature is inferred from the argument types. We map the primitive
  420. * type wrapper class to their primitive types (an auto un-boxing), so this
  421. * won't work for method calls that take args of Boolean, Integer, etc,
  422. * only boolean, int, etc.
  423. */
  424. public static Object execute(Object object, String className, String methodName, Object[] args)
  425. throws ClassNotFoundException,
  426. NoSuchMethodException,
  427. IllegalArgumentException,
  428. IllegalAccessException,
  429. java.lang.reflect.InvocationTargetException
  430. {
  431. if (DEBUG) {
  432. // use multiple prints in remote case of a class-load or some such error along the way
  433. System.err.println("Util.execute:");
  434. System.err.println("\t className: [" + className + "]");
  435. System.err.println("\tmethodName: [" + methodName + "]");
  436. String desc;
  437. if (args == null)
  438. desc = "null";
  439. else if (args.length == 0)
  440. desc = "(none)";
  441. else if (args.length == 1)
  442. desc = objectTag(args[0]) + " [" + args[0] + "]";
  443. else
  444. desc = Arrays.asList(args).toString();
  445. System.err.println("\t args: " + desc);
  446. System.err.println("\t object: " + objectTag(object) + " [" + object + "]");
  447. }
  448. final Class clazz = Class.forName(className);
  449. final Class[] argTypes;
  450. if (args == null) {
  451. argTypes = null;
  452. } else {
  453. argTypes = new Class[args.length];
  454. for (int i = 0; i < args.length; i++) {
  455. final Class argClass = args[i].getClass();
  456. if (argClass == Boolean.class) argTypes[i] = Boolean.TYPE;
  457. else if (argClass == Integer.class) argTypes[i] = Integer.TYPE;
  458. else if (argClass == Long.class) argTypes[i] = Long.TYPE;
  459. else if (argClass == Short.class) argTypes[i] = Short.TYPE;
  460. else if (argClass == Float.class) argTypes[i] = Float.TYPE;
  461. else if (argClass == Double.class) argTypes[i] = Double.TYPE;
  462. else if (argClass == Byte.class) argTypes[i] = Byte.TYPE;
  463. else if (argClass == Character.class) argTypes[i] = Character.TYPE;
  464. else
  465. argTypes[i] = args[i].getClass();
  466. }
  467. }
  468. java.lang.reflect.Method method = clazz.getMethod(methodName, argTypes);
  469. if (DEBUG) System.err.print("\t invoking: " + method + " ... ");
  470. Object result = method.invoke(object, args);
  471. if (DEBUG) System.err.println("returned.");
  472. if (DEBUG && method.getReturnType() != void.class) {
  473. // use multiple prints in remote case of a class-load or some such error along the way
  474. //System.err.println("Util.execute:");
  475. System.err.println("\t return: " + objectTag(result) + " [" + result + "]");
  476. }
  477. //System.out.println("Sucessfully invoked " + className + "." + methodName + ", result=" + result);
  478. return result;
  479. }
  480. public static Object execute(String className, String methodName, Object[] args)
  481. throws ClassNotFoundException,
  482. NoSuchMethodException,
  483. IllegalArgumentException,
  484. IllegalAccessException,
  485. java.lang.reflect.InvocationTargetException
  486. {
  487. return execute(null, className, methodName, args);
  488. }
  489. /** Attempt a method call. If it fails, quietly fail, printing a stack trace and returning null.
  490. * @param object - cannot be null (implying a static method), as is also used to get the class name
  491. * If object is a Class object, make this a static invocation in that class.
  492. */
  493. public static Object invoke(Object object, String methodName, Object[] args)
  494. {
  495. String className;
  496. if (object instanceof Class) {
  497. className = ((Class)object).getName();
  498. object = null;
  499. } else
  500. className = object.getClass().getName();
  501. try {
  502. return execute(object, className, methodName, args);
  503. } catch (Exception e) {
  504. e.printStackTrace();
  505. return e;
  506. }
  507. }
  508. /**
  509. * Attempt a method call. If it fails, quietly fail, printing a stack trace and returning null.
  510. * This is a convenience version that allows the passing in of a single argument directly.
  511. **/
  512. public static Object invoke(Object object, String methodName, Object arg0) {
  513. return invoke(object, methodName, new Object[] { arg0 });
  514. }
  515. public static Object invoke(Object object, String methodName) {
  516. return invoke(object, methodName, null);
  517. }
  518. /**
  519. * Attempt to invoke the given method with the given args. If
  520. * any exception occurs, (e.g., ClassNotFoundException because a
  521. * particular library isn't present) we quietly catch it and
  522. * pass it back as the return value;
  523. */
  524. public static Object executeIfFound(String className, String methodName, Object[] args) {
  525. try {
  526. return execute(className, methodName, args);
  527. } catch (Exception e) {
  528. return e;
  529. }
  530. }
  531. /** Encode a query pair URL such that it will work with the current platform openURL code.
  532. * E.g., construct a mailto: whose subject/body args are encoded such that they successfully
  533. * pass through to the local mail client.
  534. */
  535. public static String makeQueryURL(String urlStart, String ... nameValuePairs) {
  536. StringBuffer url = new StringBuffer(urlStart);
  537. boolean isKey = true;
  538. boolean isFirstKey = true;
  539. String curKey = "<no-key!>";
  540. for (String s : nameValuePairs) {
  541. //System.out.format("TOKEN[%s]\n", s);
  542. if (isKey) {
  543. if (isFirstKey) {
  544. url.append('?');
  545. isFirstKey = false;
  546. } else
  547. url.append('&');
  548. curKey = s;
  549. System.out.format("KEY[%s]\n", s);
  550. url.append(s);
  551. url.append('=');
  552. } else if ("attachment".equals(curKey)) {
  553. // append windows pathname raw:
  554. // An "attachment" arg has been rumoured to work on Windows,
  555. // but as far as I can tell, these rumours are total BS.
  556. // Have yet to see this work in any configuration.
  557. url.append('"' + s + '"');
  558. } else {
  559. // value field:
  560. final String encodedValue = encodeURLData(s);
  561. if (DEBUG) {
  562. System.out.format(" %-17s [%s]\n", curKey + "(RAW):", s);
  563. System.out.format(" %-17s [%s]\n", curKey + "(ENCODED):", encodedValue);
  564. }
  565. url.append(encodedValue);
  566. }
  567. isKey = !isKey;
  568. }
  569. //if (DEBUG) System.out.println("QUERY URL: " + url);
  570. return url.toString();
  571. }
  572. public static String encodeURLData(String url) {
  573. try {
  574. url = URLEncoder.encode(url, "UTF-8");
  575. url = url.replaceAll("\\+", "%20"); // Mail clients don't understand '+' as space
  576. } catch (Throwable t) {
  577. // should never happen:
  578. printStackTrace(t);
  579. }
  580. return url;
  581. }
  582. // GAK! Move this code to URLResource, as it's going to have to be smart
  583. // about local file drops for mac URL's, to be sure to UTF-8 DECODE them
  584. // first, so we get RID of special characters or spaces, which come
  585. // when the local file was dragged Safari, as opposed to the Finder
  586. // (e.g., Desktop), which already decodes them for us.
  587. // Also, we need to generically handle the decoding of ":" into "/"
  588. // for these URL's. (God forbid there is HTML in the name: e.g. <i>foo</i>
  589. // will send us a ':' in place of the '/', which we also don't
  590. // want to mistake for a protocol below. Actually, do fix the ':'
  591. // in the display name (title), but not raw meta-data: could be confusing.
  592. private static java.lang.reflect.Method macOpenURL_Method = null;
  593. private static void openURL_Mac(String url, boolean isLocalFile, boolean isMailTo)
  594. {
  595. //if (DEBUG) System.err.println("openURL_Mac0 [" + url + "]");
  596. System.err.println("openURL_Mac0 [" + url + "], isLocal=" + isLocalFile);
  597. if (isLocalFile) {
  598. boolean changed = true;
  599. if (url.startsWith("file:////")) {
  600. // don't think we have to do this, but just in case
  601. // (was getting a complaint and couldn't tell if this was why or not,
  602. // so now we won't see it)
  603. url = "file:///" + url.substring(9);
  604. } else if (url.startsWith("/")) {
  605. // must have file: at head to be sure it works on mac
  606. url = "file:" + url;
  607. } else
  608. changed = false;
  609. if (DEBUG && changed) System.err.println("openURL_Mac1 [" + url + "]");
  610. }
  611. if (isMailTo) {
  612. // final String flatURL = url.toLowerCase();
  613. // final int queryIndex = flatURL.indexOf('?') + 1;
  614. // if (queryIndex > 1) {
  615. // final String query = flatURL.substring(queryIndex);
  616. // if (DEBUG) System.out.println("QUERY: [" + query + "]");
  617. // final int subjectIndex = query.indexOf("subject=");
  618. // }
  619. //url = url.replaceAll(" ", "%20");
  620. // try {
  621. // url = URLEncoder.encode(url, "UTF-8");
  622. // } catch (Throwable t) {
  623. // printStackTrace(t);
  624. // }
  625. } else {
  626. try {
  627. url = encodeSpecialChars_Mac(url, isMailTo);
  628. } catch (Throwable t) {
  629. printStackTrace(t);
  630. }
  631. }
  632. // In Mac OS X, local files MUST have %20 and NO spaces in the URL's -- reverse of Windows.
  633. // But enforcing this for regular HTTP URL's breaks them: turns existing %20's into %2520's
  634. // If no protocol in the URL string, assume it's a pathname. Normally, there
  635. // would be nothing to do as openURL handles that fine on MacOSX, unless it's
  636. // not absolute, it which case we make it absolute by assuming the users home
  637. // directory.
  638. if (!isMailTo && url.indexOf(':') < 0 && !url.startsWith("/")) {
  639. // Hack to make relative references relative to user home directory. OSX
  640. // won't default to use current directory for a relative references, so
  641. // we're prepending the home directory manually as a bail out try-for-it.
  642. url = "file://" + System.getProperty("user.home") + "/" + url;
  643. if (DEBUG) System.err.println(" OUM HOME [" + url + "]");
  644. }
  645. execMacOpenURL(url);
  646. }
  647. // WHAT WE KNOW WORKS FOR MAILTO: '@' encoded, but ? / & decoded, except WITHIN
  648. // the value of &field=value, which of course messes it up.
  649. // Also in the working state: All spaces as %20, newlines %0A
  650. // If we take out the colons tho, we're screwed.
  651. private static String encodeSpecialChars_Mac(String url, boolean isMailTo)
  652. throws java.io.IOException
  653. {
  654. // if (url.indexOf('%') >= 0) {
  655. // // If we were to make sure we're always handed URI's (at
  656. // // least on the mac) this would prevent accidentally
  657. // // decoding actual '+' characters in the file-name,
  658. // // as they strings would already come with %20 for spaces.
  659. // // However, if there was a special (e.g. Unicode) character
  660. // // anywhere in the string, we would still need to encode it,
  661. // // but then we'd have to determine if the '+' we see at this
  662. // // point is from the URLEncoder, or from the real File name.
  663. // // Eventually, this Util code should take a real File object
  664. // // so we can be more sure about what we're doing in these
  665. // // corner cases.
  666. // if (DEBUG) System.err.println(" NO-CLEANUP [" + url + "]");
  667. // return url;
  668. // }
  669. // In case there are any special characters (e.g., Unicode chars) in the
  670. // file name, we must first encode them for MacOSX (local files only?)
  671. // FYI, MacOSX openURL uses UTF-8, NOT the native MacRoman encoding.
  672. // URLEncoder encodes EVERYTHING other than alphas tho, so we need
  673. // to put it back.
  674. // Note: using the less intense encoding of URI's may make this simpler
  675. if (url.indexOf('%') >= 0) {
  676. // DECODE it, in case there are already any encodings,
  677. // we don't want to double-encode.
  678. url = java.net.URLDecoder.decode(url, "UTF-8");
  679. if (DEBUG) System.err.println(" DECODE UTF [" + url + "]");
  680. }
  681. url = java.net.URLEncoder.encode(url, "UTF-8"); // URLEncoder is way overzealous...
  682. if (DEBUG) System.err.println(" ENCODE UTF [" + url + "]");
  683. // now decode the over-coded stuff -- these are all crucial characters
  684. // that must be present...
  685. url = url.replaceAll("%3A", ":");
  686. url = url.replaceAll("%2F", "/");
  687. url = url.replaceAll("%3F", "?");
  688. url = url.replaceAll("%3D", "=");
  689. url = url.replaceAll("%26", "&");
  690. // Mac doesn't undestand '+' means ' ' in it's openURL support method:
  691. // url = url.replace('+', ' '); // nor does it understand actual spaces
  692. url = url.replaceAll("\\+", "%20");
  693. if (DEBUG) System.err.println(" CLEANUP [" + url + "]");
  694. return url;
  695. }
  696. private static void execMacOpenURL(String url)
  697. {
  698. if (isMacLeopard()) {
  699. final String cmd = "/usr/bin/open";
  700. try {
  701. if (DEBUG) System.err.println(" Leopard: " + cmd + " " + url);
  702. Runtime.getRuntime().exec(new String[]{ cmd, url });
  703. } catch (Throwable t) {
  704. printStackTrace(t, cmd + " " + url);
  705. }
  706. } else if (getJavaVersion() >= 1.4f) {
  707. // Can't call this directly because wont compile on the PC
  708. //com.apple.eio.FileManager.openURL(url);
  709. if (macOpenURL_Method == null) {
  710. try {
  711. Class macFileManager = Class.forName("com.apple.eio.FileManager");
  712. //Class macFileManager = ClassLoader.getSystemClassLoader().loadClass("com.apple.eio.FileManager");
  713. macOpenURL_Method = macFileManager.getMethod("openURL", new Class[] { String.class });
  714. } catch (Exception e) {
  715. System.err.println("Failed to find Mac FileManager or openURL method: will not be able to display URL content.");
  716. e.printStackTrace();
  717. throw new UnsupportedOperationException("com.apple.eio.FileManager:openURL " + e);
  718. }
  719. }
  720. if (macOpenURL_Method != null) {
  721. try {
  722. macOpenURL_Method.invoke(null, new Object[] { url });
  723. } catch (Exception e) {
  724. e.printStackTrace();
  725. throw new UnsupportedOperationException("com.apple.eio.FileManager.openURL " + e);
  726. }
  727. } else
  728. throw new UnsupportedOperationException("openURL_Mac");
  729. } else {
  730. throw new UnsupportedOperationException("mac java <= 1.3 openURL unimplemented");
  731. // put this back if want to suppor mac java 1.3
  732. // this has been deprecated in mac java 1.4, so
  733. // just ignore the warning if using a 1.4 or beyond
  734. // compiler
  735. // com.apple.mrj.MRJFileUtils.openURL(url);
  736. }
  737. if (DEBUG) System.err.println("execMacOpenURL returns for (" + url + ")");
  738. }
  739. private static boolean HasGnomeOpen = false;
  740. private static boolean GnomeOpenSet = false;
  741. private static void openURL_Unix(String url, boolean isLocalFile, boolean isMailTo)
  742. throws java.io.IOException
  743. {
  744. // For now we just assume Netscape is installed.
  745. // todo: run down list of netscape, mozilla, konqueror (KDE
  746. // browser), gnome version? KDE/Gnome may have their own
  747. // services for getting a default browser.
  748. /*
  749. The problem I had with my 2 linux installations was that even though netscape wasn't
  750. installed the distribution provided a symlink named netscape which pointed to firefox
  751. however firefox couldn't interpet the netscape parameters. So below I've modified it
  752. to try to load firefox first and then if that fails load netscape, i suppose konqueror
  753. should be in the mix too maybe but this is better than it was and catches alot of cases.
  754. */
  755. final Runtime runtime = Runtime.getRuntime();
  756. Process process = null;
  757. int waitFor = -1;
  758. if (!GnomeOpenSet) {
  759. // test for gnome
  760. try {
  761. process = runtime.exec("gnome-open");
  762. waitFor = process.waitFor();
  763. }
  764. catch (InterruptedException e) {
  765. e.printStackTrace();
  766. }
  767. catch (IOException ioe2) {
  768. ioe2.printStackTrace();
  769. waitFor = 2;
  770. }
  771. GnomeOpenSet = true;
  772. if (waitFor != 2)
  773. HasGnomeOpen = true;
  774. }
  775. if (HasGnomeOpen) {
  776. //open file with gnome
  777. if (isLocalFile) {
  778. url = decodeURL(url);
  779. // SMF 2008-04-30: commented this out: was ensuring that most
  780. // local file links would not work -- not sure what cases
  781. // this was handling.
  782. //
  783. //url = "file:///" + url.substring(6);
  784. // old:
  785. ////jjurl = url.replaceAll(" ","\\ ");
  786. ////url ="\""+url+"\"";
  787. }
  788. Log.info("gnome-open " + url);
  789. process = runtime.exec(new String[] {"gnome-open" , url});
  790. // out("process: " + process);
  791. InputStream stdin = process.getErrorStream();
  792. InputStreamReader isr = new InputStreamReader(stdin);
  793. BufferedReader br = new BufferedReader(isr);
  794. String line = null;
  795. System.out.println("<OUTPUT>");
  796. while ((line = br.readLine()) != null)
  797. System.out.println(line);
  798. System.out.println("<OUTPUT>");
  799. try
  800. {
  801. int exitVal = process.waitFor();
  802. System.out.println("exit val : " + exitVal);
  803. }
  804. catch(InterruptedException inte)
  805. {
  806. inte.printStackTrace();
  807. }
  808. return;
  809. }
  810. else
  811. waitFor=-1;
  812. // kde
  813. try
  814. {
  815. System.out.println("TESTING KDE");
  816. process =runtime.exec("kfmexec");
  817. waitFor = process.waitFor();
  818. } catch (InterruptedException e)
  819. {
  820. e.printStackTrace();
  821. }
  822. catch (IOException ioe2)
  823. {
  824. ioe2.printStackTrace();
  825. waitFor=2;
  826. }
  827. if (waitFor != 2)
  828. {
  829. if (isLocalFile)
  830. {
  831. url = decodeURL(url);
  832. //jjurl = url.replaceAll(" ","\\ ");
  833. url = "file:///" + url.substring(6);
  834. //url ="\""+url+"\"";
  835. System.out.println(url);
  836. }
  837. //open file with kde
  838. process = runtime.exec(new String[] { "kfmclient","exec", url});
  839. InputStream stdin = process.getErrorStream();
  840. InputStreamReader isr = new InputStreamReader(stdin);
  841. BufferedReader br = new BufferedReader(isr);
  842. String line = null;
  843. System.out.println("<OUTPUT>");
  844. while ((line = br.readLine()) != null)
  845. System.out.println(line);
  846. System.out.println("<OUTPUT>");
  847. System.out.println("<OUTPUT2>");
  848. stdin=process.getInputStream();
  849. isr = new InputStreamReader(stdin);
  850. br = new BufferedReader(isr);
  851. line = null;
  852. while ((line = br.readLine()) != null)
  853. System.out.println(line);
  854. System.out.println("<OUTPUT2>");
  855. try
  856. {
  857. int exitVal = process.waitFor();
  858. System.out.println("exit val : " + exitVal);
  859. }
  860. catch(InterruptedException inte)
  861. {
  862. inte.printStackTrace();
  863. }
  864. return;
  865. }
  866. //if (waitFor == 2)
  867. try
  868. {
  869. process = runtime.exec(new String[] { "firefox", url});
  870. waitFor = process.waitFor();
  871. System.out.println("WAIT FOR : " + waitFor);
  872. }
  873. catch (java.io.IOException ioe3)
  874. {
  875. //firefox not available try netscape instead.
  876. process = Runtime.getRuntime().exec(new String[] { "netscape",
  877. "-remove",
  878. "'openURL('" + url + "')" });
  879. } catch (InterruptedException e) {
  880. // TODO Auto-generated catch block
  881. e.printStackTrace();
  882. }
  883. out("process: " + process);
  884. }
  885. /**
  886. * Execute the given system command (arg0 is command, subsequent args are command arguments).
  887. * @param runDirectory -- if non-null, the directory to run the command in.
  888. *
  889. * The current impl will only return up to the first 256 chars of output, and will
  890. * use String.trim on it, to remove any trailing newline.
  891. *
  892. * @see java.lang.Runtime
  893. */
  894. public static String getSystemCommandOutput(String[] args, String runDirectory)
  895. {
  896. String output = null;
  897. try {
  898. File dir = null;
  899. if (runDirectory != null) {
  900. try {
  901. dir = new File(runDirectory);
  902. } catch (Throwable t) {
  903. printStackTrace(t, "Warning: couldn't create file from: " + runDirectory);
  904. }
  905. }
  906. Log.info("exec " + args[0] + ": " + Arrays.asList(args) + " in dir " + dir + " (" + runDirectory + ")");
  907. final Process proc = Runtime.getRuntime().exec(args, null, dir);
  908. final java.io.InputStream stream = proc.getInputStream();
  909. final byte[] buf = new byte[256];
  910. final int got = stream.read(buf);
  911. output = new String(buf, 0, got).trim();
  912. Log.debug("exec " + args[0] + ": got output[" + output + "]");
  913. } catch (Throwable t) {
  914. printStackTrace(t, "getSystemCommandOutput");
  915. }
  916. return output;
  917. }
  918. /**
  919. * Fast impl of replacing %xx hexidecimal codes with actual characters (e.g., %20 is a space, %2F is '/').
  920. * Leaves untouched any bad hex digits, or %xx strings that represent control characters (less than space/0x20
  921. * or greater than tilde/0x7E).
  922. *
  923. * @return String with replaced %xx codes. If there are no '%' characters in the input string,
  924. * the original String object is returned.
  925. */
  926. public static String decodeURL(final String s)
  927. {
  928. //System.out.println("DECODING " + s);
  929. int i = s.indexOf('%');
  930. if (i < 0)
  931. return s;
  932. final int len = s.length();
  933. final StringBuffer buf = new StringBuffer(len);
  934. // copy in everything we've skipped in the original string up to now
  935. buf.append(s.substring(0, i));
  936. //System.out.println("DECODE START " + buf);
  937. for ( ; i < len; i++) {
  938. final char c = s.charAt(i);
  939. if (c == '%' && i+2 < len) {
  940. final int hex1 = Character.digit(s.charAt(++i), 16);
  941. final int hex2 = Character.digit(s.charAt(++i), 16);
  942. final char charValue = (char) (hex1 * 16 + hex2);
  943. //System.out.println("Got char value " + charValue + " from " + c1 + c2);
  944. if (hex1 < 1 || hex2 < 0 || charValue < 0x20 || charValue > 0x7E) {
  945. // Pass through untouched if not two good hex characters (and first can't be 0),
  946. // or if result is a control character (anything less than space, or greater than '~')
  947. buf.append('%');
  948. buf.append(s.charAt(i-1));
  949. buf.append(s.charAt(i));
  950. } else {
  951. buf.append(charValue);
  952. }
  953. } else {
  954. buf.append(c);
  955. }
  956. }
  957. if (DEBUG) {
  958. System.out.println("DECODED [" + s + "]");
  959. System.out.println(" TO [" + buf + "]");
  960. }
  961. return buf.toString();
  962. }
  963. public static final Iterator EmptyIterator = new EmptyIterable();
  964. public static final Iterable EmptyIterable = (Iterable) EmptyIterator;
  965. private static final class EmptyIterable implements java.util.Iterator, java.lang.Iterable {
  966. public boolean hasNext() { return false; }
  967. public Object next() { throw new NoSuchElementException(); }
  968. public void remove() { throw new UnsupportedOperationException(); }
  969. public String toString() { return "EmptyIterator"; }
  970. public Iterator iterator() { return this; }
  971. }
  972. public interface Itering<T> extends java.util.Iterator<T>, Iterable<T> {}
  973. public static abstract class AbstractItering<T> implements Itering<T> {
  974. public Iterator<T> iterator() {
  975. return this;
  976. }
  977. public void remove() {
  978. throw new UnsupportedOperationException();
  979. }
  980. }
  981. private static abstract class IndexedItering<T> extends AbstractItering<T> {
  982. final int length;
  983. int index = 0;
  984. IndexedItering(int len) { length = len; }
  985. public boolean hasNext() {
  986. return index < length;
  987. }
  988. // could reset index if another "instance" is requested via iterator()
  989. }
  990. public static <T> Itering<T> iterable(T o) {
  991. return new SingletonIterable<T>(o);
  992. }
  993. public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.NodeList nl) {
  994. return new IndexedItering<org.w3c.dom.Node>(nl.getLength()) {
  995. public org.w3c.dom.Node next() {
  996. return nl.item(index++);
  997. }
  998. };
  999. }
  1000. public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.NamedNodeMap nm) {
  1001. return new IndexedItering<org.w3c.dom.Node>(nm.getLength()) {
  1002. public org.w3c.dom.Node next() {
  1003. return nm.item(index++);
  1004. }
  1005. };
  1006. }
  1007. public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.Node n) {
  1008. return iterable(n.getChildNodes());
  1009. }
  1010. /** Convenience class: provides a single element iterator. Is also an iterable, returning self.
  1011. * Each request for an iterable resets us to be iterated again (not threadsafe) */
  1012. private static final class SingletonIterable<T> implements Itering<T> {
  1013. private final T object;
  1014. private boolean done;
  1015. public SingletonIterable(T o) {
  1016. object = o;
  1017. }
  1018. public boolean hasNext() { return !done; }
  1019. public T next() { if (done) throw new NoSuchElementException(); done = true; return object; }
  1020. public void remove() { throw new UnsupportedOperationException(); }
  1021. public Iterator<T> iterator() { done = false; return this; }
  1022. public String toString() { return "[" + object + "]"; }
  1023. };
  1024. public static <T> List<T> asList(T[] array) {
  1025. return new ExposedArrayList(array);
  1026. }
  1027. public static <T> T[] toArray(Collection<? extends T> bag, Class<T> clazz) {
  1028. // return (T[]) bag.toArray(); class cast exception
  1029. // can't create a new instance of the array w/out a known type -- unreliable to pull from collection (and could be empty)
  1030. //return bag.toArray((T[])java.lang.reflect.Array.newInstance(?.getClass(), bag.size()));
  1031. return bag.toArray((T[])java.lang.reflect.Array.newInstance(clazz, bag.size()));
  1032. }
  1033. /**
  1034. * Identical to Arrays.asList, except that toArray() returns the internal array,
  1035. * which allows for Collection.addAll(ExposedArrayList) to be used w/out triggering an array clone
  1036. */
  1037. private static final class ExposedArrayList<E> extends AbstractList<E>
  1038. implements RandomAccess
  1039. {
  1040. private final Object[] a;
  1041. ExposedArrayList(E[] array) {
  1042. if (array == null) throw new NullPointerException();
  1043. a = array;
  1044. }
  1045. @Override
  1046. public int size() { return a.length; }
  1047. /** returns the internal array -- allows for Collection.addAll(ExposedArrayList) to be called w/out triggering a clone */
  1048. @Override
  1049. public Object[] toArray() { return a; }
  1050. @Override
  1051. public E get(int index) { return (E)a[index]; }
  1052. @Override
  1053. public E set(int index, E element) {
  1054. Object oldValue = a[index];
  1055. a[index] = element;
  1056. return (E)oldValue;
  1057. }
  1058. @Override
  1059. public int indexOf(Object o) {
  1060. if (o==null) {
  1061. for (int i=0; i<a.length; i++)
  1062. if (a[i]==null)
  1063. return i;
  1064. } else {
  1065. for (int i=0; i<a.length; i++)
  1066. if (o.equals(a[i]))
  1067. return i;
  1068. }
  1069. return -1;
  1070. }
  1071. @Override
  1072. public boolean contains(Object o) {
  1073. return indexOf(o) != -1;
  1074. }
  1075. }
  1076. private static final class SkipNullsArrayList<T> extends ArrayList<T> {
  1077. SkipNullsArrayList() {}
  1078. @Override
  1079. public boolean add(T c) {
  1080. if (c == null) {
  1081. //Util.printStackTrace("null not allowed");
  1082. } else {
  1083. super.add(c);
  1084. }
  1085. return true;
  1086. }
  1087. }
  1088. public static ArrayList skipNullsArrayList() {
  1089. return new SkipNullsArrayList();
  1090. }
  1091. public static <A, T extends A> int countTypes(final Iterable<A> list, final Class<T> clazz) {
  1092. int count = 0;
  1093. for (A item: list)
  1094. if (clazz.isInstance(item))
  1095. count++;
  1096. return count;
  1097. }
  1098. public static <A, T extends A> boolean containsOnly(final Iterable<A> list, final Class<T> clazz) {
  1099. for (A item: list)
  1100. if (!clazz.isInstance(item))
  1101. return false;
  1102. return true;
  1103. }
  1104. public static <T> T getFirst(Collection<T> bag)
  1105. {
  1106. if (bag.isEmpty())
  1107. return null;
  1108. if (bag instanceof java.util.List) {
  1109. return ((List<T>)bag).get(0);
  1110. } else {
  1111. return bag.iterator().next();
  1112. }
  1113. }
  1114. public static <A, T extends A> List<T> extractType
  1115. (final Collection<A> list,
  1116. final Class<T> clazz)
  1117. {
  1118. final List<T> desiredType = new ArrayList(list.size());
  1119. for (A item : list)
  1120. if (clazz.isInstance(item))
  1121. desiredType.add((T)item);
  1122. return desiredType;
  1123. }
  1124. /** choose the given object for inclusion */
  1125. public interface Picker<T> { boolean match(T o); }
  1126. /** exclude the given object from inclusion */
  1127. public interface Filter<T> { boolean match(T o); }
  1128. public static <T> List<T> extract
  1129. (final Collection<T> list,
  1130. final Picker<T> picker)
  1131. {
  1132. final List<T> desired = new ArrayList(list.size());
  1133. for (T item : list) {
  1134. try {
  1135. if (picker.match(item))
  1136. desired.add(item);
  1137. } catch (Throwable t) {
  1138. Log.error("picker " + tags(picker) + " failed matching " + item, t);
  1139. }
  1140. }
  1141. return desired;
  1142. }
  1143. /** reverse of extract */
  1144. public static <T> List<T> filter
  1145. (final Collection<T> list,
  1146. final Filter<T> filter)
  1147. {
  1148. final List<T> desired = new ArrayList(list.size());
  1149. for (T item : list) {
  1150. try {
  1151. if (!filter.match(item))
  1152. desired.add(item);
  1153. } catch (Throwable t) {
  1154. Log.error("filter " + tags(filter) + " failed matching " + item, t);
  1155. }
  1156. }
  1157. return desired;
  1158. }
  1159. /**
  1160. * Note the hairy generic method signature. 'A' is the generic type contained in
  1161. * an iterable that is the source of all objects for the filter. 'T' is the
  1162. * specific type that we're looking for. T should be a subclass of A.
  1163. * Currently creates a type filter that requires *exact* type matching: subclasses of the type do NOT match.
  1164. */
  1165. public static <A, T extends A> Iterable<T> typeFilter
  1166. (final Class<T> clazz,
  1167. final Iterable<A> iterable)
  1168. {
  1169. return new IteratorTypeFilter<A,T>(iterable, clazz);
  1170. }
  1171. public static <A, T extends A> Iterable<T> typeFilter
  1172. (final Iterable<A> iterable,
  1173. final Class<T> clazz)
  1174. {
  1175. return new IteratorTypeFilter<A,T>(iterable, clazz);
  1176. }
  1177. private static final class IteratorTypeFilter<A,T extends A> extends AbstractItering<T> {
  1178. private static final Object NEXT_NEEDED = new Object();
  1179. private static final Object EOL = new Object();
  1180. final Iterator<A> iter;
  1181. final Class<T> clazz;
  1182. Object next = NEXT_NEEDED;
  1183. // todo: could also allow an array of varied types to be looked for
  1184. public IteratorTypeFilter(Iterable<A> i, Class<T> c) {
  1185. iter = i.iterator();
  1186. clazz = c;
  1187. }
  1188. private void advance() {
  1189. if (iter.hasNext()) {
  1190. while (true) {
  1191. next = iter.next();
  1192. //Log.debug(" ADVANCED " + tags(next));
  1193. if (next != null && next.getClass() == clazz)
  1194. break;
  1195. // if (clazz.isInstance(next))
  1196. // break;
  1197. if (!iter.hasNext()) {
  1198. next = EOL;
  1199. break;
  1200. }
  1201. }
  1202. } else {
  1203. next = EOL;
  1204. }
  1205. }
  1206. public boolean hasNext() {
  1207. if (next == NEXT_NEEDED)
  1208. advance();
  1209. //if (next == EOL) Log.debug("EOL on " + tags(iter));
  1210. return next != EOL;
  1211. }
  1212. public T next() {
  1213. if (next == NEXT_NEEDED)
  1214. advance();
  1215. if (next == EOL)
  1216. throw new NoSuchElementException("at end of iterator " + tags(iter));
  1217. final Object result = next;
  1218. next = NEXT_NEEDED;
  1219. //Log.debug("RETURNING " + tags(result));
  1220. return (T) result;
  1221. }
  1222. };
  1223. // /** Flatten's a Map who's values are collections: returns a key/value for each value in each collection */
  1224. // public static final class FlatteningIterator<K,V> extends AbstractItering<Map.Entry<K,V>> {
  1225. // final Iterator<Map.Entry<Object,Collection>> keyIterator;
  1226. // /** this object returned as the result every time */
  1227. // final KVEntry entry = new KVEntry();
  1228. // Iterator valueIterator;
  1229. // FlatteningIterator(Map<Object,Collection> map) {
  1230. // keyIterator = map.entrySet().iterator();
  1231. // if (keyIterator.hasNext()) {
  1232. // findValueIteratorAndKey();
  1233. // } else {
  1234. // valueIterator = Iterators.emptyIterator();
  1235. // }
  1236. // }
  1237. // void findValueIteratorAndKey() {
  1238. // final Map.Entry e = keyIterator.next();
  1239. // entry.key = e.getKey();
  1240. // Collection collection = (Collection) e.getValue();
  1241. // valueIterator = collection.iterator();
  1242. // }
  1243. // public boolean hasNext() {
  1244. // return valueIterator.hasNext() || keyIterator.hasNext();
  1245. // }
  1246. // /** note: current impl will always return the same Map.Entry object */
  1247. // public Map.Entry next() {
  1248. // if (!hasNext()) throw new NoSuchElementException();
  1249. // if (!valueIterator.hasNext())
  1250. // findValueIteratorAndKey();
  1251. // entry.value = valueIterator.next();
  1252. // return entry;
  1253. // }
  1254. // }
  1255. /** for providing a copy of a list -- especially useful for providing a concurrency safe iteration of a list */
  1256. public static <T> List<T> copy(java.util.List<T> list) {
  1257. if (list instanceof java.util.ArrayList)
  1258. return (List<T>) ((java.util.ArrayList)list).clone();
  1259. else
  1260. return new ArrayList(list);
  1261. }
  1262. /** usage: for (SomeObject o : reverse(someObjectCollection)) { ... } */
  1263. public static <T> Iterable<T> reverse(java.util.Collection<T> bag) {
  1264. if (bag instanceof List) {
  1265. return reverse((java.util.List)bag);
  1266. } else {
  1267. return new ReverseArrayIterator(bag.toArray());
  1268. }
  1269. }
  1270. /** usage: for (SomeObject o : reverse(someObjectList)) { ... } */
  1271. public static <T> Iterable<T> reverse(java.util.List<T> list) {
  1272. return new ReverseListIterator<T>(list);
  1273. }
  1274. /** Convenience class: provides a reversed list iteration. List should not modified during iteration.
  1275. Currently does NOT provide fail-fast behaviour. */
  1276. // could provide a standard fail-fast on concurrent modification by internally using a ListIterator
  1277. private static final class ReverseListIterator<T> implements java.util.Iterator<T>, Iterable<T> {
  1278. private final java.util.List<T> list;
  1279. private int index;
  1280. public ReverseListIterator(java.util.List<T> toReverse) {
  1281. list = toReverse;
  1282. index = list.size();
  1283. }
  1284. public boolean hasNext() { return index > 0; }
  1285. public T next() { return list.get(--index); }
  1286. public void remove() { throw new UnsupportedOperationException(); }
  1287. public Iterator iterator() { return this; }
  1288. };
  1289. private static final class ArrayIterator implements java.util.Iterator, Iterable {
  1290. private final Object[] array;
  1291. private int index;
  1292. public ArrayIterator(Object[] a) {
  1293. array = a;
  1294. index = 0;
  1295. }
  1296. public boolean hasNext() { return index < array.length; }
  1297. public Object next() { return array[index++]; }
  1298. public void remove() { throw new UnsupportedOperationException(); }
  1299. public Iterator iterator() { return this; }
  1300. };
  1301. private static final class ReverseArrayIterator implements java.util.Iterator, Iterable {
  1302. private final Object[] array;
  1303. private int index;
  1304. public ReverseArrayIterator(Object[] a) {
  1305. array = a;
  1306. index = a.length;
  1307. }
  1308. public boolean hasNext() { return index > 0; }
  1309. public Object next() { return array[--index]; }
  1310. public void remove() { throw new UnsupportedOperationException(); }
  1311. public Iterator iterator() { return this; }
  1312. };
  1313. /** GroupIterator allows you to construct a new iterator that
  1314. * will aggregate an underlying set of Iterators and/or Collections */
  1315. public static final class GroupIterator<T> extends java.util.ArrayList
  1316. implements java.util.Iterator, java.lang.Iterable
  1317. {
  1318. int iterIndex = 0;
  1319. Iterator<T> curIter;
  1320. public GroupIterator() {}
  1321. public GroupIterator(Iterable<T>... iterables) {
  1322. super.addAll(new ExposedArrayList(iterables));
  1323. }
  1324. public GroupIterator(Iterator<T>... iterators) {
  1325. super.addAll(new ExposedArrayList(iterators));
  1326. }
  1327. public GroupIterator(Object... mixedTypes) {
  1328. for (Object o : mixedTypes)
  1329. add(o);
  1330. }
  1331. /**
  1332. * Add a new Iterator or Iterable to this GroupIterator. This can only be
  1333. * done before iteration has started for this GroupIterator.
  1334. * @param o an Iterator or Collection
  1335. * @return result of super.add (ArrayList.add)
  1336. */
  1337. @Override
  1338. public boolean add(Object o) {
  1339. if (!(o instanceof Iterable) &&
  1340. !(o instanceof Iterator))
  1341. throw new IllegalArgumentException("GroupIterator: can only add Iterable's or Iterators: " + o);
  1342. return super.add(o);
  1343. }
  1344. /**
  1345. * Add a new Iterable to to group. This can only be done before iteration has started.
  1346. */
  1347. public void add(Iterable o) {
  1348. super.add(o);
  1349. }
  1350. /**
  1351. * Add a new Iterator to to group. This can only be done before iteration has started.
  1352. */
  1353. public void add(Iterator o) {
  1354. super.add(o);
  1355. }
  1356. public boolean hasNext()
  1357. {
  1358. if (curIter == null) {
  1359. if (iterIndex >= size())
  1360. return false;
  1361. Object next = get(iterIndex);
  1362. if (next instanceof Iterator)
  1363. curIter = (Iterator) next;
  1364. else
  1365. curIter = ((Iterable)next).iterator();
  1366. iterIndex++;
  1367. if (curIter == null)
  1368. return false;
  1369. }
  1370. // make the call on the underlying iterator
  1371. if (curIter.hasNext()) {
  1372. return true;
  1373. } else {
  1374. curIter = null;
  1375. return hasNext();
  1376. }
  1377. }
  1378. public T next()
  1379. {
  1380. if (curIter == null)
  1381. return null;
  1382. else
  1383. return curIter.next();
  1384. }
  1385. public void remove()
  1386. {
  1387. if (curIter != null)
  1388. curIter.remove();
  1389. else
  1390. throw new IllegalStateException(this + ": no underlying iterator");
  1391. }
  1392. @Override
  1393. public Iterator iterator() {
  1394. return this;
  1395. }
  1396. }
  1397. /**
  1398. * A soft-reference map for maps containing items can be garbage
  1399. * collected if we run low on memory (e.g., images). If that
  1400. * happens, items will seem to have disspeared from the cache.
  1401. *
  1402. * Not all HashMap methods covered: only safe to use
  1403. * the onces explicity implemented here.
  1404. */
  1405. public static class SoftMap extends HashMap {
  1406. public synchronized Object get(Object key) {
  1407. //out("SoftMap; get: " + key);
  1408. Object val = super.get(key);
  1409. if (val == null)
  1410. return null;
  1411. Reference ref = (Reference) val;
  1412. val = ref.get();
  1413. if (val == null) {
  1414. //out("SoftMap; image was garbage collected: " + key);
  1415. super.remove(key);
  1416. return null;
  1417. } else
  1418. return val;
  1419. }
  1420. public synchronized Object put(Object key, Object value) {
  1421. //out("SoftMap; put: " + key);
  1422. return super.put(key, new SoftReference(value));
  1423. }
  1424. public synchronized boolean containsKey(Object key) {
  1425. return get(key) != null;
  1426. }
  1427. public synchronized void clear() {
  1428. Iterator i = values().iterator();
  1429. while (i.hasNext())
  1430. ((Reference)i.next()).clear();
  1431. super.clear();
  1432. }
  1433. }
  1434. public static void dump(Object[] a) {
  1435. dumpArray(a);
  1436. }
  1437. public static void dump(Collection c) {
  1438. dumpCollection(c);
  1439. }
  1440. public static void dump(Map<?,?> m) {
  1441. dump(m, "");
  1442. }
  1443. public static void dump(Map<?,?> m, String tag) {
  1444. if (m != null) {
  1445. //System.out.format("Map of size: %d (%s) %s\n", m.size(), m.getClass().getName(), tag);
  1446. System.out.format("Map of size: %d (%s) %s\n", m.size(), tag(m), tag);
  1447. for (Map.Entry<?,?> e : m.entrySet()) {
  1448. System.out.format(" %24s: %s\n", tags(e.getKey()), tags(e.getValue()));
  1449. }
  1450. } else
  1451. System.out.println("\t<NULL MAP>");
  1452. }
  1453. public static void dumpArray(Object[] a) {
  1454. if (a != null)
  1455. dumpCollection(Arrays.asList(a));
  1456. else
  1457. System.out.println("\t<NULL ARRAY>");
  1458. }
  1459. public static void dumpCollection(Collection c) {
  1460. System.out.println("Collection of size: " + c.size() + " (" + tag(c) + ")");
  1461. try {
  1462. dumpIterator(c.iterator());
  1463. } catch (Throwable t) {
  1464. Log.warn("dumping " + tag(c), t);
  1465. }
  1466. }
  1467. public static void dumpIterator(Iterator i) {
  1468. int x = 0;
  1469. while (i.hasNext()) {
  1470. //System.out.println((x<10?" ":"") + x + ": " + i.next());
  1471. System.out.format("\t%2d: %s\n", x, tags(i.next()));
  1472. //System.out.format("\t%2d: \"%s\"\n", x, i.next());
  1473. x++;
  1474. }
  1475. }
  1476. public static RuntimeException wrapIfChecked(String msg, Throwable t) {
  1477. if (t instanceof RuntimeException)
  1478. throw (RuntimeException) t;
  1479. else
  1480. throw wrapException(msg, t);
  1481. }
  1482. public static RuntimeException wrapException(String msg, Throwable t) {
  1483. return new WrappedException("(" + msg + ") ", t);
  1484. }
  1485. private static class WrappedException extends RuntimeException {
  1486. WrappedException(String msg, Throwable cause) {
  1487. super(msg, cause);
  1488. }
  1489. @Override public String toString() {
  1490. return getMessage() + getCause().toString();
  1491. }
  1492. }
  1493. // public static void dumpURI(URI u) {
  1494. // dumpURI(u, null);
  1495. // }
  1496. // public static void dumpURI(URI u, String msg) {
  1497. // synchronized (System.out) {
  1498. // //System.out.format("%16s URI: %s %s\n", msg, u, System.identityHashCode(u), u, msg==null?"":"("+msg+")");
  1499. // System.out.format("%16s URI: %s @%x\n",
  1500. // msg==null?"":('"'+msg+'"'),
  1501. // u,
  1502. // System.identityHashCode(u));
  1503. // dumpField("hashCode", Integer.toHexString(u.hashCode()));
  1504. // dumpField("scheme", u.getScheme());
  1505. // dumpRawField("authority", u.getAuthority(), u.getRawAuthority());
  1506. // dumpField("userInfo", u.getUserInfo());
  1507. // dumpField("host", u.getHost());
  1508. // if (u.getPort() != -1)
  1509. // dumpField("port", u.getPort());
  1510. // dumpRawField("path", u.getPath(), u.getRawPath());
  1511. // dumpRawField("query", u.getQuery(), u.getRawQuery());
  1512. // dumpRawField("fragment", u.getFragment(), u.getRawFragment());
  1513. // System.out.println("-------------------------------------------------------");
  1514. // }
  1515. // }
  1516. // private static void dumpField(String label, Object value) {
  1517. // //if (value != null)
  1518. // System.out.format("%20s: %s\n", label, value);
  1519. // }
  1520. // private static void dumpRawField(String label, Object value, Object rawValue) {
  1521. // dumpField(label, value);
  1522. // if (value != null && !value.equals(rawValue) || rawValue == null && value != null)
  1523. // dumpField("raw" + label, rawValue);
  1524. // }
  1525. /** center the given window on default physical screen */
  1526. public static void centerOnScreen(java.awt.Window window)
  1527. {
  1528. if (getJavaVersion() >= 1.4f) {
  1529. java.awt.Point p = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
  1530. p.x -= window.getWidth() / 2;
  1531. p.y -= window.getHeight() / 2;
  1532. window.setLocation(p);
  1533. } else {
  1534. java.awt.Dimension d = window.getToolkit().getScreenSize();
  1535. int x = d.width/2 - window.getWidth()/2;
  1536. int y = d.height/2 - window.getHeight()/2;
  1537. window.setLocation(x, y);
  1538. }
  1539. }
  1540. static final double sFactor = 0.9;
  1541. public static Color darkerColor(Color c) {
  1542. return factorColor(c, sFactor);
  1543. }
  1544. public static Color brighterColor(Color c) {
  1545. return factorColor(c, 1/sFactor);
  1546. }
  1547. public static Color factorColor(Color c, double factor)
  1548. {
  1549. return new Color((int)(c.getRed() *factor),
  1550. (int)(c.getGreen()*factor),
  1551. (int)(c.getBlue() *factor));
  1552. }
  1553. public static final float brightness(java.awt.Color c) {
  1554. if (c == null)
  1555. return 0;
  1556. final int r = c.getRed();
  1557. final int g = c.getGreen();
  1558. final int b = c.getBlue();
  1559. int max = (r > g) ? r : g;
  1560. if (b > max) max = b;
  1561. return ((float) max) / 255f;
  1562. }
  1563. /** @return a new color, which is a mix a given color with alpha, plus another NON alpha color */
  1564. // ... wouldn't take much more to mix multiple alpha's, tho normally some color at bottom should
  1565. // always be non-alpha
  1566. public static final Color alphaMix(java.awt.Color ac, java.awt.Color c) {
  1567. final float r = ac.getRed();
  1568. final float g = ac.getGreen();
  1569. final float b = ac.getBlue();
  1570. final float alpha = ac.getAlpha();
  1571. final float mix = 255 - alpha;
  1572. return new Color((int) ( (r * alpha + mix * c.getRed() ) / 255f + 0.5f ),
  1573. (int) ( (g * alpha + mix * c.getGreen()) / 255f + 0.5f ),
  1574. (int) ( (b * alpha + mix * c.getBlue() ) / 255f + 0.5f ));
  1575. }
  1576. public static final Color alphaColor(java.awt.Color c, float alpha) {
  1577. final int a = (int) ((alpha * 255f) + 0.5f); // covert % alpha to 0-255
  1578. final int rgba =
  1579. (c.getRGB() & 0x00FFFFFF) | // strip existing alpha
  1580. ((a & 0xFF) << 24); // add new alpha
  1581. return new Color(rgba, true);
  1582. }
  1583. /** a JPanel that anti-aliases text */
  1584. public static class JPanelAA extends javax.swing.JPanel {
  1585. public JPanelAA(java.awt.LayoutManager layout) {
  1586. super(layout, true);
  1587. }
  1588. public JPanelAA() {}
  1589. public void paint(java.awt.Graphics g) {
  1590. // only works when, of course, the panel is asked
  1591. // to redraw -- but if you mess with subcomponents
  1592. // and just they repaint, we lose this.
  1593. // todo: There must be a way to stick this in a global
  1594. // property somewhere.
  1595. // anti-alias is default on mac, so don't do it there.
  1596. if (!isMacPlatform())
  1597. ((java.awt.Graphics2D)g).setRenderingHint
  1598. (java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
  1599. java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  1600. super.paint(g);
  1601. }
  1602. }
  1603. public static class JLabelAA extends javax.swing.JLabel {
  1604. public JLabelAA(String text) {
  1605. super(text);
  1606. }
  1607. public JLabelAA() {}
  1608. public void paintComponent(java.awt.Graphics g) {
  1609. // anti-alias is default on mac, so don't do it there.
  1610. if (!isMacPlatform())
  1611. ((java.awt.Graphics2D)g).setRenderingHint
  1612. (java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
  1613. java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  1614. super.paintComponent(g);
  1615. }
  1616. }
  1617. /** This is for testing individual components. It will display the given component in frame
  1618. * of the given size. */
  1619. public static JFrame displayComponent(java.awt.Component comp, int width, int height)
  1620. {
  1621. javax.swing.JFrame frame = new javax.swing.JFrame(objectTag(comp));
  1622. comp.setSize(comp.getPreferredSize());
  1623. if (comp instanceof JComponent)
  1624. frame.setContentPane((JComponent)comp);
  1625. else
  1626. frame.getContentPane().add(comp);
  1627. if (width != 0 && height != 0)
  1628. frame.setSize(width, height);
  1629. else
  1630. frame.pack();
  1631. frame.validate();
  1632. centerOnScreen(frame);
  1633. frame.setVisible(true);
  1634. return frame;
  1635. }
  1636. /** This is for testing individual components. It will display the given component in frame. */
  1637. public static JFrame displayComponent(java.awt.Component comp) {
  1638. return displayComponent(comp, 0, 0);
  1639. }
  1640. // public static void screenToBlack() {
  1641. // if (!isMacPlatform())
  1642. // return;
  1643. // try {
  1644. // MacOSX.goBlack();
  1645. // } catch (LinkageError e) {
  1646. // eout(e);
  1647. // }
  1648. // }
  1649. // public static void screenFadeFromBlack() {
  1650. // if (isMacPlatform()) {
  1651. // try {
  1652. // MacOSX.fadeFromBlack();
  1653. // } catch (LinkageError e) {
  1654. // eout(e);
  1655. // }
  1656. // }
  1657. // }
  1658. /** For mac platform: to keep tool windows that are frames on top
  1659. * of the main app window, you need to go to "native" java/cocoa code.
  1660. * @param inActionTitle - the title of a window just shown / or currently
  1661. * undergoing a show, to make sure we fix up, even if it doesn't claim
  1662. * to be visible yet.
  1663. */
  1664. public static void adjustMacWindows(String mainWindowTitleStart,
  1665. String ensureShown,
  1666. String ensureHidden,
  1667. boolean inFullScreenMode)
  1668. {
  1669. if (isMacPlatform()) {
  1670. try {
  1671. MacOSX.adjustMacWindows(mainWindowTitleStart, ensureShown, ensureHidden, inFullScreenMode);
  1672. } catch (LinkageError e) {
  1673. eout(e);
  1674. } catch (Exception e) {
  1675. System.err.println("failed to handle mac window adjustment");
  1676. e.printStackTrace();
  1677. }
  1678. }
  1679. }
  1680. public static String upperCaseWords(String s)
  1681. {
  1682. //if (DEBUG) out("UCW in["+s+"]");
  1683. final StringBuilder result = new StringBuilder(s.length());
  1684. final String[] words = s.split(" ");
  1685. for (int i = 0; i < words.length; i++) {
  1686. String word = words[i];
  1687. //if (DEBUG) out("word" + i + "["+word+"]");
  1688. if (word.length() < 1)
  1689. continue;
  1690. if (Character.isLowerCase(word.charAt(0))) {
  1691. result.append(Character.toUpperCase(word.charAt(0)));
  1692. word = word.substring(1);
  1693. }
  1694. result.append(word);
  1695. if (i + 1 < words.length)
  1696. result.append(' ');
  1697. }
  1698. //if (DEBUG) out("UCWout["+result+"]");
  1699. return result.toString();
  1700. }
  1701. private static void eout(LinkageError e) {
  1702. if (e instanceof NoSuchMethodError)
  1703. eout((NoSuchMethodError)e);
  1704. else if (e instanceof NoClassDefFoundError)
  1705. eout((NoClassDefFoundError)e);
  1706. else {
  1707. System.err.println(e + ": problem with Mac Java/Cocoa Code");
  1708. }
  1709. }
  1710. private static void eout(NoSuchMethodError e) {
  1711. // If tufts.macosx.Screen get's out of date, or
  1712. // it's library is not included in the build, we'll
  1713. // get a NoSuchMethodError
  1714. System.err.println(e + ": tufts.macosx.Screen needs rebuild or VUE-MacOSX.jar library not in classpath");
  1715. }
  1716. private static void eout(NoClassDefFoundError e) {
  1717. // We'll get this if /System/Library/Java isn't in the classpath
  1718. System.err.println(e + ": Not Mac OS X Platform, or VUE-MacOSX.jar and/or /System/Library/Java not in classpath");
  1719. }
  1720. public static Rectangle2D.Float grow(Rectangle2D.Float r, int size) {
  1721. r.x -= size;
  1722. r.y -= size;
  1723. r.width += size * 2;
  1724. r.height += size * 2;
  1725. return r;
  1726. }
  1727. public static Rectangle2D.Float grow(Rectangle2D.Float r, float size) {
  1728. r.x -= size;
  1729. r.y -= size;
  1730. r.width += size * 2;
  1731. r.height += size * 2;
  1732. return r;
  1733. }
  1734. /** @return true if any value (x,y,width,height) is Float.NaN. As a single
  1735. * Float.NaN (or Double.NaN) will corrupt any accumulation of values, they can
  1736. * ultimately cause java Graphics2D renderings to fail completely. For this reason
  1737. * it's important to exclude bad Rectangle's from all manner of bounds computation
  1738. * or drawing code. */
  1739. public static boolean isBadRect(Rectangle2D.Float r) {
  1740. return r.x != r.x
  1741. || r.y != r.y
  1742. || r.width != r.width
  1743. || r.height != r.height;
  1744. }
  1745. /** @return true if any value (x,y,width,height) is Double.NaN */
  1746. public static boolean isBadRect(Rectangle2D.Double r) {
  1747. return r.x != r.x
  1748. || r.y != r.y
  1749. || r.width != r.width
  1750. || r.height != r.height;
  1751. }
  1752. /** @return true if any value (x,y,width,height) is Double.NaN */
  1753. public static boolean isBadRect(Rectangle2D r) {
  1754. return Double.isNaN(r.getX())
  1755. || Double.isNaN(r.getY())
  1756. || Double.isNaN(r.getWidth())
  1757. || Double.isNaN(r.getHeight());
  1758. }
  1759. /** @return true if either value is Double.NaN */
  1760. public static boolean isBadPoint(Point2D p) {
  1761. return Double.isNaN(p.getX())
  1762. || Double.isNaN(p.getY());
  1763. }
  1764. /** @return true if either value is Float.NaN */
  1765. public static boolean isBadPoint(Point2D.Float p) {
  1766. return p.x != p.x
  1767. || p.y != p.y;
  1768. }
  1769. /** @return true if either value is Double.NaN */
  1770. public static boolean isBadPoint(Point2D.Double p) {
  1771. return p.x != p.x
  1772. || p.y != p.y;
  1773. }
  1774. public static String fmt(final Shape shape) {
  1775. final Rectangle2D r;
  1776. final String name;
  1777. if (shape instanceof Rectangle2D) {
  1778. r = (Rectangle2D) shape;
  1779. name = "Rect";
  1780. } else {
  1781. if (shape == null) {
  1782. name = "Shape";
  1783. r = null;
  1784. } else {
  1785. name = shape.getClass().getName();
  1786. r = shape.getBounds2D();
  1787. }
  1788. }
  1789. return shape == null
  1790. ? "<null-" + name + ">"
  1791. : String.format("%s@%08x[%7.1f,%-7.1f %5.1fx%-5.1f]",
  1792. name,
  1793. shape == null ? 0 : System.identityHashCode(shape),
  1794. r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1795. }
  1796. public static String fmt(QuadCurve2D.Float c) {
  1797. return String.format("QuadCurveF[%.1f,%.1f %.1f,%,1f %.1f,%.1f]",
  1798. c.x1, c.y1,
  1799. c.x2, c.y2,
  1800. c.ctrlx, c.ctrly);
  1801. }
  1802. public static String fmt(CubicCurve2D.Float c) {
  1803. return String.format("CubicCurveF[%.1f,%.1f %.1f,%,1f %.1f,%.1f %.1f,%.1f]",
  1804. c.x1, c.y1,
  1805. c.x2, c.y2,
  1806. c.ctrlx1, c.ctrly1,
  1807. c.ctrlx2, c.ctrly2);
  1808. }
  1809. // public static String fmt(CubicCurve2D c) {
  1810. // return String.format("QuadCurve[%.1f,.1f %.1f,%,1f %.1f,%.1f]",
  1811. // c.getX1(), c.getY1(),
  1812. // c.getX2(), c.getY2(),
  1813. // c.getCtrlX1(), c.getCtrlY1(),
  1814. // c.getCtrlX2(), c.getCtrlY2());
  1815. // }
  1816. public static String fmt(final java.awt.Color c) {
  1817. if (c == null)
  1818. return "<null-Color>";
  1819. if (c.getAlpha() != 0xFF)
  1820. return String.format("Color(%d,%d,%d,%d)", c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
  1821. else
  1822. return String.format("Color(%d,%d,%d)", c.getRed(), c.getGreen(), c.getBlue());
  1823. }
  1824. public static String fmt(java.awt.geom.Point2D p) {
  1825. if (p == null)
  1826. return "<null-Point2D>";
  1827. else
  1828. return String.format("%.1f,%.1f", p.getX(), p.getY());
  1829. }
  1830. public static String fmt(java.awt.Point p) {
  1831. if (p == null)
  1832. return "<null-Point>";
  1833. else
  1834. return String.format("%d,%d", p.x, p.y);
  1835. }
  1836. public static String fmt(java.awt.geom.Line2D l) {
  1837. if (l == null)
  1838. return "<null-Line2D>";
  1839. else
  1840. return String.format("%.1f,%.1f -> %.1f,%.1f", l.getX1(), l.getY1(), l.getX2(), l.getY2());
  1841. }
  1842. public static String fmt(java.awt.geom.Dimension2D d) {
  1843. if (d == null)
  1844. return "<null-Dimension>";
  1845. else
  1846. return String.format("[%.1f x %.1f]", d.getWidth(), d.getHeight());
  1847. }
  1848. public static void out(Object o) {
  1849. //System.out.println((o==null?"null":o.toString()));
  1850. Log.debug("OUT: "+(o==null?"null":o.toString()));
  1851. }
  1852. /*
  1853. public static void out(String s) {
  1854. System.out.println(s==null?"null":s);
  1855. }
  1856. */
  1857. public static String out(Object[] o) {
  1858. if (o == null)
  1859. return "<null Object[]>";
  1860. else
  1861. return Arrays.asList(o).toString();
  1862. }
  1863. public static String out(java.awt.geom.Point2D p) {
  1864. return fmt(p);
  1865. //return oneDigitDecimal(p.getX()) + "," + oneDigitDecimal(p.getY());
  1866. //return (float)p.getX() + "," + (float)p.getY();
  1867. }
  1868. public static String out(java.awt.Dimension d) {
  1869. return d == null ? "null" : (d.width + "x" + d.height);
  1870. }
  1871. public static String out(java.awt.geom.Rectangle2D r) {
  1872. if (r == null)
  1873. return "<null Rectangle2D>";
  1874. else
  1875. return String.format("[%7.1f,%-7.1f %5.1fx%-5.1f]", r.getX(), r.getY(), r.getWidth(), r.getHeight());
  1876. }
  1877. public static String out(java.awt.Rectangle r) {
  1878. if (r == null)
  1879. return "<null Rectangle>";
  1880. else
  1881. return String.format("[%4d,%4d %-5dx%4d]", r.x, r.y, r.width, r.height);
  1882. }
  1883. public static String out(java.awt.geom.RectangularShape r) {
  1884. if (r == null)
  1885. return "<null RectangularShape>";
  1886. String name = r.getClass().getName();
  1887. name = name.substring(name.lastIndexOf('.') + 1);
  1888. return name + "["
  1889. + (float)r.getX() + "," + (float)r.getY()
  1890. + " "
  1891. + (float)r.getWidth() + "x" + (float)r.getHeight()
  1892. + "]"
  1893. ;
  1894. }
  1895. public static String out(java.awt.geom.Line2D l) {
  1896. if (l == null)
  1897. return "<null Line2D>";
  1898. else
  1899. return ""
  1900. + (float)l.getX1() + "," + (float)l.getY1()
  1901. + " -> "
  1902. + (float)l.getX2() + "," + (float)l.getY2()
  1903. ;
  1904. }
  1905. public static void outf(org.apache.log4j.Logger logger, String format, Object ... args)
  1906. {
  1907. if (args == null || args.length == 0) {
  1908. logger.debug(format);
  1909. } else {
  1910. try {
  1911. logger.debug(String.format(format, args));
  1912. } catch (Throwable t) {
  1913. logger.warn("bad format? " + t);
  1914. logger.debug(format);
  1915. t.printStackTrace();
  1916. }
  1917. }
  1918. }
  1919. public static String oneDigitDecimal(double x) {
  1920. int tenX = (int) Math.round(x * 10);
  1921. if ((tenX / 10) * 10 == tenX)
  1922. return new Integer(tenX / 10).toString();
  1923. else
  1924. return new Float( ((float)tenX) / 10f ).toString();
  1925. }
  1926. /** @return a friendly looking string to represent the given number of bytes: e.g.: 120k, or 3.8M.
  1927. * for values less than zero, returns ""
  1928. */
  1929. public static String abbrevBytes(long bytes) {
  1930. if (bytes > 1024*1024)
  1931. return String.format("%.1fM", (bytes/(1024.0*1024)));
  1932. else if (bytes > 1024)
  1933. return bytes/1024 + "k";
  1934. else if (bytes >= 0)
  1935. return "" + bytes;
  1936. else
  1937. return "";
  1938. }
  1939. /*
  1940. public static String displayName(Class clazz) {
  1941. if (clazz == null)
  1942. return "()";
  1943. final String name = clazz.getSimpleName();
  1944. final StringBuffer buf = new StringBuffer(name.length() + 6);
  1945. // if (true) {
  1946. // String[] segs = name.split("\\p{Lower}\\p{Upper}");
  1947. // for (int i = 0; i < segs.length; i++) {
  1948. // buf.append(segs[i]);
  1949. // buf.append(' ');
  1950. // }
  1951. // return buf.toString();
  1952. // }
  1953. int i = 0;
  1954. while (i < name.length() && Character.isUpperCase(name.charAt(i)))
  1955. buf.append(name.charAt(i++));
  1956. if (i > 1)
  1957. buf.insert(i - 1, ' ');
  1958. int lastAdd = 0;
  1959. boolean inUpper = true;
  1960. for (; i < name.length(); i++) {
  1961. final char c = name.charAt(0);
  1962. if (inUpper && Character.isLowerCase(c)) {
  1963. buf.append(name, lastAdd, i - 2);
  1964. buf.append(' ');
  1965. buf.append(name.charAt(i - 1));
  1966. buf.append(c);
  1967. //inUpper = false;
  1968. }
  1969. }
  1970. return name+"{"+buf.toString() +"}";
  1971. //return buf.toString();
  1972. }
  1973. */
  1974. public static void test_OpenURL()
  1975. {
  1976. try {
  1977. openURL("http://hosea.lib.tufts.edu:8080/fedora/get//tufts:7/demo:60/getThumbnail/");
  1978. //openURL("file:///tmp/two words.txt"); // does not work on OSX 10.2 (does now with %20 space replacement)
  1979. //openURL("\"file:///tmp/two words.txt\""); // does not work on OSX 10.2
  1980. //openURL("\'file:///tmp/two words.txt\'"); // does not work on OSX 10.2
  1981. //openURL("file:///tmp/two%20words.txt"); // works on OSX 10.2, but not Windows 2000
  1982. //openURL("file:///tmp/foo.txt");
  1983. //openURL("file:///tmp/index.html");
  1984. //openURL("file:///tmp/does_not_exist");
  1985. //openURL("file:///zip/About_Developer_Tools.pdf");
  1986. } catch (Exception e) {
  1987. System.err.println(e);
  1988. }
  1989. }
  1990. /** encode the given String in some charset into easily persistable UTF-8 8-bit format */
  1991. public static String encodeUTF(String s) {
  1992. if (s == null) return null;
  1993. try {
  1994. String encoded = new String(s.getBytes("UTF-8"));
  1995. //System.out.println("ENCODED [" + encoded + "]");
  1996. return encoded;
  1997. } catch (java.io.UnsupportedEncodingException e) {
  1998. // should never happen
  1999. e.printStackTrace();
  2000. return s;
  2001. }
  2002. }
  2003. public static String encodeASCII(String s) {
  2004. if (s == null) return null;
  2005. try {
  2006. // unfortunately, this doesn't encode non-ascii chars as % codes, only '?'
  2007. String encoded = new String(s.getBytes("ASCII"));
  2008. return encoded;
  2009. } catch (java.io.UnsupportedEncodingException e) {
  2010. e.printStackTrace();
  2011. return s;
  2012. }
  2013. }
  2014. /** decode the given String in 8-bit UTF-8 to the default java 16-bit unicode format
  2015. (the platform default, which varies) for display */
  2016. public static String decodeUTF(String s) {
  2017. if (s == null) return null;
  2018. try {
  2019. String decoded = new String(s.getBytes(), "UTF-8");
  2020. //System.out.println("DECODED [" + decoded + "]");
  2021. return decoded;
  2022. } catch (java.io.UnsupportedEncodingException e) {
  2023. e.printStackTrace();
  2024. return s;
  2025. }
  2026. }
  2027. private final static String NO_CLASS_FILTER = "";
  2028. private static final StringWriter ExceptionLog = new StringWriter(1024);
  2029. private static final PrintWriter LogPrintWriter = new PrintWriter(ExceptionLog);
  2030. /**
  2031. * @eturn the contents of the exception log. This is not a copy, it's
  2032. * the actual log, so don't modify the contents unless you really mean
  2033. * to.
  2034. */
  2035. public static StringBuffer getExceptionLog() {
  2036. return ExceptionLog.getBuffer();
  2037. }
  2038. /** @return the log writer for anyone else who might want to write to it */
  2039. public static Writer getLogWriter() {
  2040. return LogPrintWriter;
  2041. }
  2042. /** print stack trace items only from fully qualified class names that match the given prefix */
  2043. public static void printClassTrace(Throwable t, String prefix, String message, java.io.PrintStream pst) {
  2044. java.awt.Toolkit.getDefaultToolkit().beep();
  2045. final PrintWriter log = LogPrintWriter;
  2046. synchronized (System.out) {
  2047. synchronized (System.err) {
  2048. synchronized (pst) {
  2049. pst.print(TERM_RED);
  2050. log.println();
  2051. if (message != null) {
  2052. pst.println(message);
  2053. log.println(message);
  2054. }
  2055. final String head;
  2056. if (t.getClass().getName().equals("java.lang.Throwable"))
  2057. head = t.getMessage();
  2058. else
  2059. head = t.toString();
  2060. if (prefix == null || prefix == NO_CLASS_FILTER) {
  2061. pst.println(head + ";");
  2062. log.println(head + ";");
  2063. } else {
  2064. pst.println(head + " (stack element prefix \"" + prefix + "\") ");
  2065. log.println(head + " (stack element prefix \"" + prefix + "\") ");
  2066. }
  2067. final long now = System.currentTimeMillis();
  2068. final String stamp = "\tin " + Thread.currentThread() + " at " + now + " " + new java.util.Date(now);
  2069. pst.print(stamp);
  2070. log.print(stamp);
  2071. //pst.print(TERM_CLEAR);
  2072. if (prefix == null || prefix == NO_CLASS_FILTER)
  2073. prefix = "!tufts.Util.print";
  2074. StackTraceElement[] trace = t.getStackTrace();
  2075. int skipped = 0;
  2076. for (int i = 0; i < trace.length; i++) {
  2077. if (includeInTrace(trace[i], prefix)) {
  2078. pst.print("\n\tat " + trace[i] + " ");
  2079. log.print("\n\tat " + trace[i] + " ");
  2080. } else {
  2081. pst.print(".");
  2082. log.print(".");
  2083. }
  2084. }
  2085. pst.println();
  2086. log.println();
  2087. Throwable cause = t.getCause();
  2088. if (cause != null) {
  2089. //ourCause.printStackTraceAsCause(s, trace);
  2090. pst.print(TERM_RED);
  2091. pst.print(" CAUSE: ");
  2092. log.print(" CAUSE: ");
  2093. pst.print(TERM_CLEAR);
  2094. cause.printStackTrace(pst);
  2095. cause.printStackTrace(log);
  2096. }
  2097. pst.println("END " + t + "\n");
  2098. log.println("END " + t + "\n");
  2099. pst.print(TERM_CLEAR);
  2100. }
  2101. }}
  2102. //System.exit(-1); // e.g.: enable for debugging severe stack overflows
  2103. }
  2104. private static boolean includeInTrace(StackTraceElement trace, String prefix) {
  2105. boolean matchIsIncluded = true;
  2106. if (prefix.charAt(0) == '!') {
  2107. prefix = prefix.substring(1);
  2108. matchIsIncluded = false;
  2109. }
  2110. String where = trace.getClassName() + "." + trace.getMethodName();
  2111. if (where.startsWith(prefix))
  2112. return matchIsIncluded;
  2113. else
  2114. return !matchIsIncluded;
  2115. }
  2116. public static void printClassTrace(Throwable t, String prefix) {
  2117. printClassTrace(t, prefix, null, System.err);
  2118. }
  2119. public static void printClassTrace(String prefix, String message) {
  2120. printClassTrace(new Throwable(message), prefix, null, System.err);
  2121. }
  2122. public static void printClassTrace(String prefix) {
  2123. printClassTrace(prefix, "*** STACK TRACE ***");
  2124. }
  2125. public static void printClassTrace(Class clazz, String message) {
  2126. printClassTrace(clazz.getName(), message);
  2127. }
  2128. public static void printStackTrace() {
  2129. printClassTrace(NO_CLASS_FILTER);
  2130. }
  2131. public static void printStackTrace(Throwable t) {
  2132. printClassTrace(t, NO_CLASS_FILTER, null, System.err);
  2133. }
  2134. public static void printStackTrace(Throwable t, String message) {
  2135. printClassTrace(t, NO_CLASS_FILTER, message, System.err);
  2136. }
  2137. public static void printStackTrace(String message) {
  2138. printClassTrace(new Throwable(message), NO_CLASS_FILTER);
  2139. }
  2140. public static String tag(Object o) {
  2141. if (o == null)
  2142. return "null";
  2143. else
  2144. return String.format("%s@%08x", o.getClass().getName(), System.identityHashCode(o));
  2145. }
  2146. public static String quote(String s) {
  2147. final StringBuilder buf = new StringBuilder(s == null ? 2 : s.length() + 2);
  2148. buf.append('"');
  2149. //buf.append('\u201C');
  2150. ////buf.append('\u201F');
  2151. if (s != null)
  2152. buf.append(s);
  2153. //buf.append('\u201D');
  2154. buf.append('"');
  2155. return buf.toString();
  2156. }
  2157. public static String quote(String s, String color) {
  2158. final StringBuilder buf = new StringBuilder(s == null ? 2 : s.length() + 16);
  2159. buf.append(color);
  2160. buf.append('"');
  2161. if (s != null)
  2162. buf.append(s);
  2163. buf.append('"');
  2164. buf.append(TERM_CLEAR);
  2165. return buf.toString();
  2166. }
  2167. public static String color(String s, String color) {
  2168. if (s == null || s.length() == 0)
  2169. return s;
  2170. final StringBuilder buf = new StringBuilder(s.length() + 16);
  2171. buf.append(color);
  2172. if (s != null)
  2173. buf.append(s);
  2174. buf.append(TERM_CLEAR);
  2175. return buf.toString();
  2176. }
  2177. // special case for strings: we dont care about hashCode / type -- just return quoted
  2178. public static String tags(String s) {
  2179. if (s == null)
  2180. return "null";
  2181. //return quote((String) o);
  2182. return TERM_RED + quote((String)s) + TERM_CLEAR;
  2183. }
  2184. /**
  2185. * Produce a "package.class@idenityHashCode[toString]" debug tag to uniquely identify
  2186. * arbitrary objects. Allows for toString failure, and shortens the output if the
  2187. * toString result already includes the type (class) @ identityHashCode information.
  2188. */
  2189. public static String tags(Object o) {
  2190. if (o == null)
  2191. return "null";
  2192. if (o instanceof java.lang.String) {
  2193. return tags((String) o);
  2194. }
  2195. if (o instanceof java.lang.Number) {
  2196. // special case for strings: we dont care about hashCode / type -- just return quoted
  2197. return o.toString() + " (" + o.getClass().getSimpleName() + ")";
  2198. //return TERM_RED + '"' + o.toString() + '"' + TERM_CLEAR;
  2199. }
  2200. if (o instanceof int[]) {
  2201. int[] ia = (int[]) o;
  2202. return String.format("int[%d]=%s", ia.length, Arrays.toString(ia));
  2203. }
  2204. final String type = o.getClass().getName();
  2205. final String simpleType = o.getClass().getSimpleName();
  2206. final int ident = System.identityHashCode(o);
  2207. String txt = null;
  2208. try {
  2209. if (o instanceof Collection) {
  2210. final int size = ((Collection)o).size();
  2211. txt = "size=" + size;
  2212. final Object item;
  2213. if (size == 0)
  2214. item = null;
  2215. else if (o instanceof java.util.List)
  2216. item = ((java.util.List)o).get(0);
  2217. else
  2218. item = ((Collection)o).toArray()[0];
  2219. if (item != null) {
  2220. if (size == 1)
  2221. txt += "; only=" + tags(item); // note: recursion
  2222. else
  2223. txt += "; first=" + tags(item); // note: recursion
  2224. // if (size == 1)
  2225. // txt += "; " + tags(item);
  2226. // else
  2227. // txt += "type[0]=" + item.getClass().getName();
  2228. }
  2229. }
  2230. else if (o instanceof java.awt.image.BufferedImage) {
  2231. final BufferedImage bi = (BufferedImage) o;
  2232. final int t = bi.getTransparency();
  2233. return String.format("BufferedImage@%08x[%dx%d %s]", ident,
  2234. bi.getWidth(),
  2235. bi.getHeight(),
  2236. transparency(t));
  2237. }
  2238. else if (o instanceof org.w3c.dom.Node) {
  2239. final org.w3c.dom.Node n = (org.w3c.dom.Node) o;
  2240. final Object value = n.getNodeValue();
  2241. if (value == null)
  2242. return String.format("%s@%08x[%s]", simpleType, ident, n.getNodeName());
  2243. else
  2244. return String.format("%s@%08x[%s=%s]", simpleType, ident, n.getNodeName(), tags(n.getNodeValue())); // note: recursion
  2245. }
  2246. else {
  2247. txt = o.toString();
  2248. final String stdShortTag = String.format("%s@%x", simpleType, ident);
  2249. final String stdShortTag0 = String.format("%s@%07x", simpleType, ident);
  2250. final String stdLongTag = String.format("%s@%x", type, ident); // default java object toString
  2251. final String stdLongTag0 = String.format("%s@%07x", type, ident);
  2252. // remove redunant type info from toString:
  2253. if (txt.startsWith(stdLongTag) || txt.startsWith(stdLongTag0)) {
  2254. return txt;
  2255. } else if (txt.startsWith(stdShortTag)) {
  2256. txt = txt.substring(stdShortTag.length());
  2257. } else if (txt.startsWith(stdShortTag0)) {
  2258. txt = txt.substring(stdShortTag0.length());
  2259. } else if (txt.startsWith(simpleType)) {
  2260. txt = txt.substring(simpleType.length());
  2261. } else if (txt.startsWith(type)) {
  2262. txt = txt.substring(type.length());
  2263. }
  2264. }
  2265. } catch (Throwable t) {
  2266. txt = t.toString();
  2267. }
  2268. final String s;
  2269. if (txt.length() > 0) {
  2270. if (txt.length() > 2 && txt.charAt(0) == '[' && txt.charAt(txt.length() - 1) == ']') {
  2271. // skip redundant brackets
  2272. s = String.format("%s@%08x%s", type, ident, txt);
  2273. } else
  2274. s = String.format("%s@%08x[%s]", type, ident, txt);
  2275. } else
  2276. s = String.format("%s@%08x", type, ident);
  2277. return s;
  2278. }
  2279. private static String transparency(int i) {
  2280. switch (i) {
  2281. case Transparency.OPAQUE: return "OPAQUE";
  2282. case Transparency.BITMASK: return "BITMASK";
  2283. case Transparency.TRANSLUCENT: return "HASALPHA";
  2284. }
  2285. return "*UNKOWN-TRANSPARENCY*";
  2286. }
  2287. public static String objectTag(Object o) {
  2288. return tag(o);
  2289. }
  2290. /** @deprecated -- very old -- use String.format with width specifiers instead */
  2291. public static String pad(char c, int wide, String s, boolean alignRight) {
  2292. if (s.length() >= wide)
  2293. return s;
  2294. int pad = wide - s.length();
  2295. StringBuilder buf = new StringBuilder(wide);
  2296. if (alignRight == false)
  2297. buf.append(s);
  2298. while (pad-- > 0)
  2299. buf.append(c);
  2300. if (alignRight)
  2301. buf.append(s);
  2302. return buf.toString();
  2303. }
  2304. public static String pad(char c, int wide, String s) {
  2305. return pad(c, wide, s, false);
  2306. }
  2307. public static String pad(int wide, String s) {
  2308. return pad(' ', wide, s, false);
  2309. }
  2310. public static String toBase2(byte b) {
  2311. StringBuilder buf = new StringBuilder(8);
  2312. buf.append((b & (1<<7)) == 0 ? '0' : '1');
  2313. buf.append((b & (1<<6)) == 0 ? '0' : '1');
  2314. buf.append((b & (1<<5)) == 0 ? '0' : '1');
  2315. buf.append((b & (1<<4)) == 0 ? '0' : '1');
  2316. buf.append((b & (1<<3)) == 0 ? '0' : '1');
  2317. buf.append((b & (1<<2)) == 0 ? '0' : '1');
  2318. buf.append((b & (1<<1)) == 0 ? '0' : '1');
  2319. buf.append((b & (1<<0)) == 0 ? '0' : '1');
  2320. return buf.toString();
  2321. }
  2322. /**
  2323. * For now, this just determines if DNS is available, and assumes that if it is,
  2324. * we have external network access. Ultimately, pinging a known "permanent",
  2325. * high-availability host (e.g., www.google.com), would be somewhat more accurate,
  2326. * (tho also slignly risky, as whatever you pick may in fact someday not respoond)
  2327. * but InetAddress.isReachable is a java 1.5 API call, and VUE isn't built
  2328. * with that yet.
  2329. *
  2330. * TODO: This currently not actually helpful to us: only will tell you if DNS
  2331. * is available the first time this is run in the Java VM (VUE was started),
  2332. * after that, the result is cached.
  2333. */
  2334. public static boolean isInternetReachable() {
  2335. try {
  2336. InetAddress result = InetAddress.getByName("www.google.com");
  2337. return result != null;
  2338. } catch (Throwable t) {
  2339. return false;
  2340. }
  2341. }
  2342. public static void main(String args[])
  2343. throws Exception
  2344. {
  2345. //System.out.println("System.in: " + tags(System.in));
  2346. if (false) {
  2347. openURL(makeQueryURL("MAILTO:foo@foobar.com",
  2348. "subject", "VUE Log Report",
  2349. //"attachment", "c:\\\\foo.txt"
  2350. //,
  2351. "body",
  2352. "I am the body. Spic & Span?"
  2353. + "\nfoo@bar.com"
  2354. + "\nfile://local/file/"
  2355. + "\n\\\\.psf\\foobie\\"
  2356. + "\ncolons:are:no:problem"
  2357. + "\nVUE 2007-06-25 18:32:43,187 [main] INFO Startup; build: June 25 2007 at 1523 by sfraize on Mac OS X 10.4.10 i386 JVM 1.5.0_07-164"
  2358. + "\nVUE 2007-06-25 18:32:43,197 [main] INFO Running in Java VM: 1.5.0_11-b03; MaxMemory(-Xmx)=381.1M, CurMemory(-Xms)=1.9M"
  2359. + "\nVUE 2007-06-25 18:32:43,197 [main] INFO VUE version: 2.0 alpha-x"
  2360. + "\nVUE 2007-06-25 18:32:43,197 [main] INFO Current Working Directory: \\\\.psf\\vue"
  2361. + "\nVUE 2007-06-25 18:32:43,197 [main] INFO User/host: Scott Fraize@null"
  2362. + "\nVUE 2007-06-25 18:32:43,197 [main] DEBUG GUI init"
  2363. + "\nVUE 2007-06-25 18:32:43,257 [main] DEBUG GUI LAF name: Windows"
  2364. + "\nVUE 2007-06-25 18:32:43,257 [main] DEBUG GUI LAF descr: The Microsoft Windows Look and Feel"
  2365. + "\nVUE 2007-06-25 18:32:43,257 [main] DEBUG GUI LAF class: class com.sun.java.swing.plaf.windows.WindowsLookAndFeel"
  2366. + "\nVUE 2007-06-25 18:32:47,523 [main] DEBUG loading disk cache..."
  2367. + "\nVUE 2007-06-25 18:32:47,784 [main] DEBUG Got cache directory: C:\\Documents and Settings\\Scott Fraize\\vue_2\\cache"
  2368. + "\nVUE 2007-06-25 18:32:47,784 [main] DEBUG listing disk cache..."
  2369. + "\nVUE 2007-06-25 18:32:47,784 [main] DEBUG listing disk cache: done; entries=21"
  2370. + "\nVUE 2007-06-25 18:32:47,934 [main] DEBUG loading disk cache: done"
  2371. + "\nVUE 2007-06-25 18:32:48,064 [main] DEBUG loading fonts."
  2372. + "XXXXXXX"
  2373. + "XXXXXXX"
  2374. + "XXXXXXX"
  2375. + "0"
  2376. + "1" // 2064
  2377. + "2" // 2065
  2378. + "\n\nEnd.\n"
  2379. ));
  2380. System.exit(0);
  2381. }
  2382. if (args.length > 0 && "network".equals(args[0])) {
  2383. int tries = 1;
  2384. for (int i = 0; i < tries; i++) {
  2385. if (i > 0)
  2386. Thread.sleep(2000);
  2387. System.err.print("Internet is reachable (DNS available): ");
  2388. System.err.println("" + isInternetReachable());
  2389. }
  2390. Enumeration nie = NetworkInterface.getNetworkInterfaces();
  2391. while (nie.hasMoreElements()) {
  2392. NetworkInterface ni = (NetworkInterface) nie.nextElement();
  2393. System.err.println("\nNetwork Interface[" + ni + "]");
  2394. //Enumeration ie = ni.get
  2395. }
  2396. System.exit(0);
  2397. }
  2398. //System.err.println("ServerSocket: " + new ServerSocket(0)); // not sensitive to network availability
  2399. if (false && args.length > 0 && args[0].startsWith("-")) {
  2400. String host = args[0].substring(1);
  2401. InetAddress[] ips = InetAddress.getAllByName(host);
  2402. System.out.println(host + " IP's: " + Arrays.asList(ips));
  2403. System.exit(0);
  2404. }
  2405. //System.out.println("cursor16 " + java.awt.Toolkit.getDefaultToolkit().getBestCursorSize(16,16));
  2406. //System.out.println("cursor24 " + java.awt.Toolkit.getDefaultToolkit().getBestCursorSize(24,24));
  2407. //System.out.println("cursor32 " + java.awt.Toolkit.getDefaultToolkit().getBestCursorSize(32,32));
  2408. //.list(System.out);
  2409. DEBUG = true;
  2410. // TESTING CODE
  2411. System.out.println("Default JVM character encoding for this platform: " +
  2412. (new java.io.OutputStreamWriter(new java.io.ByteArrayOutputStream())).getEncoding());
  2413. if (args.length > 0 && args[0].equals("-charsets")) {
  2414. Map cs = java.nio.charset.Charset.availableCharsets();
  2415. //System.out.println("Charsets: " + cs.values());
  2416. Iterator i = cs.values().iterator();
  2417. while (i.hasNext()) {
  2418. java.nio.charset.Charset o = (java.nio.charset.Charset) i.next();
  2419. System.out.println(o
  2420. + "\t" + o.aliases()
  2421. //+ " " + o.getClass()
  2422. );
  2423. }
  2424. System.exit(0);
  2425. }
  2426. String test = "file:///Users/sfraize/Desktop/Cup?Chevron.png";
  2427. if (args.length == 1) {
  2428. if ("test".equals(args[0])) {
  2429. execMacOpenURL(test);
  2430. openURL(test);
  2431. } else
  2432. openURL(args[0]);
  2433. //else
  2434. //test_OpenURL();
  2435. } else if (args.length == 2) {
  2436. try {
  2437. // Even tho we tried putting blackships.jar in two different places in java.library.path, it claimed it couldn't find it.
  2438. System.loadLibrary("blackships.jar");
  2439. java.net.URL url = new java.net.URL("blackships/large/02_010b_DutchFamily_l.jpg");
  2440. System.out.println("URL: " + url);
  2441. System.out.println("CONTENT: " + url.getContent());
  2442. // cannot build a file object from a URL
  2443. //java.net.URL url = new java.net.URL("jar:file:/VUE/src/VUE-core.jar!/tufts/vue/images/pathway_hide_on.gif");
  2444. //java.net.URI uri = new java.net.URI(url.toString());
  2445. //java.io.File f = new java.io.File(uri);
  2446. //System.out.println("File " + f + " has length " + f.length() + " exists=" + f.exists());
  2447. } catch (Exception e) {
  2448. e.printStackTrace();
  2449. }
  2450. } else if (args.length == 3) {
  2451. JarFile jar = new JarFile(args[0]);
  2452. System.out.println("Got jar " + jar);
  2453. Enumeration e = jar.entries();
  2454. while (e.hasMoreElements()) {
  2455. JarEntry entry = (JarEntry) e.nextElement();
  2456. long size = entry.getSize();
  2457. System.out.println("Got entry " + entry + " size=" + size);
  2458. if (entry.getComment() != null)
  2459. System.out.println("\tcomment[" + entry.getComment() + "]");
  2460. byte[] extra = entry.getExtra();
  2461. if (extra != null) {
  2462. System.out.println("\textra len=" + extra.length + " [" + extra + "]");
  2463. }
  2464. if (entry.getName().endsWith("MANIFEST.MF")) {
  2465. java.io.InputStream in = jar.getInputStream(entry);
  2466. byte[] data = new byte[(int)size];
  2467. in.read(data);
  2468. System.out.println("Contents[" + new String(data) + "]");
  2469. }
  2470. }
  2471. } else {
  2472. Hashtable props = System.getProperties();
  2473. Enumeration e = props.keys();
  2474. while (e.hasMoreElements()) {
  2475. Object key = e.nextElement();
  2476. //System.out.println("" + key + "=" + props.get(key));
  2477. System.out.println(TERM_PURPLE + key + TERM_CLEAR + " " + props.get(key));
  2478. }
  2479. }
  2480. System.exit(0);
  2481. }
  2482. }