Java tutorial
/* * * The MIT License (MIT) * * Copyright (c) 2014 Ed George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Created by Ed George on 26 Dec 2014 * */ package uk.co.edgeorgedev.notifj.notification.growl; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import org.apache.commons.lang3.SystemUtils; import uk.co.edgeorgedev.notifj.notification.Notification; import uk.co.edgeorgedev.notifj.notification.exception.NotificationException; import uk.co.edgeorgedev.notifj.notification.exception.NotificationOperatingSystemException; /** * This class consists of methods to create <a href="http://growl.info">Growl Notification</a> messages on the OS X platform * * <p>The <tt>open()</tt> and <tt>show()</tt> methods of this class throw a <tt>NotificationException</tt> * if the creation of a Growl Notification fails. * * <p>It should also be noted that <tt>open()</tt> will throw a <tt>NotificationOperatingSystemException</tt> * should it be called on a non OS X operating system. * * @author Ed George * @see GrowlNotification * @see Notification * @since 1.0 */ public class OSXGrowlNotification extends GrowlNotification { private static final String GROWL_APPLICATION = "com.Growl.GrowlHelperApp"; private static final String SYSTEM_EVENTS = "System Events"; private static final String DEFAULT_ICON_NAME = "Script Editor"; private ScriptEngine mScriptEngine; /** * Constructs an unregistered named Growl notification application * * <p>The registration process occurs within the {@link #open()} method. * * @since 1.2 * */ public OSXGrowlNotification() { super(); } /** * Creates new ApppleScript Engine which is used to create notifications * @throws NotificationOperatingSystemException if the system operating system is <i>not</i> Mac OSX * @since 1.0 */ @Override public void open() throws NotificationException { if (!SystemUtils.IS_OS_MAC_OSX) throw new NotificationOperatingSystemException("Operating System is not Mac OSX"); ScriptEngineManager engineManager = new ScriptEngineManager(); mScriptEngine = engineManager.getEngineByName("AppleScript"); } /** * Displays a Growl Notification with a given title and message * * <p>Should the application, specified by the {@code application_name}, not be registered * within the Growl Notification settings, it is first registered before a message is displayed. * * <p>As of Growl Version 2.1.3, this method correctly generates and displays notifications. * * @param title the title of the notification. * @param message the message body of the notification. * @throws NotificationException if no Script Engine is available or no Growl process * is running. * @since 1.0 */ @Override public void show(String title, String message) throws NotificationException { if (mScriptEngine == null) { throw new NotificationException("No AppleScriptEngine available - Have you called open()?"); } if (!isGrowlEnabled()) { throw new NotificationException("No Growl process located"); } runScript(messageScript(title, message).build(), 0L); } /** * Cleans-up object by resetting the script engine and application name * @since 1.0 */ @Override public void close() throws NotificationException { mScriptEngine = null; super.application_name = null; } /** * Determines whether Growl Notifications are enabled on the machine * * @return <tt>true</tt> if Growl Notifications are enabled * @since 1.0 */ public boolean isGrowlEnabled() { String script = getGrowlEnabledScript().build(); long count = runScript(script, 0L); return count > 0; } /* * Generate AppleScript to test if Growl Notifications are enabled */ private ScriptBuilder getGrowlEnabledScript() { return script().add("tell application ").quote(SYSTEM_EVENTS) .newLine("return count of (every process whose bundle identifier is ").quote(GROWL_APPLICATION) .add(") > 0").newLine("end tell"); } /* * Generate AppleScript to generate Growl Notification */ private ScriptBuilder messageScript(String title, String message) { ScriptBuilder script = script().add("tell application ").quote(SYSTEM_EVENTS) .newLine("set isRunning to (count of (every process whose bundle identifier is ") .quote(GROWL_APPLICATION).add(")) > 0").newLine("end tell").newLine("if isRunning then") .newLine("tell application id ").quote(GROWL_APPLICATION) .newLine("set the allNotificationsList to ").cont().newLine().array(title) .newLine("set the enabledNotificationsList to ").cont().newLine().array(title) .newLine("register as application ").cont().newLine().quote(super.application_name) .add(" all notifications allNotificationsList ").cont() .newLine("default notifications enabledNotificationsList ").cont().newLine("icon of application ") .quote(DEFAULT_ICON_NAME).newLine("notify with name ").cont().newLine().quote(title).add(" title ") .cont().newLine().quote(title).add(" description ").cont().newLine().quote(message) .add(" application name ").quote(super.application_name); if (callback_url != null) { script.add(" callback URL ").cont().newLine().quote(super.callback_url.toString()); } if (super.isSticky()) { script.add(" with sticky"); } script.newLine("end tell").newLine("end if"); return script; } /* * Return new ScriptBuilder */ private ScriptBuilder script() { return new ScriptBuilder(); } /* * Run AppleScript and specify a default value on failure */ @SuppressWarnings("unchecked") private <T> T runScript(String script, T defaultValue) { try { return (T) runScript(script); } catch (Exception e) { return defaultValue; } } /* * Run AppleScript using the AppleScript Script Engine */ private Object runScript(String script) throws Exception { try { return mScriptEngine.eval(script, mScriptEngine.getContext()); } catch (Exception e) { throw new Exception("Could not execute script", e); } } /* * Helper class to Build valid AppleScript */ private class ScriptBuilder { StringBuilder builder = new StringBuilder(); /* * Append string to current line */ public ScriptBuilder add(String text) { this.builder.append(text); return this; } /* * Append quoted text to current line */ public ScriptBuilder quote(String text) { this.builder.append("\""); this.builder.append(text); this.builder.append("\""); return this; } /* * Append continue symbol to current line */ public ScriptBuilder cont() { this.builder.append(""); return this; } /* * Append new line */ public ScriptBuilder newLine() { this.builder.append("\n"); return this; } /* * Append new line with text */ public ScriptBuilder newLine(String text) { this.builder.append("\n"); this.builder.append(text); return this; } /* * Append array to current line */ public ScriptBuilder array(String... values) { this.builder.append("{"); for (int i = 0; i < values.length; i++) { if (i > 0) { this.builder.append(", "); } this.builder.append("\""); this.builder.append(values[i]); this.builder.append("\""); } this.builder.append("}"); return this; } /* * Return built AppleScript */ public String build() { return this.builder.toString(); } } }