/** * Copyright 2011 multibit.org * * Licensed under the MIT license (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://opensource.org/licenses/mit-license.php * * 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 net.bither.platform.builder.mac; import net.bither.platform.GenericApplication; import net.bither.platform.handler.GenericAboutHandler; import net.bither.platform.handler.GenericOpenURIHandler; import net.bither.platform.handler.GenericPreferencesHandler; import net.bither.platform.handler.GenericQuitHandler; import net.bither.platform.listener.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; /** * <p>GenericApplication to provide the following to application:</p> * <ul> * <li>Provision of Apple Mac specific implementations of common methods</li> * </ul> * <p>TODO Fill in more support code as and when required using the EAWT Javadocs as a reference for non-deprecated methods</p> * * @see <a href="http://developer.apple.com/library/mac/documentation/Java/Reference/JavaSE6_AppleExtensionsRef/api/index.html?com/apple/eawt/Application.html">The Apple EAWT Javadocs</a> * @since 0.3.0 *   */ public class MacApplication implements GenericApplication { private static final Logger log = LoggerFactory.getLogger(MacApplication.class); /** * The native EAWT Application instance providing OS events */ private Object nativeApplication; /** * Handles the OpenURI use case */ private Class nativeOpenURIHandlerClass; /** * Handles the Preferences use case */ private Class nativePreferencesHandlerClass; /** * Handles the About use case */ private Class nativeAboutHandlerClass; public void addOpenURIHandler(GenericOpenURIHandler openURIHandler) { log.debug("Adding GenericOpenURIHandler"); // Ensure the implementing class is public // This avoids anonymous interface issues if (!Modifier.isPublic(openURIHandler.getClass().getModifiers())) { throw new IllegalArgumentException("GenericOpenURIHandler must be a public class"); } // Load up an instance of the native OpenURIHandler // Provide an invocation handler to link the native openURI(AppEvent.OpenURIEvent event) // back to the generic handler Object nativeOpenURIHandler = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{nativeOpenURIHandlerClass}, new OpenURIHandlerInvocationHandler(openURIHandler, GenericOpenURIEvent.class)); // Reflective call as application.setOpenURIHandler(nativeOpenURIHandler) // nativeOpenURIHandler is a proxy that actually uses the generic handler callNativeMethod(nativeApplication, "setOpenURIHandler", new Class[]{nativeOpenURIHandlerClass}, new Object[]{nativeOpenURIHandler}); log.debug("GenericOpenURIHandler configured"); } /** * Handles the Quit use case */ private Class nativeQuitHandlerClass; public void addPreferencesHandler(GenericPreferencesHandler preferencesHandler) { log.debug("Adding GenericPreferencesHandler"); // Ensure the implementing class is public // This avoids anonymous interface issues if (!Modifier.isPublic(preferencesHandler.getClass().getModifiers())) { throw new IllegalArgumentException("GenericPreferencesHandler must be a public class"); } // Load up an instance of the native PreferencesHandler // Provide an invocation handler to link the native preferences(AppEvent.PreferencesEvent event) // back to the generic handler Object nativePreferencesHandler = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{nativePreferencesHandlerClass}, new PreferencesHandlerInvocationHandler(preferencesHandler, GenericPreferencesEvent.class)); // Reflective call as application.setPreferencesHandler(nativePreferencesHandler) // nativePreferencesHandler is a proxy that actually uses the generic handler callNativeMethod(nativeApplication, "setPreferencesHandler", new Class[]{nativePreferencesHandlerClass}, new Object[]{nativePreferencesHandler}); log.debug("GenericPreferencesHandler configured"); } public void addAboutHandler(GenericAboutHandler aboutHandler) { log.debug("Adding GenericAboutHandler"); // Ensure the implementing class is public // This avoids anonymous interface issues if (!Modifier.isPublic(aboutHandler.getClass().getModifiers())) { throw new IllegalArgumentException("GenericAboutHandler must be a public class"); } // Load up an instance of the native AboutHandler // Provide an invocation handler to link the native about(AppEvent.AboutEvent event) // back to the generic handler Object nativeAboutHandler = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{nativeAboutHandlerClass}, new AboutHandlerInvocationHandler(aboutHandler, GenericAboutEvent.class)); // Reflective call as application.setAboutHandler(nativeAboutHandler) // nativeAboutHandler is a proxy that actually uses the generic handler callNativeMethod(nativeApplication, "setAboutHandler", new Class[]{nativeAboutHandlerClass}, new Object[]{nativeAboutHandler}); log.debug("GenericAboutHandler configured"); } public void addQuitHandler(GenericQuitHandler quitHandler) { log.debug("Adding GenericQuitHandler"); // Ensure the implementing class is public // This avoids anonymous interface issues if (!Modifier.isPublic(quitHandler.getClass().getModifiers())) { throw new IllegalArgumentException("GenericQuitHandler must be a public class"); } // Load up an instance of the native QuitHandler // Provide an invocation handler to link the native about(AppEvent.AboutEvent event) // back to the generic handler Object nativeQuitHandler = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{nativeQuitHandlerClass}, new QuitHandlerInvocationHandler(quitHandler, GenericQuitEvent.class, GenericQuitResponse.class)); // Reflective call as application.setQuitHandler(nativeQuitHandler) // nativeQuitHandler is a proxy that actually uses the generic handler callNativeMethod(nativeApplication, "setQuitHandler", new Class[]{nativeQuitHandlerClass}, new Object[]{nativeQuitHandler}); log.debug("GenericAboutHandler configured"); } /** * Calls a non-zero argument method of the given (usually native) object * * @param object The object * @param methodName The method name * @param classes The classes of the arguments in the order they appear in the method signature * @param arguments The values of the arguments in the order they appear in the method signature * @return The result of the call */ private Object callNativeMethod(Object object, String methodName, Class[] classes, Object[] arguments) { log.debug("Calling methodName {}", methodName); try { // Build a suitable Class[] for the method signature based on the arguments if (classes == null) { classes = new Class[arguments.length]; for (int i = 0; i < classes.length; i++) { classes[i] = arguments[i].getClass(); } } Method method = object.getClass().getMethod(methodName, classes); return method.invoke(object, arguments); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } @Override public boolean isMac() { return true; } @Override public boolean isLinux() { return false; } @Override public boolean isWindows() { return false; } public void setApplication(Object application) { this.nativeApplication = application; } public void setOpenURIHandlerClass(Class openURIHandlerClass) { this.nativeOpenURIHandlerClass = openURIHandlerClass; } public void setPreferencesHandlerClass(Class preferencesHandlerClass) { this.nativePreferencesHandlerClass = preferencesHandlerClass; } public void setAboutHandlerClass(Class aboutHandlerClass) { this.nativeAboutHandlerClass = aboutHandlerClass; } public void setQuitHandlerClass(Class quitHandlerClass) { this.nativeQuitHandlerClass = quitHandlerClass; } }