1 /*
   2  * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.shell;
  27 
  28 import java.awt.Image;
  29 import java.awt.Toolkit;
  30 import java.awt.image.BufferedImage;
  31 import java.io.File;
  32 import java.io.FileNotFoundException;
  33 import java.io.IOException;
  34 import java.security.AccessController;
  35 import java.security.PrivilegedAction;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.List;
  39 import java.util.concurrent.Callable;
  40 import java.util.concurrent.ExecutionException;
  41 import java.util.concurrent.Future;
  42 import java.util.concurrent.LinkedBlockingQueue;
  43 import java.util.concurrent.RejectedExecutionException;
  44 import java.util.concurrent.ThreadFactory;
  45 import java.util.concurrent.ThreadPoolExecutor;
  46 import java.util.concurrent.TimeUnit;
  47 import java.util.stream.Stream;
  48 
  49 import sun.awt.OSInfo;
  50 import sun.awt.util.ThreadGroupUtils;
  51 import sun.util.logging.PlatformLogger;
  52 
  53 import static sun.awt.shell.Win32ShellFolder2.DESKTOP;
  54 import static sun.awt.shell.Win32ShellFolder2.DRIVES;
  55 import static sun.awt.shell.Win32ShellFolder2.Invoker;
  56 import static sun.awt.shell.Win32ShellFolder2.MultiResolutionIconImage;
  57 import static sun.awt.shell.Win32ShellFolder2.NETWORK;
  58 import static sun.awt.shell.Win32ShellFolder2.PERSONAL;
  59 import static sun.awt.shell.Win32ShellFolder2.RECENT;
  60 // NOTE: This class supersedes Win32ShellFolderManager, which was removed
  61 //       from distribution after version 1.4.2.
  62 
  63 /**
  64  * @author Michael Martak
  65  * @author Leif Samuelsson
  66  * @author Kenneth Russell
  67  * @since 1.4
  68  */
  69 
  70 final class Win32ShellFolderManager2 extends ShellFolderManager {
  71 
  72     private static final PlatformLogger
  73             log = PlatformLogger.getLogger("sun.awt.shell.Win32ShellFolderManager2");
  74 
  75     static {
  76         // Load library here
  77         sun.awt.windows.WToolkit.loadLibraries();
  78     }
  79 
  80     public ShellFolder createShellFolder(File file) throws FileNotFoundException {
  81         try {
  82             return createShellFolder(getDesktop(), file);
  83         } catch (InterruptedException e) {
  84             throw new FileNotFoundException("Execution was interrupted");
  85         }
  86     }
  87 
  88     static Win32ShellFolder2 createShellFolder(Win32ShellFolder2 parent, File file)
  89             throws FileNotFoundException, InterruptedException {
  90         long pIDL;
  91         try {
  92             pIDL = parent.parseDisplayName(file.getCanonicalPath());
  93         } catch (IOException ex) {
  94             pIDL = 0;
  95         }
  96         if (pIDL == 0) {
  97             // Shouldn't happen but watch for it anyway
  98             throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found");
  99         }
 100 
 101         try {
 102             return createShellFolderFromRelativePIDL(parent, pIDL);
 103         } finally {
 104             Win32ShellFolder2.releasePIDL(pIDL);
 105         }
 106     }
 107 
 108     static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL)
 109             throws InterruptedException {
 110         // Walk down this relative pIDL, creating new nodes for each of the entries
 111         while (pIDL != 0) {
 112             long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL);
 113             if (curPIDL != 0) {
 114                 parent = Win32ShellFolder2.createShellFolder(parent, curPIDL);
 115                 pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL);
 116             } else {
 117                 // The list is empty if the parent is Desktop and pIDL is a shortcut to Desktop
 118                 break;
 119             }
 120         }
 121         return parent;
 122     }
 123 
 124     private static final int VIEW_LIST = 2;
 125     private static final int VIEW_DETAILS = 3;
 126     private static final int VIEW_PARENTFOLDER = 8;
 127     private static final int VIEW_NEWFOLDER = 11;
 128 
 129     private static final Image[] STANDARD_VIEW_BUTTONS = new Image[12];
 130 
 131     private static Image getStandardViewButton(int iconIndex) {
 132         Image result = STANDARD_VIEW_BUTTONS[iconIndex];
 133 
 134         if (result != null) {
 135             return result;
 136         }
 137 
 138         final int[] iconBits = Win32ShellFolder2
 139                 .getStandardViewButton0(iconIndex, true);
 140         if (iconBits != null) {
 141             // icons are always square
 142             final int size = (int) Math.sqrt(iconBits.length);
 143             final BufferedImage img =
 144                     new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
 145             img.setRGB(0, 0, size, size, iconBits, 0, size);
 146 
 147             STANDARD_VIEW_BUTTONS[iconIndex] = (size == 16)
 148                     ? img
 149                     : new MultiResolutionIconImage(16, img);
 150         }
 151 
 152         return STANDARD_VIEW_BUTTONS[iconIndex];
 153     }
 154 
 155     // Special folders
 156     private static Win32ShellFolder2 desktop;
 157     private static Win32ShellFolder2 drives;
 158     private static Win32ShellFolder2 recent;
 159     private static Win32ShellFolder2 network;
 160     private static Win32ShellFolder2 personal;
 161 
 162     static Win32ShellFolder2 getDesktop() {
 163         if (desktop == null) {
 164             try {
 165                 desktop = new Win32ShellFolder2(DESKTOP);
 166             } catch (final SecurityException ignored) {
 167                 // Ignore, the message may have sensitive information, not
 168                 // accessible other ways
 169             } catch (IOException | InterruptedException e) {
 170                 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 171                     log.warning("Cannot access 'Desktop'", e);
 172                 }
 173             }
 174         }
 175         return desktop;
 176     }
 177 
 178     static Win32ShellFolder2 getDrives() {
 179         if (drives == null) {
 180             try {
 181                 drives = new Win32ShellFolder2(DRIVES);
 182             } catch (final SecurityException ignored) {
 183                 // Ignore, the message may have sensitive information, not
 184                 // accessible other ways
 185             } catch (IOException | InterruptedException e) {
 186                 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 187                     log.warning("Cannot access 'Drives'", e);
 188                 }
 189             }
 190         }
 191         return drives;
 192     }
 193 
 194     static Win32ShellFolder2 getRecent() {
 195         if (recent == null) {
 196             try {
 197                 String path = Win32ShellFolder2.getFileSystemPath(RECENT);
 198                 if (path != null) {
 199                     recent = createShellFolder(getDesktop(), new File(path));
 200                 }
 201             } catch (final SecurityException ignored) {
 202                 // Ignore, the message may have sensitive information, not
 203                 // accessible other ways
 204             } catch (InterruptedException | IOException e) {
 205                 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 206                     log.warning("Cannot access 'Recent'", e);
 207                 }
 208             }
 209         }
 210         return recent;
 211     }
 212 
 213     static Win32ShellFolder2 getNetwork() {
 214         if (network == null) {
 215             try {
 216                 network = new Win32ShellFolder2(NETWORK);
 217             } catch (final SecurityException ignored) {
 218                 // Ignore, the message may have sensitive information, not
 219                 // accessible other ways
 220             } catch (IOException | InterruptedException e) {
 221                 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 222                     log.warning("Cannot access 'Network'", e);
 223                 }
 224             }
 225         }
 226         return network;
 227     }
 228 
 229     static Win32ShellFolder2 getPersonal() {
 230         if (personal == null) {
 231             try {
 232                 String path = Win32ShellFolder2.getFileSystemPath(PERSONAL);
 233                 if (path != null) {
 234                     Win32ShellFolder2 desktop = getDesktop();
 235                     personal = desktop.getChildByPath(path);
 236                     if (personal == null) {
 237                         personal = createShellFolder(getDesktop(), new File(path));
 238                     }
 239                     if (personal != null) {
 240                         personal.setIsPersonal();
 241                     }
 242                 }
 243             } catch (final SecurityException ignored) {
 244                 // Ignore, the message may have sensitive information, not
 245                 // accessible other ways
 246             } catch (InterruptedException | IOException e) {
 247                 if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 248                     log.warning("Cannot access 'Personal'", e);
 249                 }
 250             }
 251         }
 252         return personal;
 253     }
 254 
 255 
 256     private static File[] roots;
 257 
 258     /**
 259      * @param key a {@code String}
 260      *  "fileChooserDefaultFolder":
 261      *    Returns a {@code File} - the default shellfolder for a new filechooser
 262      *  "roots":
 263      *    Returns a {@code File[]} - containing the root(s) of the displayable hierarchy
 264      *  "fileChooserComboBoxFolders":
 265      *    Returns a {@code File[]} - an array of shellfolders representing the list to
 266      *    show by default in the file chooser's combobox
 267      *   "fileChooserShortcutPanelFolders":
 268      *    Returns a {@code File[]} - an array of shellfolders representing well-known
 269      *    folders, such as Desktop, Documents, History, Network, Home, etc.
 270      *    This is used in the shortcut panel of the filechooser on Windows 2000
 271      *    and Windows Me.
 272      *  "fileChooserIcon <icon>":
 273      *    Returns an {@code Image} - icon can be ListView, DetailsView, UpFolder, NewFolder or
 274      *    ViewMenu (Windows only).
 275      *  "optionPaneIcon iconName":
 276      *    Returns an {@code Image} - icon from the system icon list
 277      *
 278      * @return An Object matching the key string.
 279      */
 280     public Object get(String key) {
 281         if (key.equals("fileChooserDefaultFolder")) {
 282             File file = getPersonal();
 283             if (file == null) {
 284                 file = getDesktop();
 285             }
 286             return checkFile(file);
 287         } else if (key.equals("roots")) {
 288             // Should be "History" and "Desktop" ?
 289             if (roots == null) {
 290                 File desktop = getDesktop();
 291                 if (desktop != null) {
 292                     roots = new File[] { desktop };
 293                 } else {
 294                     roots = (File[])super.get(key);
 295                 }
 296             }
 297             return checkFiles(roots);
 298         } else if (key.equals("fileChooserComboBoxFolders")) {
 299             Win32ShellFolder2 desktop = getDesktop();
 300 
 301             if (desktop != null && checkFile(desktop) != null) {
 302                 ArrayList<File> folders = new ArrayList<File>();
 303                 Win32ShellFolder2 drives = getDrives();
 304 
 305                 Win32ShellFolder2 recentFolder = getRecent();
 306                 if (recentFolder != null && OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_2000) >= 0) {
 307                     folders.add(recentFolder);
 308                 }
 309 
 310                 folders.add(desktop);
 311                 // Add all second level folders
 312                 File[] secondLevelFolders = checkFiles(desktop.listFiles());
 313                 Arrays.sort(secondLevelFolders);
 314                 for (File secondLevelFolder : secondLevelFolders) {
 315                     Win32ShellFolder2 folder = (Win32ShellFolder2) secondLevelFolder;
 316                     if (!folder.isFileSystem() || (folder.isDirectory() && !folder.isLink())) {
 317                         folders.add(folder);
 318                         // Add third level for "My Computer"
 319                         if (folder.equals(drives)) {
 320                             File[] thirdLevelFolders = checkFiles(folder.listFiles());
 321                             if (thirdLevelFolders != null && thirdLevelFolders.length > 0) {
 322                                 List<File> thirdLevelFoldersList = Arrays.asList(thirdLevelFolders);
 323 
 324                                 folder.sortChildren(thirdLevelFoldersList);
 325                                 folders.addAll(thirdLevelFoldersList);
 326                             }
 327                         }
 328                     }
 329                 }
 330                 return checkFiles(folders);
 331             } else {
 332                 return super.get(key);
 333             }
 334         } else if (key.equals("fileChooserShortcutPanelFolders")) {
 335             Toolkit toolkit = Toolkit.getDefaultToolkit();
 336             ArrayList<File> folders = new ArrayList<File>();
 337             int i = 0;
 338             Object value;
 339             do {
 340                 value = toolkit.getDesktopProperty("win.comdlg.placesBarPlace" + i++);
 341                 try {
 342                     if (value instanceof Integer) {
 343                         // A CSIDL
 344                         folders.add(new Win32ShellFolder2((Integer)value));
 345                     } else if (value instanceof String) {
 346                         // A path
 347                         folders.add(createShellFolder(new File((String)value)));
 348                     }
 349                 } catch (IOException e) {
 350                     if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 351                         log.warning("Cannot read value = " + value, e);
 352                     }
 353                     // Skip this value
 354                 } catch (InterruptedException e) {
 355                     if (log.isLoggable(PlatformLogger.Level.WARNING)) {
 356                         log.warning("Cannot read value = " + value, e);
 357                     }
 358                     // Return empty result
 359                     return new File[0];
 360                 }
 361             } while (value != null);
 362 
 363             if (folders.size() == 0) {
 364                 // Use default list of places
 365                 for (File f : new File[] {
 366                     getRecent(), getDesktop(), getPersonal(), getDrives(), getNetwork()
 367                 }) {
 368                     if (f != null) {
 369                         folders.add(f);
 370                     }
 371                 }
 372             }
 373             return checkFiles(folders);
 374         } else if (key.startsWith("fileChooserIcon ")) {
 375             String name = key.substring(key.indexOf(" ") + 1);
 376 
 377             int iconIndex;
 378 
 379             if (name.equals("ListView") || name.equals("ViewMenu")) {
 380                 iconIndex = VIEW_LIST;
 381             } else if (name.equals("DetailsView")) {
 382                 iconIndex = VIEW_DETAILS;
 383             } else if (name.equals("UpFolder")) {
 384                 iconIndex = VIEW_PARENTFOLDER;
 385             } else if (name.equals("NewFolder")) {
 386                 iconIndex = VIEW_NEWFOLDER;
 387             } else {
 388                 return null;
 389             }
 390 
 391             return getStandardViewButton(iconIndex);
 392         } else if (key.startsWith("optionPaneIcon ")) {
 393             Win32ShellFolder2.SystemIcon iconType;
 394             if (key == "optionPaneIcon Error") {
 395                 iconType = Win32ShellFolder2.SystemIcon.IDI_ERROR;
 396             } else if (key == "optionPaneIcon Information") {
 397                 iconType = Win32ShellFolder2.SystemIcon.IDI_INFORMATION;
 398             } else if (key == "optionPaneIcon Question") {
 399                 iconType = Win32ShellFolder2.SystemIcon.IDI_QUESTION;
 400             } else if (key == "optionPaneIcon Warning") {
 401                 iconType = Win32ShellFolder2.SystemIcon.IDI_EXCLAMATION;
 402             } else {
 403                 return null;
 404             }
 405             return Win32ShellFolder2.getSystemIcon(iconType);
 406         } else if (key.startsWith("shell32Icon ") || key.startsWith("shell32LargeIcon ")) {
 407             String name = key.substring(key.indexOf(" ") + 1);
 408             try {
 409                 int i = Integer.parseInt(name);
 410                 if (i >= 0) {
 411                     return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon "));
 412                 }
 413             } catch (NumberFormatException ex) {
 414             }
 415         }
 416         return null;
 417     }
 418 
 419     private static File checkFile(File file) {
 420         SecurityManager sm = System.getSecurityManager();
 421         return (sm == null || file == null) ? file : checkFile(file, sm);
 422     }
 423 
 424     private static File checkFile(File file, SecurityManager sm) {
 425         try {
 426             sm.checkRead(file.getPath());
 427 
 428             if (file instanceof Win32ShellFolder2) {
 429                 Win32ShellFolder2 f = (Win32ShellFolder2)file;
 430                 if (f.isLink()) {
 431                     Win32ShellFolder2 link = (Win32ShellFolder2)f.getLinkLocation();
 432                     if (link != null)
 433                         sm.checkRead(link.getPath());
 434                 }
 435             }
 436             return file;
 437         } catch (SecurityException se) {
 438             return null;
 439         }
 440     }
 441 
 442     static File[] checkFiles(File[] files) {
 443         SecurityManager sm = System.getSecurityManager();
 444         if (sm == null || files == null || files.length == 0) {
 445             return files;
 446         }
 447         return checkFiles(Arrays.stream(files), sm);
 448     }
 449 
 450     private static File[] checkFiles(List<File> files) {
 451         SecurityManager sm = System.getSecurityManager();
 452         if (sm == null || files.isEmpty()) {
 453             return files.toArray(new File[files.size()]);
 454         }
 455         return checkFiles(files.stream(), sm);
 456     }
 457 
 458     private static File[] checkFiles(Stream<File> filesStream, SecurityManager sm) {
 459         return filesStream.filter((file) -> checkFile(file, sm) != null)
 460                 .toArray(File[]::new);
 461     }
 462 
 463     /**
 464      * Does {@code dir} represent a "computer" such as a node on the network, or
 465      * "My Computer" on the desktop.
 466      */
 467     public boolean isComputerNode(final File dir) {
 468         if (dir != null && dir == getDrives()) {
 469             return true;
 470         } else {
 471             String path = AccessController.doPrivileged(new PrivilegedAction<String>() {
 472                 public String run() {
 473                     return dir.getAbsolutePath();
 474                 }
 475             });
 476 
 477             return (path.startsWith("\\\\") && path.indexOf("\\", 2) < 0);      //Network path
 478         }
 479     }
 480 
 481     public boolean isFileSystemRoot(File dir) {
 482         //Note: Removable drives don't "exist" but are listed in "My Computer"
 483         if (dir != null) {
 484 
 485             if (dir instanceof Win32ShellFolder2) {
 486                 Win32ShellFolder2 sf = (Win32ShellFolder2)dir;
 487 
 488                 //This includes all the drives under "My PC" or "My Computer.
 489                 // On windows 10, "External Drives" are listed under "Desktop"
 490                 // also
 491                 return  (sf.isFileSystem() && sf.parent != null &&
 492                         (sf.parent.equals (getDrives()) ||
 493                         (sf.parent.equals (getDesktop()) && isDrive(dir))));
 494             }
 495             return isDrive(dir);
 496         }
 497         return false;
 498     }
 499 
 500     private boolean isDrive(File dir) {
 501         String path = dir.getPath();
 502         if (path.length() != 3 || path.charAt(1) != ':') {
 503             return false;
 504         }
 505         File[] roots = Win32ShellFolder2.listRoots();
 506         return roots != null && Arrays.asList(roots).contains(dir);
 507     }
 508 
 509     private static List<Win32ShellFolder2> topFolderList = null;
 510     static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
 511         boolean special1 = sf1.isSpecial();
 512         boolean special2 = sf2.isSpecial();
 513 
 514         if (special1 || special2) {
 515             if (topFolderList == null) {
 516                 ArrayList<Win32ShellFolder2> tmpTopFolderList = new ArrayList<>();
 517                 tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
 518                 tmpTopFolderList.add(Win32ShellFolderManager2.getDesktop());
 519                 tmpTopFolderList.add(Win32ShellFolderManager2.getDrives());
 520                 tmpTopFolderList.add(Win32ShellFolderManager2.getNetwork());
 521                 topFolderList = tmpTopFolderList;
 522             }
 523             int i1 = topFolderList.indexOf(sf1);
 524             int i2 = topFolderList.indexOf(sf2);
 525             if (i1 >= 0 && i2 >= 0) {
 526                 return (i1 - i2);
 527             } else if (i1 >= 0) {
 528                 return -1;
 529             } else if (i2 >= 0) {
 530                 return 1;
 531             }
 532         }
 533 
 534         // Non-file shellfolders sort before files
 535         if (special1 && !special2) {
 536             return -1;
 537         } else if (special2 && !special1) {
 538             return  1;
 539         }
 540 
 541         return compareNames(sf1.getAbsolutePath(), sf2.getAbsolutePath());
 542     }
 543 
 544     static int compareNames(String name1, String name2) {
 545         // First ignore case when comparing
 546         int diff = name1.compareToIgnoreCase(name2);
 547         if (diff != 0) {
 548             return diff;
 549         } else {
 550             // May differ in case (e.g. "mail" vs. "Mail")
 551             // We need this test for consistent sorting
 552             return name1.compareTo(name2);
 553         }
 554     }
 555 
 556     @Override
 557     protected Invoker createInvoker() {
 558         return new ComInvoker();
 559     }
 560 
 561     private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker {
 562         private static Thread comThread;
 563 
 564         private ComInvoker() {
 565             super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue<>());
 566             allowCoreThreadTimeOut(false);
 567             setThreadFactory(this);
 568             final Runnable shutdownHook = () -> AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
 569                 shutdownNow();
 570                 return null;
 571             });
 572             AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
 573                 Thread t = new Thread(
 574                         ThreadGroupUtils.getRootThreadGroup(), shutdownHook,
 575                         "ShellFolder", 0, false);
 576                 Runtime.getRuntime().addShutdownHook(t);
 577                 return null;
 578             });
 579         }
 580 
 581         public synchronized Thread newThread(final Runnable task) {
 582             final Runnable comRun = new Runnable() {
 583                 public void run() {
 584                     try {
 585                         initializeCom();
 586                         task.run();
 587                     } finally {
 588                         uninitializeCom();
 589                     }
 590                 }
 591             };
 592             comThread = AccessController.doPrivileged((PrivilegedAction<Thread>) () -> {
 593                 String name = "Swing-Shell";
 594                  /* The thread must be a member of a thread group
 595                   * which will not get GCed before VM exit.
 596                   * Make its parent the top-level thread group.
 597                   */
 598                 Thread thread = new Thread(
 599                         ThreadGroupUtils.getRootThreadGroup(), comRun, name,
 600                         0, false);
 601                 thread.setDaemon(true);
 602                 /* This is important, since this thread running at lower priority
 603                    leads to memory consumption when listDrives() function is called
 604                    repeatedly.
 605                  */
 606                 thread.setPriority(Thread.MAX_PRIORITY);
 607                 return thread;
 608             });
 609             return comThread;
 610         }
 611 
 612         public <T> T invoke(Callable<T> task) throws Exception {
 613             if (Thread.currentThread() == comThread) {
 614                 // if it's already called from the COM
 615                 // thread, we don't need to delegate the task
 616                 return task.call();
 617             } else {
 618                 final Future<T> future;
 619 
 620                 try {
 621                     future = submit(task);
 622                 } catch (RejectedExecutionException e) {
 623                     throw new InterruptedException(e.getMessage());
 624                 }
 625 
 626                 try {
 627                     return future.get();
 628                 } catch (InterruptedException e) {
 629                     AccessController.doPrivileged(new PrivilegedAction<Void>() {
 630                         public Void run() {
 631                             future.cancel(true);
 632 
 633                             return null;
 634                         }
 635                     });
 636 
 637                     throw e;
 638                 } catch (ExecutionException e) {
 639                     Throwable cause = e.getCause();
 640 
 641                     if (cause instanceof Exception) {
 642                         throw (Exception) cause;
 643                     }
 644 
 645                     if (cause instanceof Error) {
 646                         throw (Error) cause;
 647                     }
 648 
 649                     throw new RuntimeException("Unexpected error", cause);
 650                 }
 651             }
 652         }
 653     }
 654 
 655     static native void initializeCom();
 656 
 657     static native void uninitializeCom();
 658 }