| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache 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.apache.org/licenses/LICENSE-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 org.openide.util; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.lang.ref.ReferenceQueue; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.nio.file.InvalidPathException; |
| import java.nio.file.Paths; |
| import java.text.BreakIterator; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.TreeSet; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.lang.model.SourceVersion; |
| import org.openide.util.lookup.implspi.ActiveQueue; |
| |
| /** |
| * General purpose utility methods. |
| * |
| * @author Jan Palka, Ian Formanek, Jaroslav Tulach |
| */ |
| public abstract class BaseUtilities { |
| private static final Logger LOG = Logger.getLogger(BaseUtilities.class.getName()); |
| |
| /** Operating system is Windows NT. */ |
| public static final int OS_WINNT = 1/* << 0*/; |
| |
| /** Operating system is Solaris. */ |
| public static final int OS_SOLARIS = OS_WINNT << 1; |
| |
| /** Operating system is Linux. */ |
| public static final int OS_LINUX = OS_SOLARIS << 1; |
| |
| /** Operating system is HP-UX. */ |
| public static final int OS_HP = OS_LINUX << 1; |
| |
| /** Operating system is IBM AIX. */ |
| public static final int OS_AIX = OS_HP << 1; |
| |
| /** Operating system is SGI IRIX. */ |
| public static final int OS_IRIX = OS_AIX << 1; |
| |
| /** Operating system is Sun OS. */ |
| public static final int OS_SUNOS = OS_IRIX << 1; |
| |
| /** Operating system is Compaq TRU64 Unix */ |
| public static final int OS_TRU64 = OS_SUNOS << 1; |
| |
| /** @deprecated please use OS_TRU64 instead */ |
| @Deprecated |
| public static final int OS_DEC = OS_TRU64 << 1; |
| |
| /** Operating system is OS/2. */ |
| public static final int OS_OS2 = OS_DEC << 1; |
| |
| /** Operating system is Mac. */ |
| public static final int OS_MAC = OS_OS2 << 1; |
| |
| /** Operating system is Windows 2000. */ |
| public static final int OS_WIN2000 = OS_MAC << 1; |
| |
| /** Operating system is Compaq OpenVMS */ |
| public static final int OS_VMS = OS_WIN2000 << 1; |
| |
| /** |
| *Operating system is one of the Windows variants but we don't know which |
| *one it is |
| */ |
| public static final int OS_WIN_OTHER = OS_VMS << 1; |
| |
| /** Operating system is unknown. */ |
| public static final int OS_OTHER = OS_WIN_OTHER << 1; |
| |
| /** Operating system is FreeBSD |
| * @since 4.50 |
| */ |
| public static final int OS_FREEBSD = OS_OTHER << 1; |
| |
| /** Operating system is Windows Vista. |
| * @since 7.17 |
| */ |
| public static final int OS_WINVISTA = OS_FREEBSD << 1; |
| |
| /** Operating system is one of the Unix variants but we don't know which |
| * one it is. |
| * @since 7.18 |
| */ |
| public static final int OS_UNIX_OTHER = OS_WINVISTA << 1; |
| |
| /** Operating system is OpenBSD. |
| * @since 7.18 |
| */ |
| public static final int OS_OPENBSD = OS_UNIX_OTHER << 1; |
| |
| /** A mask for Windows platforms. |
| * @deprecated Use {@link #isWindows()} instead. |
| */ |
| @Deprecated |
| public static final int OS_WINDOWS_MASK = OS_WINNT | OS_WIN2000 | OS_WINVISTA | OS_WIN_OTHER; |
| |
| /** A mask for Unix platforms. |
| * @deprecated Use {@link #isUnix()} instead. |
| */ |
| @Deprecated |
| public static final int OS_UNIX_MASK = OS_SOLARIS | OS_LINUX | OS_HP | OS_AIX | OS_IRIX | OS_SUNOS | OS_TRU64 | |
| OS_MAC | OS_FREEBSD | OS_OPENBSD | OS_UNIX_OTHER; |
| |
| /** The operating system on which NetBeans runs*/ |
| private static int operatingSystem = -1; |
| |
| // Package retranslation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| private static final Object TRANS_LOCK = /* FB complains about both "TRANS_LOCK" and new String("TRANS_LOCK") */new Object(); |
| |
| /** last used classloader or if run in test mode the TRANS_LOCK */ |
| private static Object transLoader; |
| |
| /** regular expression to with all changes */ |
| private static RE transExp; |
| |
| /** |
| * Prevent subclassing outside package |
| */ |
| private BaseUtilities() {} |
| |
| /** |
| * Useful queue for all parts of system that use <code>java.lang.ref.Reference</code>s |
| * together with some <code>ReferenceQueue</code> and need to do some clean up |
| * when the reference is enqueued. Usually, in order to be notified about that, one |
| * needs to either create a dedicated thread that blocks on the queue and is |
| * <code>Object.notify</code>-ed, which is the right approach but consumes |
| * valuable system resources (threads) or one can periodically check the content |
| * of the queue by <code>RequestProcessor.Task.schedule</code> which is |
| * completely wrong, because it wakes up the system every (say) 15 seconds. |
| * In order to provide useful support for this problem, this queue has been |
| * provided. |
| * <P> |
| * If you have a reference that needs cleanup, make it implement <link>Runnable</link> |
| * and register it with the queue: |
| * <PRE> |
| * class MyReference extends WeakReference<Thing> implements Runnable { |
| * private final OtherInfo dataToCleanUp; |
| * public MyReference(Thing ref, OtherInfo data) { |
| * super(ref, Utilities.queue()); |
| * dataToCleanUp = data; |
| * } |
| * public void run() { |
| * dataToCleanUp.releaseOrWhateverYouNeed(); |
| * } |
| * } |
| * </PRE> |
| * When the <code>ref</code> object is garbage collected, your run method |
| * will be invoked by calling |
| * <code>((Runnable) reference).run()</code> |
| * and you can perform whatever cleanup is necessary. Be sure not to block |
| * in such cleanup for a long time as this prevents other waiting references |
| * from cleaning themselves up. |
| * <P> |
| * Do not call any <code>ReferenceQueue</code> methods. They |
| * will throw exceptions. You may only enqueue a reference. |
| * <p> |
| * Be sure to call this method anew for each reference. |
| * Do not attempt to cache the return value. |
| * @since 3.11 |
| */ |
| public static ReferenceQueue<Object> activeReferenceQueue() { |
| return ActiveQueue.queue(); |
| } |
| |
| /** Get the operating system on which NetBeans is running. |
| * @return one of the <code>OS_*</code> constants (such as {@link #OS_WINNT}) |
| */ |
| public static int getOperatingSystem() { |
| if (operatingSystem == -1) { |
| String osName = System.getProperty("os.name"); |
| |
| if ("Windows NT".equals(osName)) { // NOI18N |
| operatingSystem = OS_WINNT; |
| } else if ("Windows 2000".equals(osName)) { // NOI18N |
| operatingSystem = OS_WIN2000; |
| } else if ("Windows Vista".equals(osName)) { // NOI18N |
| operatingSystem = OS_WINVISTA; |
| } else if (osName.startsWith("Windows ")) { // NOI18N |
| operatingSystem = OS_WIN_OTHER; |
| } else if ("Solaris".equals(osName)) { // NOI18N |
| operatingSystem = OS_SOLARIS; |
| } else if (osName.startsWith("SunOS")) { // NOI18N |
| operatingSystem = OS_SOLARIS; |
| } |
| // JDK 1.4 b2 defines os.name for me as "Redhat Linux" -jglick |
| else if (osName.endsWith("Linux")) { // NOI18N |
| operatingSystem = OS_LINUX; |
| } else if ("HP-UX".equals(osName)) { // NOI18N |
| operatingSystem = OS_HP; |
| } else if ("AIX".equals(osName)) { // NOI18N |
| operatingSystem = OS_AIX; |
| } else if ("Irix".equals(osName)) { // NOI18N |
| operatingSystem = OS_IRIX; |
| } else if ("SunOS".equals(osName)) { // NOI18N |
| operatingSystem = OS_SUNOS; |
| } else if ("Digital UNIX".equals(osName)) { // NOI18N |
| operatingSystem = OS_TRU64; |
| } else if ("OS/2".equals(osName)) { // NOI18N |
| operatingSystem = OS_OS2; |
| } else if ("OpenVMS".equals(osName)) { // NOI18N |
| operatingSystem = OS_VMS; |
| } else if (osName.equals("Mac OS X")) { // NOI18N |
| operatingSystem = OS_MAC; |
| } else if (osName.startsWith("Darwin")) { // NOI18N |
| operatingSystem = OS_MAC; |
| } else if (osName.toLowerCase(Locale.US).startsWith("freebsd")) { // NOI18N |
| operatingSystem = OS_FREEBSD; |
| } else if ("OpenBSD".equals(osName)) { // NOI18N |
| operatingSystem = OS_OPENBSD; |
| } else if (File.pathSeparatorChar == ':') { // NOI18N |
| operatingSystem = OS_UNIX_OTHER; |
| } else { |
| operatingSystem = OS_OTHER; |
| } |
| } |
| |
| return operatingSystem; |
| } |
| |
| /** Test whether NetBeans is running on some variant of Windows. |
| * @return <code>true</code> if Windows, <code>false</code> if some other manner of operating system |
| */ |
| public static boolean isWindows() { |
| return (getOperatingSystem() & OS_WINDOWS_MASK) != 0; |
| } |
| |
| /** Test whether NetBeans is running on Mac OS X. |
| * @since 7.7 |
| * @return <code>true</code> if Mac, <code>false</code> if some other manner of operating system |
| */ |
| public static boolean isMac() { |
| return (getOperatingSystem() & OS_MAC) != 0; |
| } |
| |
| /** Test whether NetBeans is running on some variant of Unix. |
| * Linux is included as well as the commercial vendors and Mac OS X. |
| * @return <code>true</code> some sort of Unix, <code>false</code> if some other manner of operating system |
| */ |
| public static boolean isUnix() { |
| return (getOperatingSystem() & OS_UNIX_MASK) != 0; |
| } |
| |
| // only for UtilitiesTest purposes |
| static void resetOperatingSystem() { |
| operatingSystem = -1; |
| } |
| |
| /** Test whether a given string is a valid Java identifier. |
| * @param id string which should be checked |
| * @return <code>true</code> if a valid identifier |
| * @see SourceVersion#isIdentifier |
| * @see SourceVersion#isKeyword |
| */ |
| public static boolean isJavaIdentifier(String id) { |
| if (id == null) { |
| return false; |
| } |
| return SourceVersion.isIdentifier(id) && !SourceVersion.isKeyword(id); |
| } |
| |
| /** Wrap multi-line strings (and get the individual lines). |
| * @param original the original string to wrap |
| * @param width the maximum width of lines |
| * @param breakIterator breaks original to chars, words, sentences, depending on what instance you provide. |
| * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored |
| * @return the lines after wrapping |
| */ |
| public static String[] wrapStringToArray( |
| String original, int width, BreakIterator breakIterator, boolean removeNewLines |
| ) { |
| if (original.length() == 0) { |
| return new String[] { original }; |
| } |
| |
| String[] workingSet; |
| |
| // substitute original newlines with spaces, |
| // remove newlines from head and tail |
| if (removeNewLines) { |
| original = trimString(original); |
| original = original.replace('\n', ' '); |
| workingSet = new String[] { original }; |
| } else { |
| StringTokenizer tokens = new StringTokenizer(original, "\n"); // NOI18N |
| int len = tokens.countTokens(); |
| workingSet = new String[len]; |
| |
| for (int i = 0; i < len; i++) { |
| workingSet[i] = tokens.nextToken(); |
| } |
| } |
| |
| if (width < 1) { |
| width = 1; |
| } |
| |
| if (original.length() <= width) { |
| return workingSet; |
| } |
| |
| widthcheck: { |
| boolean ok = true; |
| |
| for (int i = 0; i < workingSet.length; i++) { |
| ok = ok && (workingSet[i].length() < width); |
| |
| if (!ok) { |
| break widthcheck; |
| } |
| } |
| |
| return workingSet; |
| } |
| |
| java.util.ArrayList<String> lines = new java.util.ArrayList<String>(); |
| |
| int lineStart = 0; // the position of start of currently processed line in the original string |
| |
| for (int i = 0; i < workingSet.length; i++) { |
| if (workingSet[i].length() < width) { |
| lines.add(workingSet[i]); |
| } else { |
| breakIterator.setText(workingSet[i]); |
| |
| int nextStart = breakIterator.next(); |
| int prevStart = 0; |
| |
| do { |
| while (((nextStart - lineStart) < width) && (nextStart != BreakIterator.DONE)) { |
| prevStart = nextStart; |
| nextStart = breakIterator.next(); |
| } |
| |
| if (nextStart == BreakIterator.DONE) { |
| nextStart = prevStart = workingSet[i].length(); |
| } |
| |
| if (prevStart == 0) { |
| prevStart = nextStart; |
| } |
| |
| lines.add(workingSet[i].substring(lineStart, prevStart)); |
| |
| lineStart = prevStart; |
| prevStart = 0; |
| } while (lineStart < workingSet[i].length()); |
| |
| lineStart = 0; |
| } |
| } |
| |
| String[] s = new String[lines.size()]; |
| |
| return lines.toArray(s); |
| } |
| |
| /** trims String |
| * @param s a String to trim |
| * @return trimmed String |
| */ |
| private static String trimString(String s) { |
| int idx = 0; |
| char c; |
| final int slen = s.length(); |
| |
| if (slen == 0) { |
| return s; |
| } |
| |
| do { |
| c = s.charAt(idx++); |
| } while (((c == '\n') || (c == '\r')) && (idx < slen)); |
| |
| s = s.substring(--idx); |
| idx = s.length() - 1; |
| |
| if (idx < 0) { |
| return s; |
| } |
| |
| do { |
| c = s.charAt(idx--); |
| } while (((c == '\n') || (c == '\r')) && (idx >= 0)); |
| |
| return s.substring(0, idx + 2); |
| } |
| |
| /** Wrap multi-line strings. |
| * @param original the original string to wrap |
| * @param width the maximum width of lines |
| * @param breakIterator algorithm for breaking lines |
| * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored |
| * @return the whole string with embedded newlines |
| */ |
| public static String wrapString(String original, int width, BreakIterator breakIterator, boolean removeNewLines) { |
| String[] sarray = wrapStringToArray(original, width, breakIterator, removeNewLines); |
| StringBuilder retBuf = new StringBuilder(); |
| |
| for (int i = 0; i < sarray.length; i++) { |
| retBuf.append(sarray[i]); |
| retBuf.append('\n'); |
| } |
| |
| return retBuf.toString(); |
| } |
| |
| /** Turn full name of an inner class into its pure form. |
| * @param fullName e.g. <code>some.pkg.SomeClass$Inner</code> |
| * @return e.g. <code>Inner</code> |
| */ |
| public static String pureClassName(final String fullName) { |
| final int index = fullName.indexOf('$'); |
| |
| if ((index >= 0) && (index < fullName.length())) { |
| return fullName.substring(index + 1, fullName.length()); |
| } |
| |
| return fullName; |
| } |
| |
| /** Safe equality check. |
| * The supplied objects are equal if: <UL> |
| * <LI> both are <code>null</code> |
| * <LI> both are arrays with same length and equal items (if the items are arrays, |
| * they are <em>not</em> checked the same way again) |
| * <LI> the two objects are {@link Object#equals} |
| * </UL> |
| * This method is <code>null</code>-safe, so if one of the parameters is true and the second not, |
| * it returns <code>false</code>. |
| * <p>Use {@code java.util.Objects.deepEquals} in JDK 7. |
| * @param o1 the first object to compare |
| * @param o2 the second object to compare |
| * @return <code>true</code> if the objects are equal |
| */ |
| public static boolean compareObjects(Object o1, Object o2) { |
| return compareObjectsImpl(o1, o2, 1); |
| } |
| |
| /** Safe equality check with array recursion. |
| * <p>Use {@code java.util.Objects.deepEquals} in JDK 7. |
| * @param o1 the first object to compare |
| * @param o2 the second object to compare |
| * @param checkArraysDepth the depth to which arrays should be compared for equality (negative for infinite depth, zero for no comparison of elements, one for shallow, etc.) |
| * @return <code>true</code> if the objects are equal |
| * @see #compareObjects(Object, Object) |
| */ |
| public static boolean compareObjectsImpl(Object o1, Object o2, int checkArraysDepth) { |
| // handle null values |
| if (o1 == null) { |
| return (o2 == null); |
| } else if (o2 == null) { |
| return false; |
| } |
| |
| // handle arrays |
| if (checkArraysDepth > 0) { |
| if ((o1 instanceof Object[]) && (o2 instanceof Object[])) { |
| // Note: also handles multidimensional arrays of primitive types correctly. |
| // I.e. new int[0][] instanceof Object[] |
| Object[] o1a = (Object[]) o1; |
| Object[] o2a = (Object[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (!compareObjectsImpl(o1a[i], o2a[i], checkArraysDepth - 1)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof byte[]) && (o2 instanceof byte[])) { |
| byte[] o1a = (byte[]) o1; |
| byte[] o2a = (byte[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof short[]) && (o2 instanceof short[])) { |
| short[] o1a = (short[]) o1; |
| short[] o2a = (short[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof int[]) && (o2 instanceof int[])) { |
| int[] o1a = (int[]) o1; |
| int[] o2a = (int[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof long[]) && (o2 instanceof long[])) { |
| long[] o1a = (long[]) o1; |
| long[] o2a = (long[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof float[]) && (o2 instanceof float[])) { |
| float[] o1a = (float[]) o1; |
| float[] o2a = (float[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof double[]) && (o2 instanceof double[])) { |
| double[] o1a = (double[]) o1; |
| double[] o2a = (double[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof char[]) && (o2 instanceof char[])) { |
| char[] o1a = (char[]) o1; |
| char[] o2a = (char[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } else if ((o1 instanceof boolean[]) && (o2 instanceof boolean[])) { |
| boolean[] o1a = (boolean[]) o1; |
| boolean[] o2a = (boolean[]) o2; |
| int l1 = o1a.length; |
| int l2 = o2a.length; |
| |
| if (l1 != l2) { |
| return false; |
| } |
| |
| for (int i = 0; i < l1; i++) { |
| if (o1a[i] != o2a[i]) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| // else not array type |
| } |
| |
| // handle common objects--non-arrays, or arrays when depth == 0 |
| return o1.equals(o2); |
| } |
| |
| /** Assemble a human-presentable class name for a specified class. |
| * Arrays are represented as e.g. <code>java.lang.String[]</code>. |
| * @param clazz the class to name |
| * @return the human-presentable name |
| */ |
| public static String getClassName(Class<?> clazz) { |
| // if it is an array, get short name of element type and append [] |
| if (clazz.isArray()) { |
| return getClassName(clazz.getComponentType()) + "[]"; // NOI18N |
| } else { |
| return clazz.getName(); |
| } |
| } |
| |
| /** Assemble a human-presentable class name for a specified class (omitting the package). |
| * Arrays are represented as e.g. <code>String[]</code>. |
| * @param clazz the class to name |
| * @return the human-presentable name |
| */ |
| public static String getShortClassName(Class<?> clazz) { |
| // if it is an array, get short name of element type and append [] |
| if (clazz.isArray()) { |
| return getShortClassName(clazz.getComponentType()) + "[]"; // NOI18N |
| } |
| |
| String name = clazz.getName().replace('$', '.'); |
| |
| return name.substring(name.lastIndexOf('.') + 1, name.length()); // NOI18N |
| } |
| |
| /** |
| * Convert an array of objects to an array of primitive types. |
| * E.g. an <code>Integer[]</code> would be changed to an <code>int[]</code>. |
| * @param array the wrapper array |
| * @return a primitive array |
| * @throws IllegalArgumentException if the array element type is not a primitive wrapper |
| */ |
| public static Object toPrimitiveArray(Object[] array) { |
| if (array instanceof Integer[]) { |
| int[] r = new int[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Integer) array[i]) == null) ? 0 : (Integer) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Boolean[]) { |
| boolean[] r = new boolean[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Boolean) array[i]) == null) ? false : (Boolean) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Byte[]) { |
| byte[] r = new byte[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Byte) array[i]) == null) ? 0 : (Byte) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Character[]) { |
| char[] r = new char[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Character) array[i]) == null) ? 0 : (Character) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Double[]) { |
| double[] r = new double[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Double) array[i]) == null) ? 0 : (Double) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Float[]) { |
| float[] r = new float[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Float) array[i]) == null) ? 0 : (Float) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Long[]) { |
| long[] r = new long[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Long) array[i]) == null) ? 0 : (Long) array[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof Short[]) { |
| short[] r = new short[array.length]; |
| int i; |
| int k = array.length; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = (((Short) array[i]) == null) ? 0 : (Short) array[i]; |
| } |
| |
| return r; |
| } |
| |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Convert an array of primitive types to an array of objects. |
| * E.g. an <code>int[]</code> would be turned into an <code>Integer[]</code>. |
| * @param array the primitive array |
| * @return a wrapper array |
| * @throws IllegalArgumentException if the array element type is not primitive |
| */ |
| public static Object[] toObjectArray(Object array) { |
| if (array instanceof Object[]) { |
| return (Object[]) array; |
| } |
| |
| if (array instanceof int[]) { |
| int i; |
| int k = ((int[]) array).length; |
| Integer[] r = new Integer[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((int[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof boolean[]) { |
| int i; |
| int k = ((boolean[]) array).length; |
| Boolean[] r = new Boolean[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((boolean[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof byte[]) { |
| int i; |
| int k = ((byte[]) array).length; |
| Byte[] r = new Byte[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((byte[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof char[]) { |
| int i; |
| int k = ((char[]) array).length; |
| Character[] r = new Character[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((char[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof double[]) { |
| int i; |
| int k = ((double[]) array).length; |
| Double[] r = new Double[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((double[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof float[]) { |
| int i; |
| int k = ((float[]) array).length; |
| Float[] r = new Float[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((float[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof long[]) { |
| int i; |
| int k = ((long[]) array).length; |
| Long[] r = new Long[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((long[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| if (array instanceof short[]) { |
| int i; |
| int k = ((short[]) array).length; |
| Short[] r = new Short[k]; |
| |
| for (i = 0; i < k; i++) { |
| r[i] = ((short[]) array)[i]; |
| } |
| |
| return r; |
| } |
| |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Get the object type for given primitive type. |
| * |
| * @param c primitive type (e.g. <code>int</code>) |
| * @return object type (e.g. <code>Integer</code>) |
| */ |
| public static Class<?> getObjectType(Class<?> c) { |
| if (!c.isPrimitive()) { |
| return c; |
| } |
| |
| if (c == Integer.TYPE) { |
| return Integer.class; |
| } |
| |
| if (c == Boolean.TYPE) { |
| return Boolean.class; |
| } |
| |
| if (c == Byte.TYPE) { |
| return Byte.class; |
| } |
| |
| if (c == Character.TYPE) { |
| return Character.class; |
| } |
| |
| if (c == Double.TYPE) { |
| return Double.class; |
| } |
| |
| if (c == Float.TYPE) { |
| return Float.class; |
| } |
| |
| if (c == Long.TYPE) { |
| return Long.class; |
| } |
| |
| if (c == Short.TYPE) { |
| return Short.class; |
| } |
| |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Get the primitive type for given object type. |
| * |
| * @param c object type (e.g. <code>Integer</code>) |
| * @return primitive type (e.g. <code>int</code>) |
| */ |
| public static Class<?> getPrimitiveType(Class<?> c) { |
| if (!c.isPrimitive()) { |
| return c; |
| } |
| |
| if (c == Integer.class) { |
| return Integer.TYPE; |
| } |
| |
| if (c == Boolean.class) { |
| return Boolean.TYPE; |
| } |
| |
| if (c == Byte.class) { |
| return Byte.TYPE; |
| } |
| |
| if (c == Character.class) { |
| return Character.TYPE; |
| } |
| |
| if (c == Double.class) { |
| return Double.TYPE; |
| } |
| |
| if (c == Float.class) { |
| return Float.TYPE; |
| } |
| |
| if (c == Long.class) { |
| return Long.TYPE; |
| } |
| |
| if (c == Short.class) { |
| return Short.TYPE; |
| } |
| |
| throw new IllegalArgumentException(); |
| } |
| |
| /** Parses parameters from a given string in shell-like manner. |
| * Users of the Bourne shell (e.g. on Unix) will already be familiar with the behavior. |
| * For example, when using <code>org.openide.execution.NbProcessDescriptor</code> (Execution API) |
| * you should be able to: |
| * <ul> |
| * <li>Include command names with embedded spaces, such as <code>c:\Program Files\jdk\bin\javac</code>. |
| * <li>Include extra command arguments, such as <code>-Dname=value</code>. |
| * <li>Do anything else which might require unusual characters or processing. For example: |
| * <p><code><pre> |
| * "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m |
| * </pre></code> |
| * <p>This example would create the following executable name and arguments: |
| * <ol> |
| * <li> <code>c:\program files\jdk\bin\java</code> |
| * <li> <code>-Dmessage=Hello /\/\ there!</code> |
| * <li> <code>-Xmx128m</code> |
| * </ol> |
| * Note that the command string does not escape its backslashes--under the assumption |
| * that Windows users will not think to do this, meaningless escapes are just left |
| * as backslashes plus following character. |
| * </ul> |
| * <em>Caveat</em>: even after parsing, Windows programs (such as the Java launcher) |
| * may not fully honor certain |
| * characters, such as quotes, in command names or arguments. This is because programs |
| * under Windows frequently perform their own parsing and unescaping (since the shell |
| * cannot be relied on to do this). On Unix, this problem should not occur. |
| * @param s a string to parse |
| * @return an array of parameters |
| */ |
| public static String[] parseParameters(String s) { |
| final int NULL = 0x0; |
| final int IN_PARAM = 0x1; |
| final int IN_DOUBLE_QUOTE = 0x2; |
| final int IN_SINGLE_QUOTE = 0x3; |
| ArrayList<String> params = new ArrayList<>(5); |
| char c; |
| |
| int state = NULL; |
| StringBuilder buff = new StringBuilder(20); |
| int slength = s.length(); |
| |
| for (int i = 0; i < slength; i++) { |
| c = s.charAt(i); |
| switch (state) { |
| case NULL: |
| switch (c) { |
| case '\'': |
| state = IN_SINGLE_QUOTE; |
| break; |
| case '"': |
| state = IN_DOUBLE_QUOTE; |
| break; |
| default: |
| if (!Character.isWhitespace(c)) { |
| buff.append(c); |
| state = IN_PARAM; |
| } |
| } |
| break; |
| case IN_SINGLE_QUOTE: |
| if (c != '\'') { |
| buff.append(c); |
| } else { |
| state = IN_PARAM; |
| } |
| break; |
| case IN_DOUBLE_QUOTE: |
| switch (c) { |
| case '\\': |
| char peek = (i < slength - 1) ? s.charAt(i+1) : Character.MIN_VALUE; |
| if (peek == '"' || peek =='\\') { |
| buff.append(peek); |
| i++; |
| } else { |
| buff.append(c); |
| } |
| break; |
| case '"': |
| state = IN_PARAM; |
| break; |
| default: |
| buff.append(c); |
| } |
| break; |
| case IN_PARAM: |
| switch (c) { |
| case '\'': |
| state = IN_SINGLE_QUOTE; |
| break; |
| case '"': |
| state = IN_DOUBLE_QUOTE; |
| break; |
| default: |
| if (Character.isWhitespace(c)) { |
| params.add(buff.toString()); |
| buff.setLength(0); |
| state = NULL; |
| } else { |
| buff.append(c); |
| } |
| } |
| break; |
| } |
| } |
| if (buff.length() > 0) { |
| params.add(buff.toString()); |
| } |
| |
| return params.toArray(new String[params.size()]); |
| } |
| |
| /** Complementary method to parseParameters |
| * @see #parseParameters |
| */ |
| public static String escapeParameters(String[] params) { |
| StringBuffer sb = new StringBuffer(); |
| |
| for (int i = 0; i < params.length; i++) { |
| escapeString(params[i], sb); |
| sb.append(' '); |
| } |
| |
| final int len = sb.length(); |
| |
| if (len > 0) { |
| sb.setLength(len - 1); |
| } |
| |
| return sb.toString().trim(); |
| } |
| |
| /** Escapes one string |
| * @see #escapeParameters |
| */ |
| private static void escapeString(String s, StringBuffer sb) { |
| if (s.length() == 0) { |
| sb.append("\"\""); |
| |
| return; |
| } |
| |
| boolean hasSpace = false; |
| final int sz = sb.length(); |
| final int slen = s.length(); |
| char c; |
| |
| for (int i = 0; i < slen; i++) { |
| c = s.charAt(i); |
| |
| if (Character.isWhitespace(c)) { |
| hasSpace = true; |
| sb.append(c); |
| |
| continue; |
| } |
| |
| if (c == '\\') { |
| sb.append('\\').append('\\'); |
| |
| continue; |
| } |
| |
| if (c == '"') { |
| sb.append('\\').append('"'); |
| |
| continue; |
| } |
| |
| sb.append(c); |
| } |
| |
| if (hasSpace) { |
| sb.insert(sz, '"'); |
| sb.append('"'); |
| } |
| } |
| |
| /** |
| * Topologically sort some objects. |
| * <p>There may not be any nulls among the objects, nor duplicates |
| * (as per hash/equals), nor duplicates among the edge lists. |
| * The edge map need not contain an entry for every object, only if it |
| * has some outgoing edges (empty but not null map values are permitted). |
| * The edge map shall not contain neither keys nor value entries for objects not |
| * in the collection to be sorted, if that happens they will be ignored (since version 7.9). |
| * <p>The incoming parameters will not be modified; they must not be changed |
| * during the call and possible calls to TopologicalSortException methods. |
| * The returned list will support modifications. |
| * <p>There is a <em>weak</em> stability guarantee: if there are no edges |
| * which contradict the incoming order, the resulting list will be in the same |
| * order as the incoming elements. However if some elements need to be rearranged, |
| * it is <em>not</em> guaranteed that others will not also be rearranged, even |
| * if they did not strictly speaking need to be. |
| * @param c a collection of objects to be topologically sorted |
| * @param edges constraints among those objects, of type <code>Map<Object,Collection></code>; |
| * if an object is a key in this map, the resulting order will |
| * have that object before any objects listed in the value |
| * @return a partial ordering of the objects in the collection, |
| * @exception TopologicalSortException if the sort cannot succeed due to cycles in the graph, the |
| * exception contains additional information to describe and possibly recover from the error |
| * @since 3.30 |
| * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=27286">Issue #27286</a> |
| */ |
| public static <T> List<T> topologicalSort(Collection<? extends T> c, Map<? super T, ? extends Collection<? extends T>> edges) |
| throws TopologicalSortException { |
| Map<T,Boolean> finished = new HashMap<T,Boolean>(); |
| List<T> r = new ArrayList<T>(Math.max(c.size(), 1)); |
| List<T> cRev = new ArrayList<T>(c); |
| Collections.reverse(cRev); |
| |
| Iterator<T> it = cRev.iterator(); |
| |
| while (it.hasNext()) { |
| List<T> cycle = visit(it.next(), edges, finished, r); |
| |
| if (cycle != null) { |
| throw new TopologicalSortException(cRev, edges); |
| } |
| } |
| |
| Collections.reverse(r); |
| if (r.size() != c.size()) { |
| r.retainAll(c); |
| } |
| |
| return r; |
| } |
| |
| /** |
| * Visit one node in the DAG. |
| * @param node node to visit |
| * @param edges edges in the DAG |
| * @param finished which nodes are finished; a node has no entry if it has not yet |
| * been visited, else it is set to false while recurring and true |
| * when it has finished |
| * @param r the order in progress |
| * @return list with detected cycle |
| */ |
| static <T> List<T> visit( |
| T node, |
| Map<? super T, ? extends Collection<? extends T>> edges, |
| Map<T,Boolean> finished, |
| List<T> r |
| ) { |
| Boolean b = finished.get(node); |
| |
| //System.err.println("node=" + node + " color=" + b); |
| if (b != null) { |
| if (b.booleanValue()) { |
| return null; |
| } |
| |
| ArrayList<T> cycle = new ArrayList<T>(); |
| cycle.add(node); |
| finished.put(node, null); |
| |
| return cycle; |
| } |
| |
| Collection<? extends T> e = edges.get(node); |
| |
| if (e != null) { |
| finished.put(node, Boolean.FALSE); |
| |
| Iterator<? extends T> it = e.iterator(); |
| |
| while (it.hasNext()) { |
| List<T> cycle = visit(it.next(), edges, finished, r); |
| |
| if (cycle != null) { |
| if (cycle instanceof ArrayList) { |
| // if cycle instanceof ArrayList we are still in the |
| // cycle and we want to collect new members |
| if (Boolean.FALSE == finished.get(node)) { |
| // another member in the cycle |
| cycle.add(node); |
| } else { |
| // we have reached the head of the cycle |
| // do not add additional cycles anymore |
| Collections.reverse(cycle); |
| |
| // changing cycle to not be ArrayList |
| cycle = Collections.unmodifiableList(cycle); |
| } |
| } |
| |
| // mark this node as tested |
| finished.put(node, Boolean.TRUE); |
| |
| // and report an error |
| return cycle; |
| } |
| } |
| } |
| |
| finished.put(node, Boolean.TRUE); |
| r.add(node); |
| |
| return null; |
| } |
| |
| /** Provides support for parts of the system that deal with classnames |
| * (use <code>Class.forName</code>, <code>NbObjectInputStream</code>, etc.) or filenames |
| * in layers. |
| * <P> |
| * Often class names (especially package names) changes during lifecycle |
| * of a module. When some piece of the system stores the name of a class |
| * in certain point of a time and wants to find the correct <code>Class</code> |
| * later it needs to count with the possibility of rename. |
| * <P> |
| * For such purposes this method has been created. It allows modules to |
| * register their classes that changed names and other parts of system that |
| * deal with class names to find the correct names. |
| * <P> |
| * To register a mapping from old class names to new ones create a file |
| * <code>META-INF/netbeans/translate.names</code> in your module and fill it |
| * with your mapping: |
| * <PRE> |
| * # |
| * # Mapping of legacy classes to new ones |
| * # |
| * |
| * org.oldpackage.MyClass=org.newpackage.MyClass # rename of package for one class |
| * org.mypackage.OldClass=org.mypackage.NewClass # rename of class in a package |
| * |
| * # rename of class and package |
| * org.oldpackage.OldClass=org.newpackage.NewClass |
| * |
| * # rename of whole package |
| * org.someoldpackage=org.my.new.package.structure |
| * |
| * # class was removed without replacement |
| * org.mypackage.OldClass= |
| * |
| * </PRE> |
| * Btw. one can use spaces instead of <code>=</code> sign. |
| * For a real world example |
| * check the |
| * <a href="http://www.netbeans.org/source/browse/xml/text-edit/compat/src/META-INF/netbeans/"> |
| * xml module</a>. |
| * |
| * <P> |
| * For purposes of <link>org.openide.util.io.NbObjectInputStream</link> there is |
| * a following special convention: |
| * If the |
| * className is not listed as one that is to be renamed, the returned |
| * string == className, if the className is registered to be renamed |
| * than the className != returned value, even in a case when className.equals (retValue) |
| * <p/> |
| * Similar behaviour applies to <b>filenames</b> provided by layers (system filesystem). Filenames |
| * can be also translated to adapt to location changes e.g. in action registrations. Note that |
| * <b>no spaces or special characters</b> are allowed in both translated filenames or translation |
| * results. Filenames must conform to regexp {@code ^[/a-zA-Z0-9$_.+-]+$}. Keys and values are treated |
| * as paths from fs root. |
| * |
| * <p/> |
| * Example of file path translation (action registration file has moved): |
| * <pre> |
| * # registration ID has changed |
| * Actions/Refactoring/RefactoringWhereUsed.instance=Actions/Refactoring/org-netbeans-modules-refactoring-api-ui-WhereUsedAction.instance |
| * </pre> |
| * |
| * @param className fully qualified name of a class, or file path to translate |
| * @return new name of the class according to renaming rules. |
| */ |
| public static String translate(final String className) { |
| checkMapping(); |
| |
| RE exp; |
| |
| synchronized (TRANS_LOCK) { |
| exp = transExp; |
| } |
| |
| if (exp == null) { |
| // no transition table found |
| return className; |
| } |
| |
| synchronized (exp) { |
| // refusing convertions as fast as possible |
| return exp.convert(className); |
| } |
| } |
| |
| /** Loads all resources that contain renaming information. |
| * @param l classloader to load packages from |
| */ |
| private static void checkMapping() { |
| // test if we run in test mode |
| if (transLoader == TRANS_LOCK) { |
| // no check |
| return; |
| } |
| |
| ClassLoader current = Lookup.getDefault().lookup(ClassLoader.class); |
| |
| if (current == null) { |
| current = ClassLoader.getSystemClassLoader(); |
| } |
| |
| if (transLoader == current) { |
| // no change, no rescan |
| return; |
| } |
| |
| initForLoader(current, current); |
| } |
| |
| /* Initializes the content of transition table from a classloader. |
| * @param loader loader to read data from |
| * @param set loader to set as the transLoader or null if we run in test mode |
| */ |
| static void initForLoader(ClassLoader current, Object set) { |
| if (set == null) { |
| set = TRANS_LOCK; |
| } |
| |
| Enumeration<URL> en; |
| |
| try { |
| en = current.getResources("META-INF/netbeans/translate.names"); |
| } catch (IOException ex) { |
| LOG.log(Level.WARNING, null, ex); |
| en = null; |
| } |
| |
| if ((en == null) || !en.hasMoreElements()) { |
| synchronized (TRANS_LOCK) { |
| transLoader = set; |
| transExp = null; |
| } |
| |
| return; |
| } |
| |
| // format of line in the meta files |
| // |
| // # comments are allowed |
| // a.name.in.a.Package=another.Name # with comment is allowed |
| // for.compatibility.one.can.use.Space instead.of.Equal |
| // |
| RE re = null; |
| |
| // [pnejedly:perf] commented out. The RegExp based translation was way slower |
| // than the hand-written RE13 |
| // if (Dependency.JAVA_SPEC.compareTo(new SpecificationVersion("1.4")) >= 0) { // NOI18N |
| // try { |
| // re = (RE)Class.forName ("org.openide.util.RE14").newInstance (); |
| // } catch (ThreadDeath t) { |
| // throw t; |
| // } catch (Throwable t) { |
| // } |
| // } |
| // if (re == null) { |
| re = new RE13(); |
| |
| // } |
| TreeSet<String[]> list = new TreeSet<String[]>( |
| new Comparator<String[]>() { |
| @Override public int compare(String[] o1, String[] o2) { |
| String s1 = o1[0]; |
| String s2 = o2[0]; |
| |
| int i1 = s1.length(); |
| int i2 = s2.length(); |
| |
| if (i1 != i2) { |
| return i2 - i1; |
| } |
| |
| return s2.compareTo(s1); |
| } |
| } |
| ); |
| |
| while (en.hasMoreElements()) { |
| URL u = en.nextElement(); |
| |
| try { |
| BufferedReader reader = new BufferedReader( |
| new InputStreamReader(u.openStream(), "UTF8") // use explicit encoding //NOI18N |
| ); |
| loadTranslationFile(re, reader, list); |
| reader.close(); |
| } catch (IOException ex) { |
| LOG.log(Level.WARNING, "Problematic file: {0}", u); |
| LOG.log(Level.WARNING, null, ex); |
| } |
| } |
| |
| // construct a regular expression of following form. Let "1", "2", "3", "4" |
| // be the keys: |
| // "^ |
| // thus if 4 is matched five groups will be created |
| String[] arr = new String[list.size()]; |
| String[] pattern = new String[arr.length]; |
| |
| int i = 0; |
| for (String[] pair : list) { |
| arr[i] = pair[1].intern(); // name of the track |
| pattern[i] = pair[0]; // original object |
| i++; |
| } |
| |
| synchronized (TRANS_LOCK) { |
| // last check |
| if (arr.length == 0) { |
| transExp = null; |
| } else { |
| transExp = re; |
| transExp.init(pattern, arr); |
| } |
| |
| transLoader = set; |
| } |
| } |
| |
| /** |
| * Load single translation file. |
| * @param resource URL identifiing transaction table |
| * @param results will be filled with String[2] |
| */ |
| private static void loadTranslationFile(RE re, BufferedReader reader, Set<String[]> results) |
| throws IOException { |
| for (;;) { |
| String line = reader.readLine(); |
| |
| if (line == null) { |
| break; |
| } |
| |
| if ((line.length() == 0) || line.startsWith("#")) { // NOI18N |
| |
| continue; |
| } |
| |
| String[] pair = re.readPair(line); |
| |
| if (pair == null) { |
| throw new java.io.InvalidObjectException("Line is invalid: " + line); |
| } |
| |
| results.add(pair); |
| } |
| } |
| |
| /** |
| * Converts a file to a URI while being safe for UNC paths. |
| * Uses {@link File f}.{@link File#toPath() toPath}().{@link java.nio.file.Path#toUri() toUri}() |
| * which results into {@link URI} that works with {@link URI#normalize()} |
| * and {@link URI#resolve(URI)}. |
| * @param f a file |
| * @return a {@code file}-protocol URI which may use the host field |
| * @see java.nio.file.Path.toUri |
| * @since 8.25 |
| */ |
| public static URI toURI(File f) { |
| URI u; |
| if (pathToURISupported()) { |
| try { |
| u = f.toPath().toUri(); |
| } catch (java.nio.file.InvalidPathException ex) { |
| u = f.toURI(); |
| LOG.log(Level.FINE, "can't convert " + f + " falling back to " + u, ex); |
| } |
| } else { |
| u = f.toURI(); |
| } |
| if (u.toString().startsWith("file:///")) { |
| try { |
| // #214131 workaround |
| return new URI( |
| /* "file" */u.getScheme(), /* null */u.getUserInfo(), |
| /* null (!) */u.getHost(), /* -1 */u.getPort(), |
| /* "/..." */u.getPath(), /* null */u.getQuery(), |
| /* null */u.getFragment() |
| ); |
| } catch (URISyntaxException ex) { |
| LOG.log(Level.FINE, "could not convert " + f + " to URI", ex); |
| } |
| } |
| return u; |
| } |
| |
| /** |
| * Converts a URI to a file while being safe for UNC paths. |
| * Uses {@link Paths#get(java.net.URI) Paths.get}(u).{@link java.nio.file.Path#toFile() toFile}() |
| * which accepts UNC URIs with a host field. |
| * @param u a {@code file}-protocol URI which may use the host field |
| * @return a file |
| * @see java.nio.file.Paths#get(java.net.URI) |
| * @since 8.25 |
| */ |
| public static File toFile(URI u) throws IllegalArgumentException { |
| try { |
| return Paths.get(u).toFile(); |
| } catch (Exception x) { |
| LOG.log(Level.FINE, "could not convert " + u + " to File", x); |
| } |
| String host = u.getHost(); |
| if (host != null && !host.isEmpty() && "file".equals(u.getScheme())) { |
| return new File("\\\\" + host + u.getPath().replace('/', '\\')); |
| } |
| return new File(u); |
| } |
| |
| /** |
| * Normalizes the given {@code URI}. Like {@link URI#normalize()}, but does |
| * not break certain special {@code URI}s, so should be preferred over |
| * {@linkplain URI#normalize()}. |
| * |
| * @param uri the {@code URI} to normalize |
| * @return the normalized URI |
| */ |
| public static URI normalizeURI(URI uri) { |
| @SuppressWarnings("URI.normalize") |
| URI normalized = uri.normalize(); |
| |
| if (uri.getAuthority() == null && "file".equals(uri.getScheme()) && uri.getPath().startsWith("//")) { |
| try { |
| normalized = new URI(normalized.getScheme(), null, "///" + normalized.getPath(), normalized.getQuery(), normalized.getFragment()); |
| } catch (URISyntaxException ex) { |
| throw new IllegalStateException(ex); //unexpected |
| } |
| } |
| |
| return normalized; |
| } |
| |
| /** Interfaces for communication between Utilities.translate and regular |
| * expression impl. |
| * |
| * Order of methods is: |
| * readPair few times |
| * init once |
| * convert many times |
| */ |
| @SuppressWarnings("PackageVisibleInnerClass") |
| static interface RE { |
| public void init(String[] original, String[] newversion); |
| |
| public String convert(String pattern); |
| |
| /** Parses line of text to two parts: the key and the rest |
| */ |
| public String[] readPair(String line); |
| } |
| |
| private static volatile Boolean pathURIConsistent; |
| |
| private static boolean pathToURISupported() { |
| Boolean res = pathURIConsistent; |
| if (res == null) { |
| boolean c; |
| try { |
| final File f = new File("küñ"); //NOI18N |
| c = f.toPath().toUri().equals(f.toURI()); |
| } catch (InvalidPathException e) { |
| c = false; |
| } |
| if (!c) { |
| LOG.fine("The java.nio.file.Path.toUri is inconsistent with java.io.File.toURI"); //NOI18N |
| } |
| res = pathURIConsistent = c; |
| } |
| return res; |
| } |
| } |