diff --git a/client/build.gradle b/client/build.gradle
index a3ffca4acc..bcb71aff13 100644
--- a/client/build.gradle
+++ b/client/build.gradle
@@ -129,8 +129,6 @@ tasks.register('devClient', JavaExec) {
'--add-opens=java.base/sun.security.pkcs=ALL-UNNAMED',
'--add-opens=java.base/sun.security.rsa=ALL-UNNAMED',
'--add-opens=java.base/sun.security.x509=ALL-UNNAMED',
- '--add-opens=java.desktop/com.apple.eawt=ALL-UNNAMED',
- '--add-opens=java.desktop/com.apple.eio=ALL-UNNAMED',
'--add-opens=java.desktop/java.awt=ALL-UNNAMED',
'--add-opens=java.desktop/java.awt.color=ALL-UNNAMED',
'--add-opens=java.desktop/java.awt.font=ALL-UNNAMED',
diff --git a/client/src/main/java/com/mirth/connect/client/ui/BareBonesBrowserLaunch.java b/client/src/main/java/com/mirth/connect/client/ui/BareBonesBrowserLaunch.java
index a45efb7e79..f171475c63 100644
--- a/client/src/main/java/com/mirth/connect/client/ui/BareBonesBrowserLaunch.java
+++ b/client/src/main/java/com/mirth/connect/client/ui/BareBonesBrowserLaunch.java
@@ -4,6 +4,8 @@
package com.mirth.connect.client.ui;
+import java.awt.Desktop;
+import java.net.URI;
import java.util.Arrays;
/**
@@ -40,31 +42,17 @@ public class BareBonesBrowserLaunch {
* "https://dna-engine.org/")
*/
public static void openURL(String url) {
- try { // attempt to use Desktop library from JDK 1.6+
- Class> d = Class.forName("java.awt.Desktop");
- d.getDeclaredMethod("browse",
- new Class>[] { java.net.URI.class }).invoke(
- d.getDeclaredMethod("getDesktop").invoke(null),
- new Object[] { java.net.URI.create(url) });
- } catch (Exception ignore) { // library not available or failed
- String osName = System.getProperty("os.name");
+ try {
+ Desktop.getDesktop().browse(URI.create(url));
+ } catch (Exception ignore) { // Desktop not supported or failed, assume Unix or Linux
try {
- if (osName.startsWith("Mac OS")) {
- Class.forName("com.apple.eio.FileManager").getDeclaredMethod(
- "openURL", new Class>[] { String.class }).invoke(null,
- new Object[] { url });
- } else if (osName.startsWith("Windows"))
- Runtime.getRuntime().exec(new String[] {
- "rundll32", "url.dll,FileProtocolHandler", url });
- else { // assume Unix or Linux
- String browser = null;
- for (String b : browsers)
- if (browser == null
- && Runtime.getRuntime().exec(new String[] { "which", b }).getInputStream().read() != -1)
- Runtime.getRuntime().exec(new String[] { browser = b, url });
- if (browser == null)
- throw new Exception(Arrays.toString(browsers));
- }
+ String browser = null;
+ for (String b : browsers)
+ if (browser == null
+ && Runtime.getRuntime().exec(new String[] { "which", b }).getInputStream().read() != -1)
+ Runtime.getRuntime().exec(new String[] { browser = b, url });
+ if (browser == null)
+ throw new Exception(Arrays.toString(browsers));
} catch (Exception e) {
PlatformUI.MIRTH_FRAME.alertThrowable(PlatformUI.MIRTH_FRAME, e);
}
diff --git a/client/src/main/java/com/mirth/connect/client/ui/Mirth.java b/client/src/main/java/com/mirth/connect/client/ui/Mirth.java
index 0145252b6f..0dca370135 100644
--- a/client/src/main/java/com/mirth/connect/client/ui/Mirth.java
+++ b/client/src/main/java/com/mirth/connect/client/ui/Mirth.java
@@ -175,9 +175,20 @@ public static void initUIManager() {
createAlternateKeyBindings();
}
- if (SystemUtils.IS_OS_MAC) {
- OSXAdapter.setAboutHandler(Mirth.class, Mirth.class.getDeclaredMethod("aboutMac", (Class[]) null));
- OSXAdapter.setQuitHandler(Mirth.class, Mirth.class.getDeclaredMethod("quitMac", (Class[]) null));
+ if (Desktop.isDesktopSupported()) {
+ Desktop desktop = Desktop.getDesktop();
+ if (desktop.isSupported(Desktop.Action.APP_ABOUT)) {
+ desktop.setAboutHandler(e -> aboutMac());
+ }
+ if (desktop.isSupported(Desktop.Action.APP_QUIT_HANDLER)) {
+ desktop.setQuitHandler((e, response) -> {
+ if (quitMac()) {
+ response.performQuit();
+ } else {
+ response.cancelQuit();
+ }
+ });
+ }
}
} catch (Exception e) {
LogManager.getLogger(Mirth.class).error("Error initializing look and feel", e);
diff --git a/client/src/main/java/com/mirth/connect/client/ui/OSXAdapter.java b/client/src/main/java/com/mirth/connect/client/ui/OSXAdapter.java
deleted file mode 100644
index 403ab3f3e0..0000000000
--- a/client/src/main/java/com/mirth/connect/client/ui/OSXAdapter.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- *
- * File: OSXAdapter.java
- *
- * Abstract: Hooks existing preferences/about/quit functionality from an existing Java app into
- * handlers for the Mac OS X application menu. Uses a Proxy object to dynamically implement the
- * com.apple.eawt.ApplicationListener interface and register it with the com.apple.eawt.Application
- * object. This allows the complete project to be both built and run on any platform without any
- * stubs or placeholders. Useful for developers looking to implement Mac OS X features while
- * supporting multiple platforms with minimal impact.
- *
- * Version: 2.0
- *
- * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple") in
- * consideration of your agreement to the following terms, and your use, installation, modification
- * or redistribution of this Apple software constitutes acceptance of these terms. If you do not
- * agree with these terms, please do not use, install, modify or redistribute this Apple software.
- *
- * In consideration of your agreement to abide by the following terms, and subject to these terms,
- * Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original
- * Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple
- * Software, with or without modifications, in source and/or binary forms; provided that if you
- * redistribute the Apple Software in its entirety and without modifications, you must retain this
- * notice and the following text and disclaimers in all such redistributions of the Apple Software.
- * Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or
- * promote products derived from the Apple Software without specific prior written permission from
- * Apple. Except as expressly stated in this notice, no other rights or licenses, express or
- * implied, are granted by Apple herein, including but not limited to any patent rights that may be
- * infringed by your derivative works or by other works in which the Apple Software may be
- * incorporated.
- *
- * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS
- * OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
- *
- * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- * OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
- * OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Copyright (c) 2003-2007 Apple, Inc., All Rights Reserved
- *
- */
-
-package com.mirth.connect.client.ui;
-
-import java.io.File;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.security.AccessController;
-import java.util.List;
-
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.glassfish.jersey.internal.util.ReflectionHelper;
-
-public class OSXAdapter implements InvocationHandler {
- private static Logger logger = LogManager.getLogger(OSXAdapter.class);
-
- protected Object targetObject;
- protected Method targetMethod;
- protected String proxySignature;
-
- static Object macOSXApplication;
-
- // Pass this method an Object and Method equipped to perform application shutdown logic
- // The method passed should return a boolean stating whether or not the quit should occur
- public static void setQuitHandler(final Object target, final Method quitHandler) {
- try {
- if (isJava9OrGreater()) {
- InvocationHandler invocationHandler = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("handleQuitRequestWith")) {
- boolean quit = (boolean) quitHandler.invoke(target);
- Object quitResponse = args[1];
- quitResponse.getClass().getMethod(quit ? "performQuit" : "cancelQuit").invoke(quitResponse);
- }
- return null;
- }
- };
-
- setHandler(invocationHandler, "java.awt.desktop.QuitHandler", "setQuitHandler");
- } else {
- setHandler(new OSXAdapter("handleQuit", target, quitHandler));
- }
- } catch (Exception ex) {
- logger.error("OSXAdapter could not set quit handler", ex);
- }
- }
-
- // Pass this method an Object and Method equipped to display application info
- // They will be called when the About menu item is selected from the application menu
- public static void setAboutHandler(Object target, Method aboutHandler) {
- boolean enableAboutMenu = (target != null && aboutHandler != null);
-
- try {
- if (isJava9OrGreater()) {
- if (enableAboutMenu) {
- setHandler(new OSXAdapter("handleAbout", target, aboutHandler), "java.awt.desktop.AboutHandler", "setAboutHandler");
- }
- } else {
- if (enableAboutMenu) {
- setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
- }
- // If we're setting a handler, enable the About menu item by calling
- // com.apple.eawt.Application reflectively
- Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] {
- boolean.class });
- enableAboutMethod.invoke(macOSXApplication, new Object[] {
- Boolean.valueOf(enableAboutMenu) });
- }
- } catch (Exception ex) {
- logger.error("OSXAdapter could not access the About Menu", ex);
- }
- }
-
- // Pass this method an Object and a Method equipped to display application options
- // They will be called when the Preferences menu item is selected from the application menu
- public static void setPreferencesHandler(Object target, Method prefsHandler) {
- boolean enablePrefsMenu = (target != null && prefsHandler != null);
- try {
- if (isJava9OrGreater()) {
- if (enablePrefsMenu) {
- setHandler(new OSXAdapter("handlePreferences", target, prefsHandler), "java.awt.desktop.PreferencesHandler", "setPreferencesHandler");
- }
- } else {
- if (enablePrefsMenu) {
- setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
- }
- // If we're setting a handler, enable the Preferences menu item by calling
- // com.apple.eawt.Application reflectively
- Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] {
- boolean.class });
- enablePrefsMethod.invoke(macOSXApplication, new Object[] {
- Boolean.valueOf(enablePrefsMenu) });
- }
- } catch (Exception ex) {
- logger.error("OSXAdapter could not set preferences handler", ex);
- }
- }
-
- // Pass this method an Object and a Method equipped to handle document events from the Finder
- // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
- // application bundle's Info.plist
- public static void setFileHandler(final Object target, final Method fileHandler) {
- try {
- if (isJava9OrGreater()) {
- InvocationHandler invocationHandler = new InvocationHandler() {
- @Override
- @SuppressWarnings("unchecked")
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("openFiles")) {
- Object event = args[0];
- List files = (List) event.getClass().getMethod("getFiles").invoke(event);
- String searchTerm = (String) event.getClass().getMethod("getSearchTerm").invoke(event);
- fileHandler.invoke(target, files, searchTerm);
- }
- return null;
- }
- };
-
- setHandler(invocationHandler, "java.awt.desktop.OpenFilesHandler", "setOpenFileHandler");
- } else {
- setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
- // Override OSXAdapter.callTarget to send information on the
- // file to be opened
- public boolean callTarget(Object appleEvent) {
- if (appleEvent != null) {
- try {
- Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[]) null);
- String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[]) null);
- this.targetMethod.invoke(this.targetObject, new Object[] {
- filename });
- } catch (Exception ex) {
-
- }
- }
- return true;
- }
- });
- }
- } catch (Exception ex) {
- logger.error("OSXAdapter could not set open files handler", ex);
- }
- }
-
- // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
- public static void setHandler(OSXAdapter adapter) {
- try {
- Object application = getApplication();
- Class applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
- Method addListenerMethod = application.getClass().getDeclaredMethod("addApplicationListener", new Class[] {
- applicationListenerClass });
- // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
- Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] {
- applicationListenerClass }, adapter);
- addListenerMethod.invoke(application, new Object[] { osxAdapterProxy });
- } catch (ClassNotFoundException cnfe) {
- System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")");
- } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
- logger.error("Mac OS X Adapter could not talk to EAWT", ex);
- }
- }
-
- // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
- // the Object that will ultimately perform the task, and the Method to be called on that Object
- protected OSXAdapter(String proxySignature, Object target, Method handler) {
- this.proxySignature = proxySignature;
- this.targetObject = target;
- this.targetMethod = handler;
- }
-
- // Override this method to perform any operations on the event
- // that comes with the various callbacks
- // See setFileHandler above for an example
- public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
- Object result = targetMethod.invoke(targetObject, (Object[]) null);
- if (result == null) {
- return true;
- }
- return Boolean.valueOf(result.toString()).booleanValue();
- }
-
- // InvocationHandler implementation
- // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (isCorrectMethod(method, args)) {
- boolean handled = callTarget(args[0]);
- setApplicationEventHandled(args[0], handled);
- }
- // All of the ApplicationListener methods are void; return null regardless of what happens
- return null;
- }
-
- // Compare the method that was called to the intended method when the OSXAdapter instance was created
- // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
- protected boolean isCorrectMethod(Method method, Object[] args) {
- return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
- }
-
- // It is important to mark the ApplicationEvent as handled and cancel the default behavior
- // This method checks for a boolean result from the proxy method and sets the event accordingly
- protected void setApplicationEventHandled(Object event, boolean handled) {
- if (event != null && !isJava9OrGreater()) {
- try {
- Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] {
- boolean.class });
- // If the target method returns a boolean, use that as a hint
- setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
- } catch (Exception ex) {
- logger.error("OSXAdapter was unable to handle an ApplicationEvent: " + event, ex);
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- protected static Object getApplication() throws Exception {
- if (macOSXApplication == null) {
- Class applicationClass = Class.forName("com.apple.eawt.Application");
-
- if (isJava9OrGreater()) {
- macOSXApplication = applicationClass.getMethod("getApplication").invoke(null);
- } else {
- macOSXApplication = applicationClass.getConstructor((Class[]) null).newInstance((Object[]) null);
- }
- }
-
- return macOSXApplication;
- }
-
- @SuppressWarnings("removal")
- protected static void setHandler(InvocationHandler adapter, String interfaceName, String applicationSetter) throws Exception {
- Class> handlerInterface = Class.forName(interfaceName);
- Object handlerImpl = Proxy.newProxyInstance(AccessController.doPrivileged(ReflectionHelper.getClassLoaderPA(handlerInterface)), new Class[] {
- handlerInterface }, adapter);
- Object application = getApplication();
- application.getClass().getMethod(applicationSetter, handlerInterface).invoke(application, handlerImpl);
- }
-
- protected static boolean isJava9OrGreater() {
- String version = System.getProperty("java.version");
-
- int index = version.indexOf('-');
- if (index > 0) {
- version = version.substring(0, index);
- }
-
- index = version.indexOf('.');
- if (index > 0) {
- version = version.substring(0, index);
- }
-
- return NumberUtils.toDouble(version) >= 9;
- }
-}
\ No newline at end of file
diff --git a/server/mirth-client.jnlp b/server/mirth-client.jnlp
index 21ebd24c74..4a5754db37 100644
--- a/server/mirth-client.jnlp
+++ b/server/mirth-client.jnlp
@@ -26,7 +26,7 @@
-
+
diff --git a/server/src/test/java/com/mirth/connect/server/servlets/WebStartServletTest.java b/server/src/test/java/com/mirth/connect/server/servlets/WebStartServletTest.java
index 25945adcbf..42d40e02d2 100644
--- a/server/src/test/java/com/mirth/connect/server/servlets/WebStartServletTest.java
+++ b/server/src/test/java/com/mirth/connect/server/servlets/WebStartServletTest.java
@@ -462,7 +462,7 @@ private static String normalizeWhitespace(String input) {
+ " \n" + " \n" + " \n"
+ " \n" + " \n" + " \n" + " \n" + " \n"
+ " \n" + " \n" + " \n" + " \n"
- + " \n"
+ + " \n"
+ " \n"
+ " \n"
+ " \n"