You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/10/02 13:25:16 UTC
[2/3] cayenne git commit: Java 9 support (compile and runtime) - OSX
Wrapper to dynamically use proper app handlers - remove usage of JDK
internals
Java 9 support (compile and runtime)
- OSX Wrapper to dynamically use proper app handlers
- remove usage of JDK internals
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/253887b2
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/253887b2
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/253887b2
Branch: refs/heads/master
Commit: 253887b2daa414fd2e89add8813de7cd2863ffff
Parents: 7ba05f3
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Oct 2 16:21:31 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Oct 2 16:21:31 2017 +0300
----------------------------------------------------------------------
.../modeler/osx/OSXApplicationWrapper.java | 149 +++++++++++++++++++
.../modeler/osx/OSXPlatformInitializer.java | 38 ++---
.../modeler/osx/OSXQuitResponseWrapper.java | 73 +++++++++
.../components/image/FilteredIconFactory.java | 5 +-
4 files changed, 236 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/253887b2/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXApplicationWrapper.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXApplicationWrapper.java b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXApplicationWrapper.java
new file mode 100644
index 0000000..f02bff5
--- /dev/null
+++ b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXApplicationWrapper.java
@@ -0,0 +1,149 @@
+/*****************************************************************
+ * 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.apache.cayenne.modeler.osx;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.function.Consumer;
+
+import com.apple.eawt.Application;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class wraps apple {@link com.apple.eawt.Application} class and dynamically
+ * proxying it's lifecycle handlers setup.
+ * <p>
+ * This code exists to support both Java 8 and 9, as handler interfaces where incompatibly moved
+ * to other package between these versions.
+ * <p>
+ * See <a href="https://bugs.openjdk.java.net/browse/JDK-8160437">JDK-8160437 issue</a> for details.
+ *
+ * @see #setAboutHandler(Runnable) run action on "About App" menu item select
+ * @see #setPreferencesHandler(Runnable) run action on "Preferences..." menu item select
+ * @see #setQuitHandler(Consumer) run action on "Quit App" menu item select
+ *
+ * @see OSXQuitResponseWrapper
+ *
+ * @since 4.1
+ */
+public class OSXApplicationWrapper {
+
+ private static final Logger logger = LoggerFactory.getLogger(OSXApplicationWrapper.class);
+
+ // package for handler classes for Java 8 and older
+ private static final String JAVA8_PACKAGE = "com.apple.eawt.";
+
+ // package for handler classes for Java 9 and newer
+ private static final String JAVA9_PACKAGE = "java.awt.desktop.";
+
+ private final Application application;
+
+ private Class<?> aboutHandlerClass;
+ private Method setAboutHandler;
+
+ private Class<?> preferencesHandlerClass;
+ private Method setPreferencesHandler;
+
+ private Class<?> quitHandlerClass;
+ private Method setQuitHandler;
+
+ public OSXApplicationWrapper(Application application) {
+ this.application = application;
+ initMethods();
+ }
+
+ public void setPreferencesHandler(Runnable action) {
+ setHandler(setPreferencesHandler, preferencesHandlerClass, action);
+ }
+
+ public void setAboutHandler(Runnable action) {
+ setHandler(setAboutHandler, aboutHandlerClass, action);
+ }
+
+ public void setQuitHandler(Consumer<OSXQuitResponseWrapper> action) {
+ InvocationHandler handler = (proxy, method, args) -> {
+ // args: 0 - event, 1 - quitResponse
+ action.accept(new OSXQuitResponseWrapper(args[1]));
+ return null;
+ };
+ Object proxy = createProxy(quitHandlerClass, handler);
+ try {
+ setQuitHandler.invoke(application, proxy);
+ } catch (IllegalAccessException | InvocationTargetException ex) {
+ logger.warn("Unable to call " + setQuitHandler.getName(), ex);
+ }
+ }
+
+ /**
+ * Find required handlers' methods and classes
+ */
+ private void initMethods() {
+ aboutHandlerClass = getHandlerClass("AboutHandler");
+ setAboutHandler = getMethod("setAboutHandler", aboutHandlerClass);
+
+ preferencesHandlerClass = getHandlerClass("PreferencesHandler");
+ setPreferencesHandler = getMethod("setPreferencesHandler", preferencesHandlerClass);
+
+ quitHandlerClass = getHandlerClass("QuitHandler");
+ setQuitHandler = getMethod("setQuitHandler", quitHandlerClass);
+ }
+
+ private void setHandler(Method setMethod, Class<?> handlerClass, Runnable action) {
+ InvocationHandler handler = (proxy, method, args) -> {
+ action.run();
+ return null;
+ };
+ Object proxy = createProxy(handlerClass, handler);
+ try {
+ setMethod.invoke(application, proxy);
+ } catch (IllegalAccessException | InvocationTargetException ex) {
+ logger.warn("Unable to call " + setMethod.getName(), ex);
+ }
+ }
+
+ private Object createProxy(Class<?> handlerClass, InvocationHandler handler) {
+ return Proxy.newProxyInstance(OSXApplicationWrapper.class.getClassLoader(), new Class<?>[]{handlerClass}, handler);
+ }
+
+ private Method getMethod(String name, Class<?> ... parameters) {
+ try {
+ return application.getClass().getMethod(name, parameters);
+ } catch (NoSuchMethodException ex) {
+ logger.warn("Unable to find method " + name, ex);
+ return null;
+ }
+ }
+
+ private Class<?> getHandlerClass(String className) {
+ try {
+ return Class.forName(JAVA8_PACKAGE + className);
+ } catch (ClassNotFoundException ex) {
+ try {
+ return Class.forName(JAVA9_PACKAGE + className);
+ } catch (ClassNotFoundException ex2) {
+ return null;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/253887b2/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXPlatformInitializer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXPlatformInitializer.java b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXPlatformInitializer.java
index fa47935..21c8805 100644
--- a/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXPlatformInitializer.java
+++ b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXPlatformInitializer.java
@@ -40,12 +40,7 @@ import org.apache.cayenne.modeler.action.ConfigurePreferencesAction;
import org.apache.cayenne.modeler.action.ExitAction;
import org.apache.cayenne.modeler.init.platform.PlatformInitializer;
-import com.apple.eawt.AboutHandler;
-import com.apple.eawt.AppEvent;
import com.apple.eawt.Application;
-import com.apple.eawt.PreferencesHandler;
-import com.apple.eawt.QuitHandler;
-import com.apple.eawt.QuitResponse;
public class OSXPlatformInitializer implements PlatformInitializer {
@@ -58,27 +53,18 @@ public class OSXPlatformInitializer implements PlatformInitializer {
overrideUIDefaults();
// configure special Mac menu handlers
- Application app = Application.getApplication();
- app.setAboutHandler(new AboutHandler() {
- @Override
- public void handleAbout(AppEvent.AboutEvent aboutEvent) {
- actionManager.getAction(AboutAction.class).showAboutDialog();
- }
- });
-
- app.setPreferencesHandler(new PreferencesHandler() {
- @Override
- public void handlePreferences(AppEvent.PreferencesEvent preferencesEvent) {
- actionManager.getAction(ConfigurePreferencesAction.class).showPreferencesDialog();
- }
- });
-
- app.setQuitHandler(new QuitHandler() {
- @Override
- public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) {
- if(!actionManager.getAction(ExitAction.class).exit()) {
- quitResponse.cancelQuit();
- }
+ OSXApplicationWrapper wrapper = new OSXApplicationWrapper(Application.getApplication());
+ wrapper.setAboutHandler(()
+ -> actionManager.getAction(AboutAction.class).showAboutDialog());
+
+ wrapper.setPreferencesHandler(()
+ -> actionManager.getAction(ConfigurePreferencesAction.class).showPreferencesDialog());
+
+ wrapper.setQuitHandler(r -> {
+ if(!actionManager.getAction(ExitAction.class).exit()) {
+ r.cancelQuit();
+ } else {
+ r.performQuit();
}
});
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/253887b2/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXQuitResponseWrapper.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXQuitResponseWrapper.java b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXQuitResponseWrapper.java
new file mode 100644
index 0000000..f7e049b
--- /dev/null
+++ b/modeler/cayenne-modeler-mac-ext/src/main/java/org/apache/cayenne/modeler/osx/OSXQuitResponseWrapper.java
@@ -0,0 +1,73 @@
+/*****************************************************************
+ * 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.apache.cayenne.modeler.osx;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Small wrapper around QuitResponse class that can reside in different packages:
+ * com.apple.eawt.QuitResponse in JDK 8 and java.awt.desktop.QuitResponse in JDK 9.
+ * Luckily it has same signature so we can dynamically resolve it's methods.
+ *
+ * @since 4.1
+ */
+public class OSXQuitResponseWrapper {
+
+ private static final Logger logger = LoggerFactory.getLogger(OSXQuitResponseWrapper.class);
+
+ private Method performQuit;
+
+ private Method cancelQuit;
+
+ private final Object quitResponse;
+
+ public OSXQuitResponseWrapper(Object quitResponse) {
+ this.quitResponse = quitResponse;
+ try {
+ performQuit = quitResponse.getClass().getMethod("performQuit");
+ cancelQuit = quitResponse.getClass().getMethod("cancelQuit");
+ } catch (NoSuchMethodException ex) {
+ logger.warn("Unable to find methods for quit response", ex);
+ }
+ }
+
+ public void performQuit() {
+ safePerform(performQuit);
+ }
+
+ public void cancelQuit() {
+ safePerform(cancelQuit);
+ }
+
+ private void safePerform(Method method) {
+ if(method == null) {
+ return;
+ }
+ try {
+ method.invoke(quitResponse);
+ } catch (IllegalAccessException | InvocationTargetException ex) {
+ logger.warn("Unable to call " + method.getName(), ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/253887b2/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/swing/components/image/FilteredIconFactory.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/swing/components/image/FilteredIconFactory.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/swing/components/image/FilteredIconFactory.java
index 4e92238..cb92b1c 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/swing/components/image/FilteredIconFactory.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/swing/components/image/FilteredIconFactory.java
@@ -25,12 +25,11 @@ import java.awt.image.FilteredImageSource;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import javax.swing.Icon;
+import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.UIManager;
-import sun.swing.ImageIconUIResource;
-
/**
* @since 4.0
*/
@@ -64,7 +63,7 @@ public class FilteredIconFactory {
icon.paintIcon(DUMMY, img.getGraphics(), 0, 0);
ImageProducer producer = new FilteredImageSource(img.getSource(), filterType.filter);
Image resultImage = DUMMY.createImage(producer);
- return new ImageIconUIResource(resultImage);
+ return new ImageIcon(resultImage);
}
return null;
}