2
* Created on 13-Mar-2004
4
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
* AELITIS, SAS au capital de 46,603.30 euros
19
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
23
package org.gudy.azureus2.platform.macosx;
25
import org.gudy.azureus2.core3.logging.*;
26
import org.gudy.azureus2.core3.util.AEMonitor;
27
import org.gudy.azureus2.core3.util.Debug;
28
import org.gudy.azureus2.core3.util.SystemProperties;
29
import org.gudy.azureus2.platform.PlatformManager;
30
import org.gudy.azureus2.platform.PlatformManagerCapabilities;
31
import org.gudy.azureus2.platform.PlatformManagerListener;
32
import org.gudy.azureus2.platform.macosx.access.jnilib.OSXAccess;
34
import org.gudy.azureus2.plugins.platform.PlatformManagerException;
36
import java.io.BufferedReader;
38
import java.io.IOException;
39
import java.io.InputStreamReader;
40
import java.text.MessageFormat;
41
import java.util.HashSet;
45
* Performs platform-specific operations with Mac OS X
48
* @version 1.0 Initial Version
49
* @see PlatformManager
51
public class PlatformManagerImpl implements PlatformManager
53
private static final LogIDs LOGID = LogIDs.CORE;
55
protected static PlatformManagerImpl singleton;
56
protected static AEMonitor class_mon = new AEMonitor("PlatformManager");
58
private static final String USERDATA_PATH = new File(System.getProperty("user.home") + "/Library/Application Support/").getPath();
60
//T: PlatformManagerCapabilities
61
private final HashSet capabilitySet = new HashSet();
64
* Gets the platform manager singleton, which was already initialized
66
public static PlatformManagerImpl getSingleton()
72
* Tries to enable cocoa-java access and instantiates the singleton
76
initializeSingleton();
80
* Instantiates the singleton
82
private static void initializeSingleton()
87
singleton = new PlatformManagerImpl();
91
Logger.log(new LogEvent(LOGID, "Failed to initialize platform manager"
92
+ " for Mac OS X", e));
101
* Creates a new PlatformManager and initializes its capabilities
103
public PlatformManagerImpl()
105
capabilitySet.add(PlatformManagerCapabilities.RecoverableFileDelete);
106
capabilitySet.add(PlatformManagerCapabilities.ShowFileInBrowser);
107
capabilitySet.add(PlatformManagerCapabilities.ShowPathInCommandLine);
108
capabilitySet.add(PlatformManagerCapabilities.CreateCommandLineProcess);
109
capabilitySet.add(PlatformManagerCapabilities.GetUserDataDirectory);
110
capabilitySet.add(PlatformManagerCapabilities.UseNativeScripting);
111
capabilitySet.add(PlatformManagerCapabilities.PlaySystemAlert);
113
if (OSXAccess.isLoaded()) {
114
capabilitySet.add(PlatformManagerCapabilities.GetVersion);
121
public int getPlatformType()
129
public String getVersion() throws PlatformManagerException
131
if (!OSXAccess.isLoaded()) {
132
throw new PlatformManagerException("Unsupported capability called on platform manager");
135
return OSXAccess.getVersion();
140
* @see org.gudy.azureus2.core3.util.SystemProperties#getUserPath()
142
public String getUserDataDirectory() throws PlatformManagerException
144
return USERDATA_PATH;
151
throws PlatformManagerException
153
if ( location_id == LOC_USER_DATA ){
155
return( new File( USERDATA_PATH ));
161
* Not implemented; returns True
163
public boolean isApplicationRegistered() throws PlatformManagerException
170
getApplicationCommandLine()
171
throws PlatformManagerException
174
String bundle_path = System.getProperty("user.dir") +SystemProperties.SEP+ SystemProperties.getApplicationName() + ".app";
176
File osx_app_bundle = new File( bundle_path ).getAbsoluteFile();
178
if( !osx_app_bundle.exists() ) {
179
String msg = "OSX app bundle not found: [" +osx_app_bundle.toString()+ "]";
180
System.out.println( msg );
181
if (Logger.isEnabled())
182
Logger.log(new LogEvent(LOGID, msg));
183
throw new PlatformManagerException( msg );
186
return "open -a \"" +osx_app_bundle.toString()+ "\"";
187
//return osx_app_bundle.toString() +"/Contents/MacOS/JavaApplicationStub";
190
catch( Throwable t ){
198
isAdditionalFileTypeRegistered(
199
String name, // e.g. "BitTorrent"
200
String type ) // e.g. ".torrent"
202
throws PlatformManagerException
204
throw new PlatformManagerException("Unsupported capability called on platform manager");
208
unregisterAdditionalFileType(
209
String name, // e.g. "BitTorrent"
210
String type ) // e.g. ".torrent"
212
throws PlatformManagerException
214
throw new PlatformManagerException("Unsupported capability called on platform manager");
218
registerAdditionalFileType(
219
String name, // e.g. "BitTorrent"
220
String description, // e.g. "BitTorrent File"
221
String type, // e.g. ".torrent"
222
String content_type ) // e.g. "application/x-bittorrent"
224
throws PlatformManagerException
226
throw new PlatformManagerException("Unsupported capability called on platform manager");
230
* Not implemented; does nothing
232
public void registerApplication() throws PlatformManagerException
234
// handled by LaunchServices and/0r user interaction
240
public void createProcess(String cmd, boolean inheritsHandles) throws PlatformManagerException
244
performRuntimeExec(cmd.split(" "));
248
throw new PlatformManagerException("Failed to create process", e);
255
public void performRecoverableFileDelete(String path) throws PlatformManagerException
257
File file = new File(path);
260
if (Logger.isEnabled())
261
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "Cannot find "
266
boolean useOSA = !NativeInvocationBridge.sharedInstance().isEnabled() || !NativeInvocationBridge.sharedInstance().performRecoverableFileDelete(file);
272
StringBuffer sb = new StringBuffer();
273
sb.append("tell application \"");
275
sb.append("\" to move (posix file \"");
277
sb.append("\" as alias) to the trash");
279
performOSAScript(sb);
283
throw new PlatformManagerException("Failed to move file", e);
291
public boolean hasCapability(PlatformManagerCapabilities capability)
293
return capabilitySet.contains(capability);
299
public void dispose()
301
NativeInvocationBridge.sharedInstance().dispose();
307
public void setTCPTOSEnabled(boolean enabled) throws PlatformManagerException
309
throw new PlatformManagerException("Unsupported capability called on platform manager");
314
String from_file_name,
315
String to_file_name )
317
throws PlatformManagerException
319
throw new PlatformManagerException("Unsupported capability called on platform manager");
325
public void showFile(String path) throws PlatformManagerException
327
File file = new File(path);
330
if (Logger.isEnabled())
331
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "Cannot find "
333
throw new PlatformManagerException("File not found");
339
// Public utility methods not shared across the interface
342
* Plays the system alert (the jingle is specified by the user in System Preferences)
344
public void playSystemAlert()
348
performRuntimeExec(new String[]{"beep"});
350
catch (IOException e)
352
if (Logger.isEnabled())
353
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
354
"Cannot play system alert"));
355
Logger.log(new LogEvent(LOGID, "", e));
360
* <p>Shows the given file or directory in Finder</p>
361
* @param path Absolute path to the file or directory
363
public void showInFinder(File path)
365
boolean useOSA = !NativeInvocationBridge.sharedInstance().isEnabled() || !NativeInvocationBridge.sharedInstance().showInFinder(path);
369
StringBuffer sb = new StringBuffer();
370
sb.append("tell application \"");
371
sb.append(getFileBrowserName());
372
sb.append("\" to reveal (posix file \"");
374
sb.append("\" as alias)");
378
performOSAScript(sb);
380
catch (IOException e)
382
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, e
389
* <p>Shows the given file or directory in Terminal by executing cd /absolute/path/to</p>
390
* @param path Absolute path to the file or directory
392
public void showInTerminal(String path)
394
showInTerminal(new File(path));
398
* <p>Shows the given file or directory in Terminal by executing cd /absolute/path/to</p>
399
* @param path Absolute path to the file or directory
401
public void showInTerminal(File path)
405
path = path.getParentFile();
408
if (path != null && path.isDirectory())
410
StringBuffer sb = new StringBuffer();
411
sb.append("tell application \"");
412
sb.append("Terminal");
413
sb.append("\" to do script \"cd ");
414
sb.append(path.getAbsolutePath().replaceAll(" ", "\\ "));
419
performOSAScript(sb);
421
catch (IOException e)
423
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, e
429
if (Logger.isEnabled())
430
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "Cannot find "
435
// Internal utility methods
438
* Compiles a new AppleScript instance and runs it
439
* @param cmd AppleScript command to execute; do not surround command with extra quotation marks
440
* @return Output of the script
441
* @throws IOException If the script failed to execute
443
protected static String performOSAScript(CharSequence cmd) throws IOException
445
return performOSAScript(new CharSequence[]{cmd});
449
* Compiles a new AppleScript instance and runs it
450
* @param cmds AppleScript Sequence of commands to execute; do not surround command with extra quotation marks
451
* @return Output of the script
452
* @throws IOException If the script failed to execute
454
protected static String performOSAScript(CharSequence[] cmds) throws IOException
456
long start = System.currentTimeMillis();
457
Debug.outNoStack("Executing OSAScript: ");
458
for (int i = 0; i < cmds.length; i++)
460
Debug.outNoStack("\t" + cmds[i]);
463
String[] cmdargs = new String[2 * cmds.length + 1];
464
cmdargs[0] = "osascript";
465
for (int i = 0; i < cmds.length; i++)
467
cmdargs[i * 2 + 1] = "-e";
468
cmdargs[i * 2 + 2] = String.valueOf(cmds[i]);
471
Process osaProcess = performRuntimeExec(cmdargs);
472
BufferedReader reader = new BufferedReader(new InputStreamReader(osaProcess.getInputStream()));
473
String line = reader.readLine();
475
Debug.outNoStack("OSAScript Output: " + line);
477
reader = new BufferedReader(new InputStreamReader(osaProcess.getErrorStream()));
478
String errorMsg = reader.readLine();
481
Debug.outNoStack("OSAScript Error (if any): " + errorMsg);
483
Debug.outNoStack(MessageFormat.format("OSAScript execution ended ({0}ms)", new Object[]{String.valueOf(System.currentTimeMillis() - start)}));
485
if (errorMsg != null)
487
throw new IOException(errorMsg);
494
* Compiles a new AppleScript instance and runs it
495
* @param script AppleScript file (.scpt) to execute
496
* @return Output of the script
497
* @throws IOException If the script failed to execute
499
protected static String performOSAScript(File script) throws IOException
501
long start = System.currentTimeMillis();
502
Debug.outNoStack("Executing OSAScript from file: " + script.getPath());
504
Process osaProcess = performRuntimeExec(new String[]{"osascript", script.getPath()});
505
BufferedReader reader = new BufferedReader(new InputStreamReader(osaProcess.getInputStream()));
506
String line = reader.readLine();
508
Debug.outNoStack("OSAScript Output: " + line);
510
reader = new BufferedReader(new InputStreamReader(osaProcess.getErrorStream()));
511
String errorMsg = reader.readLine();
514
Debug.outNoStack("OSAScript Error (if any): " + errorMsg);
516
Debug.outNoStack(MessageFormat.format("OSAScript execution ended ({0}ms)", new Object[]{String.valueOf(System.currentTimeMillis() - start)}));
518
if (errorMsg != null)
520
throw new IOException(errorMsg);
527
* Compiles a new AppleScript instance to the specified location
528
* @param cmd Command to compile; do not surround command with extra quotation marks
529
* @param destination Destination location of the AppleScript file
530
* @return True if compiled successfully
532
protected static boolean compileOSAScript(CharSequence cmd, File destination)
534
return compileOSAScript(new CharSequence[]{cmd}, destination);
538
* Compiles a new AppleScript instance to the specified location
539
* @param cmds Sequence of commands to compile; do not surround command with extra quotation marks
540
* @param destination Destination location of the AppleScript file
541
* @return True if compiled successfully
543
protected static boolean compileOSAScript(CharSequence[] cmds, File destination)
545
long start = System.currentTimeMillis();
546
Debug.outNoStack("Compiling OSAScript: " + destination.getPath());
547
for (int i = 0; i < cmds.length; i++)
549
Debug.outNoStack("\t" + cmds[i]);
552
String[] cmdargs = new String[2 * cmds.length + 3];
553
cmdargs[0] = "osacompile";
554
for (int i = 0; i < cmds.length; i++)
556
cmdargs[i * 2 + 1] = "-e";
557
cmdargs[i * 2 + 2] = String.valueOf(cmds[i]);
560
cmdargs[cmdargs.length - 2] = "-o";
561
cmdargs[cmdargs.length - 1] = destination.getPath();
566
Process osaProcess = performRuntimeExec(cmdargs);
568
BufferedReader reader = new BufferedReader(new InputStreamReader(osaProcess.getErrorStream()));
569
errorMsg = reader.readLine();
572
catch (IOException e)
574
Debug.outNoStack("OSACompile Execution Failed: " + e.getMessage());
575
Debug.printStackTrace(e);
579
Debug.outNoStack("OSACompile Error (if any): " + errorMsg);
581
Debug.outNoStack(MessageFormat.format("OSACompile execution ended ({0}ms)", new Object[]{String.valueOf(System.currentTimeMillis() - start)}));
583
return (errorMsg == null);
587
* @see Runtime#exec(String[])
589
protected static Process performRuntimeExec(String[] cmdargs) throws IOException
593
return Runtime.getRuntime().exec(cmdargs);
595
catch (IOException e)
597
Logger.log(new LogAlert(LogAlert.UNREPEATABLE, e.getMessage(), e));
603
* <p>Gets the preferred file browser name</p>
604
* <p>Currently supported browsers are Path Finder and Finder. If Path Finder is currently running
605
* (not just installed), then "Path Finder is returned; else, "Finder" is returned.</p>
606
* @return "Path Finder" if it is currently running; else "Finder"
608
private static String getFileBrowserName()
613
if ("true".equalsIgnoreCase(performOSAScript("tell application \"System Events\" to exists process \"Path Finder\"")))
615
Debug.outNoStack("Path Finder is running");
617
return "Path Finder";
624
catch (IOException e)
626
Debug.printStackTrace(e);
627
Logger.log(new LogEvent(LOGID, e.getMessage(), e));
634
testNativeAvailability(
637
throws PlatformManagerException
639
throw new PlatformManagerException("Unsupported capability called on platform manager");
644
PlatformManagerListener listener )
650
PlatformManagerListener listener )