/*
* Copyright (c) 2012 Jeremy Goetsch
*
* Licensed 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 com.jgoetsch.eventtrader.processor;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.code.jgntp.Gntp;
import com.google.code.jgntp.GntpApplicationInfo;
import com.google.code.jgntp.GntpClient;
import com.google.code.jgntp.GntpNotificationInfo;
import com.jgoetsch.eventtrader.Msg;
/**
* Processor that triggers a Growl notification for an incoming message. By
* default <code>sourceName</code> and <code>message</code> fields of the
* incoming message are used for the title and message body respectively of the
* notification. This can be changed by overriding the <code>getTitle</code> and
* <code>getMessageBody</code> methods.
*
* @author jgoetsch
*
*/
public class GrowlNotification<M extends Msg> implements Processor<M> {
public static class GntpClientBean {
private String appName;
private String appIcon;
private Set<String> notificationTypes = new LinkedHashSet<String>();
private long timeout = 3000;
private String host = "localhost";
private int port = Gntp.WINDOWS_TCP_PORT;
private Map<String, GntpNotificationInfo> notificationInfos;
private GntpClient client;
private Logger log = LoggerFactory.getLogger(GntpClientBean.class);
@PostConstruct
public void initialize() {
GntpApplicationInfo info = Gntp.appInfo(appName).build();
notificationInfos = new HashMap<String, GntpNotificationInfo>();
for (String notificationType : notificationTypes) {
notificationInfos.put(notificationType, Gntp.notificationInfo(info, notificationType).build());
log.debug("Registering notification type: " + notificationType);
}
client = Gntp.client(info).forHost(host).onPort(port).build();
client.register();
}
public void sendNotification(String notificationType, String title, String msg, RenderedImage image) {
if (client == null)
initialize();
GntpNotificationInfo notificationInfo = notificationInfos.get(notificationType);
if (notificationInfo != null) {
try {
client.notify(Gntp.notification(notificationInfo, title).text(msg).icon(image).build(), timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.warn("GNTP notification timed out", e);
}
} else {
throw new IllegalArgumentException("Attempt to notify with unregistered notification type " + notificationType);
}
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppIcon() {
return appIcon;
}
public void setAppIcon(String appIcon) {
this.appIcon = appIcon;
}
public Set<String> getNotificationTypes() {
return notificationTypes;
}
public void setNotificationTypes(Set<String> notificationTypes) {
this.notificationTypes = notificationTypes;
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
private Logger log = LoggerFactory.getLogger(GrowlNotification.class);
private GntpClientBean client;
private String appName = "EventTrader";
private String notificationType;
private URL imageURL;
private boolean sticky;
private BufferedImage bufferedImage;
private static Map<String, GntpClientBean> autoRegisterNotifications = new HashMap<String, GntpClientBean>();
public GrowlNotification() {
}
/**
* @param alertType
* @param nextProcessor
* @throws IOException
*/
public GrowlNotification(String appName, String notificationType) throws IOException {
this.appName = appName;
this.notificationType = notificationType;
initialize();
}
@PostConstruct
public void initialize() throws IOException {
if (notificationType == null)
throw new IllegalStateException("Required property \"alertType\" not set");
if (client == null) {
if (appName != null) {
synchronized (autoRegisterNotifications) {
client = autoRegisterNotifications.get(appName);
if (client == null) {
client = new GntpClientBean();
client.setAppName(appName);
autoRegisterNotifications.put(appName, client);
}
client.getNotificationTypes().add(notificationType);
}
} else {
throw new IllegalStateException("Autoregistered notification must specify appName property");
}
}
if (imageURL != null) {
bufferedImage = ImageIO.read(imageURL);
}
}
/**
* Autoregisters all notifications without a client reference explicitly set.
* Calling this is not necessarily required as each client will be initialized
* anyway the first time one of its notifications is fired.
*/
public static void autoRegister() {
for (GntpClientBean client : autoRegisterNotifications.values()) {
client.initialize();
}
}
public void process(M msg, Map<Object,Object> context) {
if (client != null) {
try {
BufferedImage image = null;
if (msg.getImageUrl() != null) {
try {
image = ImageIO.read(new URL(msg.getImageUrl()));
} catch (Exception e) {
log.debug("Failed to load Msg imageUrl", e);
}
}
else {
image = bufferedImage;
}
client.sendNotification(getNotificationType(), getTitle(msg), getMessageBody(msg), image);
} catch (Exception e) {
log.warn("Growl notification failed", e);
}
}
else
log.error("initialize method on GrowlNotification not called, Growl notification cannot be sent");
}
protected String getTitle(Msg msg) {
return msg.getSourceName() != null ? msg.getSourceName() : notificationType;
}
protected String getMessageBody(Msg msg) {
return msg.getMessage() != null ? msg.getMessage() : "(no content)";
}
public void setSticky(boolean sticky) {
this.sticky = sticky;
}
public boolean isSticky() {
return sticky;
}
public void setNotificationType(String notificationType) {
this.notificationType = notificationType;
}
public String getNotificationType() {
return notificationType;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppName() {
return appName;
}
public void setImageURL(URL imageURL) {
this.imageURL = imageURL;
}
public URL getImageURL() {
return imageURL;
}
public void setClient(GntpClientBean client) {
this.client = client;
}
public GntpClientBean getClient() {
return client;
}
}