/src/tufts/Util.java
Java | 2943 lines | 2035 code | 399 blank | 509 comment | 382 complexity | 2b4672dcddb0d4a661f9aa9b6c212404 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright 2003-2010 Tufts University Licensed under the
- * Educational Community License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may
- * obtain a copy of the License at
- *
- * http://www.osedu.org/licenses/ECL-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an "AS IS"
- * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
- package tufts;
-
- import java.awt.Color;
- import java.awt.Shape;
- import java.awt.Transparency;
- import java.awt.geom.Point2D;
- import java.awt.geom.Rectangle2D;
- import java.awt.geom.CubicCurve2D;
- import java.awt.geom.QuadCurve2D;
- import java.awt.image.BufferedImage;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import java.io.Writer;
- import java.lang.ref.Reference;
- import java.lang.ref.SoftReference;
- import java.net.InetAddress;
- import java.net.NetworkInterface;
- import java.net.URLEncoder;
- import java.text.BreakIterator;
- import java.util.AbstractList;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.NoSuchElementException;
- import java.util.RandomAccess;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
-
- import javax.swing.JComponent;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JPanel;
- import javax.swing.border.LineBorder;
-
- import tufts.macosx.MacOSX;
-
-
- /**
- * Utility class. Provides code for determining what platform we're on,
- * platform-specific code for opening URL's, as well as various convenience
- * functions.
- *
- * @version $Revision: $ / $Date: $ / $Author: sfraize $
- */
-
- public class Util
- {
- private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(Util.class);
-
- private static boolean WindowsPlatform = false;
- private static boolean MacPlatform = false;
- private static boolean MacAquaLAF = false;
- private static boolean MacAquaLAF_set = false;
- private static boolean UnixPlatform = false;
- private static final String PlatformName;
- private static final String OSVersion;
- private static final boolean OSisMacLeopard;
- private static float javaVersion = 1.0f;
-
- private static int MacMRJVersion = -1;
-
- private static boolean DEBUG = false;
-
- private static String PlatformEncoding;
- private static boolean JVM_is_64_bit;
-
- static {
-
- if (!DEBUG)
- DEBUG = System.getProperty("tufts.Util.debug") != null;
-
- final String osName = System.getProperty("os.name");
- final String osArch = System.getProperty("os.arch");
- OSVersion = System.getProperty("os.version");
- final String javaSpec = System.getProperty("java.specification.version");
-
- final String bits = System.getProperty("sun.arch.data.model");
-
- if (bits.equals("64"))
- JVM_is_64_bit = true;
- else
- JVM_is_64_bit = false;
-
- PlatformName = osName + " " + OSVersion + " " + osArch;
-
- if (DEBUG) out(String.format("Platform: %s / %s / %s", osName, OSVersion, osArch));
- //if (DEBUG) out(String.format("Platform: %s / %s / %s; Leopard=%s", osName, OSVersion, osArch, OSisMacLeopard));
-
- try {
- javaVersion = Float.parseFloat(javaSpec);
- if (DEBUG) out("Java Version: " + javaVersion + "; JVM-bits=" + bits + "; 64bit=" + JVM_is_64_bit);
- } catch (Exception e) {
- errorOut("couldn't parse java.specifcaion.version: [" + javaSpec + "]");
- errorOut(e.toString());
- }
-
- final String osn = osName.toUpperCase();
- /*
- * fix for forums problem. one of the strangest bugs i've seen in a while.
- * something to keep in mind for future, calling toUpperCase() in a
- * locale that uses diacritics will add diacritics to a string that
- * did not originally contain them. so, "windows vista" gets
- * diacritics on the i in both words, the fix is so put the match
- * we're looking for as the lower case word mac and winodws, and call
- * toUpperCase on them so both sides of the comparison are always being
- * processed the same way. note that if you call to upper on a string
- * that is already upper case it does not place in the diacritic characters.
- */
- if (osn.startsWith("mac".toUpperCase())) {
- MacPlatform = true;
- OSisMacLeopard =
- OSVersion.startsWith("10.5") || // Leopard
- OSVersion.startsWith("10.6"); // Snow Leopard
- if (DEBUG) out(String.format("Mac: Leopard/Snow-Leopard=%s", OSisMacLeopard));
- String mrj = System.getProperty("mrj.version");
- int i = 0;
- while (i < mrj.length()) {
- if (!Character.isDigit(mrj.charAt(i)))
- break;
- i++;
- }
-
- try {
- MacMRJVersion = Integer.parseInt(mrj.substring(0, i));
- } catch (NumberFormatException e) {
- errorOut("couldn't parse mrj.version: " + e);
- errorOut(e.toString());
- }
- if (DEBUG) out("Mac mrj.version: \"" + mrj + "\" = " + MacMRJVersion);
-
- } else if (osn.indexOf("windows".toUpperCase()) >= 0) {
- WindowsPlatform = true;
- OSisMacLeopard = false;
- //if (DEBUG) out("Windows Platform: " + PlatformName);
- } else {
- UnixPlatform = true;
- OSisMacLeopard = false;
- }
-
- if (DEBUG) out(String.format("OSFlags: isWin=%b; isMac=%b(leopard=%b); isUnix=%b;", WindowsPlatform, MacPlatform, OSisMacLeopard, UnixPlatform));
-
- String term = System.getenv("TERM");
- boolean allowColor = false;
-
- if (term == null)
- term = "";
-
- allowColor = term.indexOf("color") >= 0;
- if (!allowColor) {
- term = System.getenv("SSH_TERM");
- if (term != null && term.indexOf("color") >= 0)
- allowColor = true;
- }
-
- if (allowColor) {
- TERM_RED = "\033[1;31m";
- TERM_GREEN = "\033[1;32m";
- TERM_YELLOW = "\033[1;33m";
- TERM_BLUE = "\033[1;34m";
- TERM_PURPLE = "\033[1;35m";
- TERM_CYAN = "\033[1;36m";
- TERM_CLEAR = "\033[m";
- } else {
- TERM_RED = TERM_GREEN = TERM_YELLOW = TERM_BLUE = TERM_PURPLE = TERM_CYAN = TERM_CLEAR = "";
- }
- //printStackTrace("TERM[" + term + "]");
- }
-
- /** Common escape codes for terminal text colors. Set to empty string unless on a color terminal */
- public static final String TERM_RED, TERM_GREEN, TERM_YELLOW, TERM_BLUE, TERM_PURPLE, TERM_CYAN, TERM_CLEAR;
-
- private static void out(String s) {
- if (Log.isDebugEnabled())
- Log.debug(s);
- else
- System.out.println("tufts.Util: " + s);
- }
-
- private static void errorOut(String s) {
- System.err.println("tufts.Util: " + s);
- Log.error(s);
- }
-
- public static String formatLines(String target, int maxLength)
- {
- Locale currentLocale = new Locale ("en","US");
-
- return formatLines(target,maxLength,currentLocale);
- }
-
- public static String formatLines(String target, int maxLength,
- Locale locale)
- {
- if (target == null) {
- Log.warn("attempt to line-break null string");
- return null;
- }
-
- try {
- target = breakLines(target, maxLength, locale);
- } catch (Throwable t) {
- Log.error("failed to line-break [" + target + "]; ", t);
- }
-
- return target;
-
- }
-
- public static String maxDisplay(final String s, int len) {
-
- if (s == null)
- return null;
-
- if (len < 4)
- len = 4;
-
- if (s.length() > len) {
- return s.substring(0,len-3) + "...";
- } else {
- return s;
- }
- }
-
- private static String breakLines(final String target, int maxLength, Locale currentLocale)
- {
- final StringBuilder s = new StringBuilder(target.length() + 4);
-
- final BreakIterator boundary = BreakIterator.getLineInstance(currentLocale);
- boundary.setText(target);
-
- int start = boundary.first();
- int end = boundary.next();
- int lineLength = 0;
-
- boolean didBreak = false;
-
- while (end != BreakIterator.DONE) {
- final String word = target.substring(start,end);
-
- lineLength += word.length();
-
- // Log.debug(String.format("len: %2d, word %s%s",
- // lineLength,
- // tags(word),
- // atExistingNewline ? ", @newline" : ""));
-
- if (lineLength >= maxLength) {
-
- final boolean atExistingNewline =
- s.length() > 1 && s.charAt(s.length() - 1) == '\n';
-
- if (!atExistingNewline) {
- //Log.debug("adding newline");
- s.append('\n');
- didBreak = true;
- }
- lineLength = word.length();
- }
-
- //Log.debug("adding word " + tags(word));
- s.append(word);
- start = end;
- end = boundary.next();
- }
- return didBreak ? s.toString() : target;
- }
-
- /*
- * Be sure to compare this value to a constant *float*
- * value -- e.g. "1.4f" -- just "1.4" as double value may
- * actually appear to be less than 1.4, as that can't
- * be exactly represented by a double.
- */
- public static float getJavaVersion() {
- return javaVersion;
- }
-
- /** return mac runtime for java version. Will return -1 if we're not running on mac platform. */
- public static int getMacMRJVersion() {
- return MacMRJVersion;
- }
-
- public static String getPlatformName() {
- return PlatformName == null ? (System.getProperty("os.name") + "?") : PlatformName;
- }
-
- public static String getOSVersion() {
- return OSVersion;
- }
-
- public static boolean isMacLeopard() {
- return OSisMacLeopard;
- }
-
- public static boolean isMacTiger() {
- return MacPlatform && !OSisMacLeopard;
- }
-
-
- /** @return true if we're running on a version Microsoft Windows */
- public static boolean isWindowsPlatform() {
- return WindowsPlatform;
- }
- /** @return true if we're running on an Apple Mac OS */
- public static boolean isMacPlatform() {
- return MacPlatform;
- }
- /** @return true if we're running on unix only platform (e.g., Linux -- Mac OS X not included) */
- public static boolean isUnixPlatform(){
- return UnixPlatform;
- }
-
- /**
- * @return true of Mac Cocoa extensions are supported.
- * Currently only true if running in a 32bit Java 1.5 VM.
- */
- public static boolean isMacCocoaSupported()
- {
- return isMacPlatform() && !JVM_is_64_bit && javaVersion < 1.6;
- }
-
- public static String getDefaultPlatformEncoding() {
- if (PlatformEncoding == null)
- PlatformEncoding = (new java.io.OutputStreamWriter(new java.io.ByteArrayOutputStream())).getEncoding();
- return PlatformEncoding;
- }
-
-
- /** @return true if the current Look & Feel is Mac Aqua (not always true just because you're on a mac)
- * Note: do NOT call this from any static initializers the result may be changed by application startup
- * code. */
- public static boolean isMacAquaLookAndFeel()
- {
- // we can't set this at static init time because the LAF can be set after that
- if (MacAquaLAF_set == false) {
- MacAquaLAF =
- isMacPlatform() &&
- javax.swing.UIManager.getLookAndFeel().getName().toLowerCase().indexOf("aqua") >= 0;
- MacAquaLAF_set = true;
- }
- return MacAquaLAF;
- }
-
- /** @param url -- a url assumed to be in the platform default format (e.g., it may be
- * formatted in a way only understood on the current platform).
- */
- public static void openURL(String url)
- throws java.io.IOException
- {
- // TODO: isLocalFile should check for inital '\' also (File.separator) -- but follow-on code will now need re-testing
- boolean isLocalFile = (url.length() >= 5 && "file:".equalsIgnoreCase(url.substring(0,5))) || url.startsWith("/");
- boolean isMailTo = url.length() >= 7 && "mailto:".equalsIgnoreCase(url.substring(0,7));
-
- if (DEBUG) System.err.println("openURL_PLAT [" + url + "] isLocalFile=" + isLocalFile + " isMailTo=" + isMailTo);
-
- if (isMacPlatform())
- openURL_Mac(url, isLocalFile, isMailTo);
- else if (isUnixPlatform())
- openURL_Unix(url, isLocalFile, isMailTo);
- else // default is a windows platform
- openURL_Windows(url, isLocalFile, isMailTo);
- }
-
- private static final String PC_OPENURL_CMD = "rundll32 url.dll,FileProtocolHandler";
- private static void openURL_Windows(String url, boolean isLocalFile, boolean isMailTo)
- throws java.io.IOException
- {
- System.err.println("openURL_Win [" + url + "]");
-
- // On at least Windows 2000, %20's don't work when given to url.dll FileProtocolHandler
- // (Should be using some kind of URLProtocolHanlder ?)
-
- // Also at least Win2K: file:///C:/foo/bar.html works, but start that with file:/ or file://
- // and it DOES NOT work -- you MUST have the three slashes, OR, you can have NO SLASHES,
- // and it will work... (file:C:/foo/bar.html)
- // ALSO, file:// or // file:/// works BY ITSELF (file:/ by itself still doesn't work).
-
- //url = url.replaceAll("%20", " ");
-
- if (!isMailTo) {
- url = decodeURL(url);
- url = decodeURL(url); // run twice in case any %2520 double encoded spaces
- }
-
- if (isLocalFile) {
- // below works, but we're doing a full conversion to windows path names now
- //url = url.replaceFirst("^file:/+", "file:");
- url = url.replaceFirst("^file:/+", "");
- url = url.replace('/', '\\');
- System.err.println("openURL_patch[" + url + "]");
- char c1 = 0;
- try { c1 = url.charAt(1); } catch (StringIndexOutOfBoundsException e) {}
- if (c1 == ':' || c1 == '|') {
- // Windows drive letter specification, e.g., "C:".
- // Also, I've seen D|/dir/file.txt in a shortcut file, so we allow that too.
- // In any case, we do noting: this string should be workable to url.dll
- } else {
-
- if (url.startsWith("file:")) {
- // DO NOTHING.
- // If we had "file:" above and NOT "file:/", we need this check here.
- // This suggests this code needs refactoring. SMF 2008-04-02
- } else {
- // if this does NOT start with a drive specification, assume
- // the first component is a host for a windows network
- // drive, and thus we have to pre-pend \\ to it, to get \\host\file
- url = "\\\\" + url;
- }
- }
- // at this point, "url" is really just a local windows file
- // in full windows syntax (backslashes, drive specs, etc)
- System.err.println("openURL_WinLF[" + url + "]");
- }
-
- String cmd = PC_OPENURL_CMD + " " + url;
- final int sizeURL = url.length();
- final int sizeCommand = cmd.length();
- final int sizeWinArgs = sizeCommand - 17; // subtract "rundll32 url.dll,"
- boolean debug = DEBUG;
- if (sizeURL > 2027 || sizeCommand > 2064 || sizeWinArgs >= 2048) {
- System.err.println("\nWarning: WinXP buffer lengths likely exceeded: command not likely to run (arglen=" + sizeWinArgs + ")");
- debug = true;
- } else {
- System.err.println();
- }
- if (debug) {
- System.err.println("exec url length: " + sizeURL);
- System.err.println("exec command length: " + sizeCommand);
- System.err.println("exec url.dll args len: " + sizeWinArgs);
- }
-
- if (sizeCommand > 2064) {
- System.err.println("exec: truncating command and hoping for the best...");
- cmd = cmd.substring(0,2063);
- }
-
- System.err.println("exec[" + cmd + "]");
-
- Runtime.getRuntime().exec(cmd);
-
- // final String mailto = "mailto:"
- // + "foo@bar.com?"
- // + "subject=TestSubject"
- // + "&attachment="
- // //+ "&Attach="
- // + "\""
- // + "c:\\\\foo.txt"
- // + "\""
- // ;
- // System.err.println("MAILTO: ["+mailto+"]");
- // Runtime.getRuntime().exec(new String[] {"rundll32", "url.dll,FileProtocolHandler", mailto
- // "mailto:"
- // + "&subject=TestSubject"
- // + "&attachment=" + "\"" + "c:\\\\foo.txt" + "\""
- // },
- // null);
-
-
- // if (false) {
- // Process p = Runtime.getRuntime().exec(cmd);
- // try {
- // System.err.println("waiting...");
- // p.waitFor();
- // } catch (Exception ex) {
- // System.err.println(ex);
- // }
- // System.err.println("exit value=" + p.exitValue());
- // }
- }
-
- /**
- * Call a named static method with the given args.
- * The method signature is inferred from the argument types. We map the primitive
- * type wrapper class to their primitive types (an auto un-boxing), so this
- * won't work for method calls that take args of Boolean, Integer, etc,
- * only boolean, int, etc.
- */
- public static Object execute(Object object, String className, String methodName, Object[] args)
- throws ClassNotFoundException,
- NoSuchMethodException,
- IllegalArgumentException,
- IllegalAccessException,
- java.lang.reflect.InvocationTargetException
- {
- if (DEBUG) {
- // use multiple prints in remote case of a class-load or some such error along the way
- System.err.println("Util.execute:");
- System.err.println("\t className: [" + className + "]");
- System.err.println("\tmethodName: [" + methodName + "]");
-
- String desc;
- if (args == null)
- desc = "null";
- else if (args.length == 0)
- desc = "(none)";
- else if (args.length == 1)
- desc = objectTag(args[0]) + " [" + args[0] + "]";
- else
- desc = Arrays.asList(args).toString();
-
- System.err.println("\t args: " + desc);
- System.err.println("\t object: " + objectTag(object) + " [" + object + "]");
-
- }
-
- final Class clazz = Class.forName(className);
- final Class[] argTypes;
-
- if (args == null) {
- argTypes = null;
- } else {
- argTypes = new Class[args.length];
- for (int i = 0; i < args.length; i++) {
- final Class argClass = args[i].getClass();
- if (argClass == Boolean.class) argTypes[i] = Boolean.TYPE;
- else if (argClass == Integer.class) argTypes[i] = Integer.TYPE;
- else if (argClass == Long.class) argTypes[i] = Long.TYPE;
- else if (argClass == Short.class) argTypes[i] = Short.TYPE;
- else if (argClass == Float.class) argTypes[i] = Float.TYPE;
- else if (argClass == Double.class) argTypes[i] = Double.TYPE;
- else if (argClass == Byte.class) argTypes[i] = Byte.TYPE;
- else if (argClass == Character.class) argTypes[i] = Character.TYPE;
- else
- argTypes[i] = args[i].getClass();
- }
- }
-
- java.lang.reflect.Method method = clazz.getMethod(methodName, argTypes);
-
- if (DEBUG) System.err.print("\t invoking: " + method + " ... ");
-
- Object result = method.invoke(object, args);
-
- if (DEBUG) System.err.println("returned.");
-
- if (DEBUG && method.getReturnType() != void.class) {
- // use multiple prints in remote case of a class-load or some such error along the way
- //System.err.println("Util.execute:");
- System.err.println("\t return: " + objectTag(result) + " [" + result + "]");
- }
- //System.out.println("Sucessfully invoked " + className + "." + methodName + ", result=" + result);
-
- return result;
- }
-
- public static Object execute(String className, String methodName, Object[] args)
- throws ClassNotFoundException,
- NoSuchMethodException,
- IllegalArgumentException,
- IllegalAccessException,
- java.lang.reflect.InvocationTargetException
- {
- return execute(null, className, methodName, args);
- }
-
- /** Attempt a method call. If it fails, quietly fail, printing a stack trace and returning null.
- * @param object - cannot be null (implying a static method), as is also used to get the class name
- * If object is a Class object, make this a static invocation in that class.
- */
- public static Object invoke(Object object, String methodName, Object[] args)
- {
- String className;
- if (object instanceof Class) {
- className = ((Class)object).getName();
- object = null;
- } else
- className = object.getClass().getName();
-
- try {
- return execute(object, className, methodName, args);
- } catch (Exception e) {
- e.printStackTrace();
- return e;
- }
- }
-
- /**
- * Attempt a method call. If it fails, quietly fail, printing a stack trace and returning null.
- * This is a convenience version that allows the passing in of a single argument directly.
- **/
- public static Object invoke(Object object, String methodName, Object arg0) {
- return invoke(object, methodName, new Object[] { arg0 });
- }
- public static Object invoke(Object object, String methodName) {
- return invoke(object, methodName, null);
- }
-
- /**
- * Attempt to invoke the given method with the given args. If
- * any exception occurs, (e.g., ClassNotFoundException because a
- * particular library isn't present) we quietly catch it and
- * pass it back as the return value;
- */
-
- public static Object executeIfFound(String className, String methodName, Object[] args) {
- try {
- return execute(className, methodName, args);
- } catch (Exception e) {
- return e;
- }
- }
-
- /** Encode a query pair URL such that it will work with the current platform openURL code.
- * E.g., construct a mailto: whose subject/body args are encoded such that they successfully
- * pass through to the local mail client.
- */
- public static String makeQueryURL(String urlStart, String ... nameValuePairs) {
-
- StringBuffer url = new StringBuffer(urlStart);
-
- boolean isKey = true;
- boolean isFirstKey = true;
- String curKey = "<no-key!>";
- for (String s : nameValuePairs) {
- //System.out.format("TOKEN[%s]\n", s);
- if (isKey) {
- if (isFirstKey) {
- url.append('?');
- isFirstKey = false;
- } else
- url.append('&');
- curKey = s;
- System.out.format("KEY[%s]\n", s);
- url.append(s);
- url.append('=');
- } else if ("attachment".equals(curKey)) {
- // append windows pathname raw:
- // An "attachment" arg has been rumoured to work on Windows,
- // but as far as I can tell, these rumours are total BS.
- // Have yet to see this work in any configuration.
- url.append('"' + s + '"');
- } else {
- // value field:
- final String encodedValue = encodeURLData(s);
- if (DEBUG) {
- System.out.format(" %-17s [%s]\n", curKey + "(RAW):", s);
- System.out.format(" %-17s [%s]\n", curKey + "(ENCODED):", encodedValue);
- }
- url.append(encodedValue);
- }
- isKey = !isKey;
-
- }
- //if (DEBUG) System.out.println("QUERY URL: " + url);
- return url.toString();
- }
-
- public static String encodeURLData(String url) {
- try {
- url = URLEncoder.encode(url, "UTF-8");
- url = url.replaceAll("\\+", "%20"); // Mail clients don't understand '+' as space
- } catch (Throwable t) {
- // should never happen:
- printStackTrace(t);
- }
- return url;
- }
-
-
-
- // GAK! Move this code to URLResource, as it's going to have to be smart
- // about local file drops for mac URL's, to be sure to UTF-8 DECODE them
- // first, so we get RID of special characters or spaces, which come
- // when the local file was dragged Safari, as opposed to the Finder
- // (e.g., Desktop), which already decodes them for us.
-
- // Also, we need to generically handle the decoding of ":" into "/"
- // for these URL's. (God forbid there is HTML in the name: e.g. <i>foo</i>
- // will send us a ':' in place of the '/', which we also don't
- // want to mistake for a protocol below. Actually, do fix the ':'
- // in the display name (title), but not raw meta-data: could be confusing.
-
-
- private static java.lang.reflect.Method macOpenURL_Method = null;
- private static void openURL_Mac(String url, boolean isLocalFile, boolean isMailTo)
- {
- //if (DEBUG) System.err.println("openURL_Mac0 [" + url + "]");
- System.err.println("openURL_Mac0 [" + url + "], isLocal=" + isLocalFile);
-
- if (isLocalFile) {
- boolean changed = true;
- if (url.startsWith("file:////")) {
- // don't think we have to do this, but just in case
- // (was getting a complaint and couldn't tell if this was why or not,
- // so now we won't see it)
- url = "file:///" + url.substring(9);
- } else if (url.startsWith("/")) {
- // must have file: at head to be sure it works on mac
- url = "file:" + url;
- } else
- changed = false;
- if (DEBUG && changed) System.err.println("openURL_Mac1 [" + url + "]");
- }
-
- if (isMailTo) {
- // final String flatURL = url.toLowerCase();
- // final int queryIndex = flatURL.indexOf('?') + 1;
- // if (queryIndex > 1) {
- // final String query = flatURL.substring(queryIndex);
- // if (DEBUG) System.out.println("QUERY: [" + query + "]");
- // final int subjectIndex = query.indexOf("subject=");
- // }
-
- //url = url.replaceAll(" ", "%20");
- // try {
- // url = URLEncoder.encode(url, "UTF-8");
- // } catch (Throwable t) {
- // printStackTrace(t);
- // }
- } else {
- try {
- url = encodeSpecialChars_Mac(url, isMailTo);
- } catch (Throwable t) {
- printStackTrace(t);
- }
- }
-
- // In Mac OS X, local files MUST have %20 and NO spaces in the URL's -- reverse of Windows.
- // But enforcing this for regular HTTP URL's breaks them: turns existing %20's into %2520's
-
- // If no protocol in the URL string, assume it's a pathname. Normally, there
- // would be nothing to do as openURL handles that fine on MacOSX, unless it's
- // not absolute, it which case we make it absolute by assuming the users home
- // directory.
-
- if (!isMailTo && url.indexOf(':') < 0 && !url.startsWith("/")) {
- // Hack to make relative references relative to user home directory. OSX
- // won't default to use current directory for a relative references, so
- // we're prepending the home directory manually as a bail out try-for-it.
- url = "file://" + System.getProperty("user.home") + "/" + url;
- if (DEBUG) System.err.println(" OUM HOME [" + url + "]");
- }
-
- execMacOpenURL(url);
- }
-
- // WHAT WE KNOW WORKS FOR MAILTO: '@' encoded, but ? / & decoded, except WITHIN
- // the value of &field=value, which of course messes it up.
- // Also in the working state: All spaces as %20, newlines %0A
- // If we take out the colons tho, we're screwed.
-
- private static String encodeSpecialChars_Mac(String url, boolean isMailTo)
- throws java.io.IOException
- {
- // if (url.indexOf('%') >= 0) {
-
- // // If we were to make sure we're always handed URI's (at
- // // least on the mac) this would prevent accidentally
- // // decoding actual '+' characters in the file-name,
- // // as they strings would already come with %20 for spaces.
-
- // // However, if there was a special (e.g. Unicode) character
- // // anywhere in the string, we would still need to encode it,
- // // but then we'd have to determine if the '+' we see at this
- // // point is from the URLEncoder, or from the real File name.
- // // Eventually, this Util code should take a real File object
- // // so we can be more sure about what we're doing in these
- // // corner cases.
-
- // if (DEBUG) System.err.println(" NO-CLEANUP [" + url + "]");
- // return url;
- // }
-
- // In case there are any special characters (e.g., Unicode chars) in the
- // file name, we must first encode them for MacOSX (local files only?)
- // FYI, MacOSX openURL uses UTF-8, NOT the native MacRoman encoding.
- // URLEncoder encodes EVERYTHING other than alphas tho, so we need
- // to put it back.
-
- // Note: using the less intense encoding of URI's may make this simpler
-
- if (url.indexOf('%') >= 0) {
- // DECODE it, in case there are already any encodings,
- // we don't want to double-encode.
- url = java.net.URLDecoder.decode(url, "UTF-8");
- if (DEBUG) System.err.println(" DECODE UTF [" + url + "]");
- }
-
- url = java.net.URLEncoder.encode(url, "UTF-8"); // URLEncoder is way overzealous...
- if (DEBUG) System.err.println(" ENCODE UTF [" + url + "]");
-
- // now decode the over-coded stuff -- these are all crucial characters
- // that must be present...
- url = url.replaceAll("%3A", ":");
- url = url.replaceAll("%2F", "/");
- url = url.replaceAll("%3F", "?");
- url = url.replaceAll("%3D", "=");
- url = url.replaceAll("%26", "&");
-
- // Mac doesn't undestand '+' means ' ' in it's openURL support method:
- // url = url.replace('+', ' '); // nor does it understand actual spaces
- url = url.replaceAll("\\+", "%20");
-
- if (DEBUG) System.err.println(" CLEANUP [" + url + "]");
-
- return url;
- }
-
- private static void execMacOpenURL(String url)
- {
- if (isMacLeopard()) {
- final String cmd = "/usr/bin/open";
- try {
- if (DEBUG) System.err.println(" Leopard: " + cmd + " " + url);
- Runtime.getRuntime().exec(new String[]{ cmd, url });
- } catch (Throwable t) {
- printStackTrace(t, cmd + " " + url);
- }
- } else if (getJavaVersion() >= 1.4f) {
- // Can't call this directly because wont compile on the PC
- //com.apple.eio.FileManager.openURL(url);
-
- if (macOpenURL_Method == null) {
- try {
- Class macFileManager = Class.forName("com.apple.eio.FileManager");
- //Class macFileManager = ClassLoader.getSystemClassLoader().loadClass("com.apple.eio.FileManager");
- macOpenURL_Method = macFileManager.getMethod("openURL", new Class[] { String.class });
- } catch (Exception e) {
- System.err.println("Failed to find Mac FileManager or openURL method: will not be able to display URL content.");
- e.printStackTrace();
- throw new UnsupportedOperationException("com.apple.eio.FileManager:openURL " + e);
- }
- }
-
- if (macOpenURL_Method != null) {
- try {
- macOpenURL_Method.invoke(null, new Object[] { url });
- } catch (Exception e) {
- e.printStackTrace();
- throw new UnsupportedOperationException("com.apple.eio.FileManager.openURL " + e);
- }
- } else
- throw new UnsupportedOperationException("openURL_Mac");
-
-
- } else {
- throw new UnsupportedOperationException("mac java <= 1.3 openURL unimplemented");
- // put this back if want to suppor mac java 1.3
- // this has been deprecated in mac java 1.4, so
- // just ignore the warning if using a 1.4 or beyond
- // compiler
- // com.apple.mrj.MRJFileUtils.openURL(url);
- }
-
- if (DEBUG) System.err.println("execMacOpenURL returns for (" + url + ")");
-
- }
-
- private static boolean HasGnomeOpen = false;
- private static boolean GnomeOpenSet = false;
-
- private static void openURL_Unix(String url, boolean isLocalFile, boolean isMailTo)
- throws java.io.IOException
- {
- // For now we just assume Netscape is installed.
-
- // todo: run down list of netscape, mozilla, konqueror (KDE
- // browser), gnome version? KDE/Gnome may have their own
- // services for getting a default browser.
-
- /*
- The problem I had with my 2 linux installations was that even though netscape wasn't
- installed the distribution provided a symlink named netscape which pointed to firefox
- however firefox couldn't interpet the netscape parameters. So below I've modified it
- to try to load firefox first and then if that fails load netscape, i suppose konqueror
- should be in the mix too maybe but this is better than it was and catches alot of cases.
- */
-
- final Runtime runtime = Runtime.getRuntime();
- Process process = null;
- int waitFor = -1;
-
- if (!GnomeOpenSet) {
-
- // test for gnome
- try {
- process = runtime.exec("gnome-open");
- waitFor = process.waitFor();
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- catch (IOException ioe2) {
- ioe2.printStackTrace();
- waitFor = 2;
- }
-
- GnomeOpenSet = true;
- if (waitFor != 2)
- HasGnomeOpen = true;
- }
-
- if (HasGnomeOpen) {
- //open file with gnome
- if (isLocalFile) {
- url = decodeURL(url);
-
- // SMF 2008-04-30: commented this out: was ensuring that most
- // local file links would not work -- not sure what cases
- // this was handling.
- //
- //url = "file:///" + url.substring(6);
-
- // old:
- ////jjurl = url.replaceAll(" ","\\ ");
- ////url ="\""+url+"\"";
- }
-
- Log.info("gnome-open " + url);
-
- process = runtime.exec(new String[] {"gnome-open" , url});
- // out("process: " + process);
- InputStream stdin = process.getErrorStream();
- InputStreamReader isr = new InputStreamReader(stdin);
- BufferedReader br = new BufferedReader(isr);
- String line = null;
- System.out.println("<OUTPUT>");
- while ((line = br.readLine()) != null)
- System.out.println(line);
- System.out.println("<OUTPUT>");
- try
- {
- int exitVal = process.waitFor();
- System.out.println("exit val : " + exitVal);
- }
- catch(InterruptedException inte)
- {
- inte.printStackTrace();
- }
- return;
- }
- else
- waitFor=-1;
-
-
- // kde
- try
- {
- System.out.println("TESTING KDE");
- process =runtime.exec("kfmexec");
- waitFor = process.waitFor();
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- catch (IOException ioe2)
- {
- ioe2.printStackTrace();
- waitFor=2;
-
- }
-
- if (waitFor != 2)
- {
- if (isLocalFile)
- {
- url = decodeURL(url);
- //jjurl = url.replaceAll(" ","\\ ");
- url = "file:///" + url.substring(6);
- //url ="\""+url+"\"";
- System.out.println(url);
- }
- //open file with kde
- process = runtime.exec(new String[] { "kfmclient","exec", url});
- InputStream stdin = process.getErrorStream();
- InputStreamReader isr = new InputStreamReader(stdin);
- BufferedReader br = new BufferedReader(isr);
- String line = null;
- System.out.println("<OUTPUT>");
- while ((line = br.readLine()) != null)
- System.out.println(line);
- System.out.println("<OUTPUT>");
-
- System.out.println("<OUTPUT2>");
- stdin=process.getInputStream();
- isr = new InputStreamReader(stdin);
- br = new BufferedReader(isr);
- line = null;
-
- while ((line = br.readLine()) != null)
- System.out.println(line);
- System.out.println("<OUTPUT2>");
- try
- {
- int exitVal = process.waitFor();
- System.out.println("exit val : " + exitVal);
- }
- catch(InterruptedException inte)
- {
- inte.printStackTrace();
- }
- return;
- }
-
-
-
-
-
- //if (waitFor == 2)
- try
- {
- process = runtime.exec(new String[] { "firefox", url});
- waitFor = process.waitFor();
- System.out.println("WAIT FOR : " + waitFor);
- }
- catch (java.io.IOException ioe3)
- {
- //firefox not available try netscape instead.
- process = Runtime.getRuntime().exec(new String[] { "netscape",
- "-remove",
- "'openURL('" + url + "')" });
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- out("process: " + process);
-
- }
-
- /**
- * Execute the given system command (arg0 is command, subsequent args are command arguments).
- * @param runDirectory -- if non-null, the directory to run the command in.
- *
- * The current impl will only return up to the first 256 chars of output, and will
- * use String.trim on it, to remove any trailing newline.
- *
- * @see java.lang.Runtime
- */
-
- public static String getSystemCommandOutput(String[] args, String runDirectory)
- {
- String output = null;
-
- try {
- File dir = null;
- if (runDirectory != null) {
- try {
- dir = new File(runDirectory);
- } catch (Throwable t) {
- printStackTrace(t, "Warning: couldn't create file from: " + runDirectory);
- }
- }
-
- Log.info("exec " + args[0] + ": " + Arrays.asList(args) + " in dir " + dir + " (" + runDirectory + ")");
-
- final Process proc = Runtime.getRuntime().exec(args, null, dir);
- final java.io.InputStream stream = proc.getInputStream();
- final byte[] buf = new byte[256];
- final int got = stream.read(buf);
-
- output = new String(buf, 0, got).trim();
- Log.debug("exec " + args[0] + ": got output[" + output + "]");
- } catch (Throwable t) {
- printStackTrace(t, "getSystemCommandOutput");
- }
-
- return output;
- }
-
-
- /**
- * Fast impl of replacing %xx hexidecimal codes with actual characters (e.g., %20 is a space, %2F is '/').
- * Leaves untouched any bad hex digits, or %xx strings that represent control characters (less than space/0x20
- * or greater than tilde/0x7E).
- *
- * @return String with replaced %xx codes. If there are no '%' characters in the input string,
- * the original String object is returned.
- */
- public static String decodeURL(final String s)
- {
- //System.out.println("DECODING " + s);
- int i = s.indexOf('%');
- if (i < 0)
- return s;
- final int len = s.length();
- final StringBuffer buf = new StringBuffer(len);
- // copy in everything we've skipped in the original string up to now
- buf.append(s.substring(0, i));
- //System.out.println("DECODE START " + buf);
- for ( ; i < len; i++) {
- final char c = s.charAt(i);
- if (c == '%' && i+2 < len) {
- final int hex1 = Character.digit(s.charAt(++i), 16);
- final int hex2 = Character.digit(s.charAt(++i), 16);
- final char charValue = (char) (hex1 * 16 + hex2);
-
- //System.out.println("Got char value " + charValue + " from " + c1 + c2);
-
- if (hex1 < 1 || hex2 < 0 || charValue < 0x20 || charValue > 0x7E) {
- // Pass through untouched if not two good hex characters (and first can't be 0),
- // or if result is a control character (anything less than space, or greater than '~')
- buf.append('%');
- buf.append(s.charAt(i-1));
- buf.append(s.charAt(i));
- } else {
- buf.append(charValue);
- }
- } else {
- buf.append(c);
- }
- }
- if (DEBUG) {
- System.out.println("DECODED [" + s + "]");
- System.out.println(" TO [" + buf + "]");
- }
- return buf.toString();
- }
-
- public static final Iterator EmptyIterator = new EmptyIterable();
- public static final Iterable EmptyIterable = (Iterable) EmptyIterator;
-
- private static final class EmptyIterable implements java.util.Iterator, java.lang.Iterable {
- public boolean hasNext() { return false; }
- public Object next() { throw new NoSuchElementException(); }
- public void remove() { throw new UnsupportedOperationException(); }
- public String toString() { return "EmptyIterator"; }
- public Iterator iterator() { return this; }
- }
-
- public interface Itering<T> extends java.util.Iterator<T>, Iterable<T> {}
-
- public static abstract class AbstractItering<T> implements Itering<T> {
- public Iterator<T> iterator() {
- return this;
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
- private static abstract class IndexedItering<T> extends AbstractItering<T> {
- final int length;
- int index = 0;
- IndexedItering(int len) { length = len; }
- public boolean hasNext() {
- return index < length;
- }
- // could reset index if another "instance" is requested via iterator()
- }
-
- public static <T> Itering<T> iterable(T o) {
- return new SingletonIterable<T>(o);
- }
-
- public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.NodeList nl) {
- return new IndexedItering<org.w3c.dom.Node>(nl.getLength()) {
- public org.w3c.dom.Node next() {
- return nl.item(index++);
- }
- };
- }
- public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.NamedNodeMap nm) {
- return new IndexedItering<org.w3c.dom.Node>(nm.getLength()) {
- public org.w3c.dom.Node next() {
- return nm.item(index++);
- }
- };
- }
-
- public static Itering<org.w3c.dom.Node> iterable(final org.w3c.dom.Node n) {
- return iterable(n.getChildNodes());
- }
-
-
-
- /** Convenience class: provides a single element iterator. Is also an iterable, returning self.
- * Each request for an iterable resets us to be iterated again (not threadsafe) */
- private static final class SingletonIterable<T> implements Itering<T> {
- private final T object;
- private boolean done;
- public SingletonIterable(T o) {
- object = o;
- }
- public boolean hasNext() { return !done; }
- public T next() { if (done) throw new NoSuchElementException(); done = true; return object; }
- public void remove() { throw new UnsupportedOperationException(); }
- public Iterator<T> iterator() { done = false; return this; }
- public String toString() { return "[" + object + "]"; }
-
- };
-
-
-
- public static <T> List<T> asList(T[] array) {
- return new ExposedArrayList(array);
- }
-
- public static <T> T[] toArray(Collection<? extends T> bag, Class<T> clazz) {
- // return (T[]) bag.toArray(); class cast exception
- // can't create a new instance of the array w/out a known type -- unreliable to pull from collection (and could be empty)
- //return bag.toArray((T[])java.lang.reflect.Array.newInstance(?.getClass(), bag.size()));
- return bag.toArray((T[])java.lang.reflect.Array.newInstance(clazz, bag.size()));
- }
-
- /**
- * Identical to Arrays.asList, except that toArray() returns the internal array,
- * which allows for Collection.addAll(ExposedArrayList) to be used w/out triggering an array clone
- */
- private static final class ExposedArrayList<E> extends AbstractList<E>
- implements RandomAccess
- {
- private final Object[] a;
-
- ExposedArrayList(E[] array) {
- if (array == null) throw new NullPointerException();
- a = array;
- }
-
- @Override
- public int size() { return a.length; }
-
- /** returns the internal array -- allows for Collection.addAll(ExposedArrayList) to be called w/out triggering a clone */
- @Override
- public Object[] toArray() { return a; }
-
- @Override
- public E get(int index) { return (E)a[index]; }
-
- @Override
- public E set(int index, E element) {
- Object oldValue = a[index];
- a[index] = element;
- return (E)oldValue;
- }
-
- @Override
- public int indexOf(Object o) {
- if (o==null) {
- for (int i=0; i<a.length; i++)
- if (a[i]==null)
- return i;
- } else {
- for (int i=0; i<a.length; i++)
- if (o.equals(a[i]))
- return i;
- }
- return -1;
- }
-
- @Override
- public boolean contains(Object o) {
- return indexOf(o) != -1;
- }
- }
-
- private static final class SkipNullsArrayList<T> extends ArrayList<T> {
- SkipNullsArrayList() {}
-
- @Override
- public boolean add(T c) {
- if (c == null) {
- //Util.printStackTrace("null not allowed");
- } else {
- super.add(c);
- }
- return true;
- }
- }
-
- public stat…
Large files files are truncated, but you can click here to view the full file