blob: 4ccf1702e536902dc3690942b020f3d402c43c1d [file] [log] [blame]
/**
* 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.marmotta.splash.systray;
import static org.apache.marmotta.splash.common.MarmottaStartupHelper.getServerName;
import static org.apache.marmotta.splash.common.MarmottaStartupHelper.getServerPort;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.marmotta.splash.common.MarmottaContext;
import org.oxbow.swingbits.dialog.task.TaskDialogs;
/**
* Add file description here!
* <p/>
* Author: Sebastian Schaffert
*/
public class SystrayListener implements LifecycleListener {
protected static Log log = LogFactory.getLog(SystrayListener.class);
private static Set<MarmottaContext> contexts = new HashSet<MarmottaContext>();
private TrayIcon icon;
private Map<String, String> demoLinks;
private Map<String, String> adminLinks;
public static void addServletContext(MarmottaContext context) {
contexts.add(context);
}
public SystrayListener() {
super();
}
/**
* Register the systray menu when the application server has successfully started.
*
* @param event LifecycleEvent that has occurred
*/
@Override
public void lifecycleEvent(LifecycleEvent event) {
if(event.getType().equals(Lifecycle.AFTER_START_EVENT) && SystemTray.isSupported()) {
initContextLinks();
initSysTray();
}
}
/**
* Check all servlet contexts for the presence of the systray.admin and systray.demo attributes and add the link
* definitions to the menu link maps
*/
private void initContextLinks() {
demoLinks = new HashMap<String, String>();
adminLinks = new HashMap<String, String>();
for(MarmottaContext ctx : contexts) {
if(ctx.getServletContext() != null) {
Object ctxAdminAttr = ctx.getServletContext().getAttribute("systray.admin");
if(ctxAdminAttr != null && ctxAdminAttr instanceof Map) {
@SuppressWarnings("unchecked")
Map<String,String> ctxAdminLinks = (Map<String,String>) ctxAdminAttr;
adminLinks.putAll(ctxAdminLinks);
}
Object ctxDemoAttr = ctx.getServletContext().getAttribute("systray.demo");
if(ctxDemoAttr != null && ctxDemoAttr instanceof Map) {
@SuppressWarnings("unchecked")
Map<String,String> ctxDemoLinks = (Map<String,String>) ctxDemoAttr;
demoLinks.putAll(ctxDemoLinks);
}
} else {
log.error("could not register systray links because servlet context is not yet initialised");
}
}
}
private void initSysTray() {
if (SystemTray.isSupported()) {
// allow proper shutdown
System.setProperty("org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES","false");
SystemTray tray = SystemTray.getSystemTray();
// create menu
PopupMenu popup = new PopupMenu();
//MenuItem mainPage = createMenuItem("Start Page", "http://"+getServerName()+":"+getServerPort()+"/");
//popup.add(mainPage);
popup.addSeparator();
// launch browser action
MenuItem admin = createMenuItem("Administration","http://"+getServerName()+":"+getServerPort()+"/");
popup.add(admin);
// admin links
for(final Map.Entry<String,String> linkEntry : adminLinks.entrySet()) {
MenuItem entry = createMenuItem(linkEntry.getKey(),linkEntry.getValue());
popup.add(entry);
}
// shutdown action
MenuItem shutdown = new MenuItem("Shutdown");
try {
Class.forName("org.apache.catalina.mbeans.MBeanUtils");
ActionListener stopListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performServerShutdown();
}
};
shutdown.addActionListener(stopListener);
} catch (ClassNotFoundException e) {
shutdown.setEnabled(false);
}
popup.add(shutdown);
popup.addSeparator();
for(final Map.Entry<String,String> linkEntry : demoLinks.entrySet()) {
boolean containsEntry = false;
for(int i = 0; i < popup.getItemCount(); i++) {
MenuItem item = popup.getItem(i);
if(item.getLabel().equals(linkEntry.getKey())) {
containsEntry = true;
break;
}
}
if(!containsEntry) {
MenuItem entry = createMenuItem(linkEntry.getKey(),linkEntry.getValue());
popup.add(entry);
}
}
popup.addSeparator();
MenuItem about = new MenuItem("About");
about.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TaskDialogs.inform(null,
"About Apache Marmotta \n",
"(c)2013 The Apache Software Foundation \n" +
"Visit http://marmotta.apache.org for further details");
}
});
popup.add(about);
MenuItem issues = createMenuItem("Issues Reports", "https://issues.apache.org/jira/browse/MARMOTTA");
popup.add(issues);
MenuItem homepage = createMenuItem("Project Homepage", "http://marmotta.apache.org");
popup.add(homepage);
// load icon image
try {
Image image = ImageIO.read(SystrayListener.class.getResource("systray.png"));
icon = new TrayIcon(image,"Apache Marmotta",popup);
icon.setImageAutoSize(true);
tray.add(icon);
} catch (IOException e) {
log.error("SYSTRAY: could not load the logo for system tray",e);
} catch (AWTException e) {
log.error("SYSTRAY: tray icon could not be added");
}
}
}
private MenuItem createMenuItem(final String label, final String uriString) {
MenuItem entry = new MenuItem(label);
if (Desktop.isDesktopSupported()) {
final Desktop desktop = Desktop.getDesktop();
if(desktop.isSupported(Desktop.Action.BROWSE)) {
ActionListener adminBrowserListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
URI uri = new URI(uriString);
desktop.browse(uri);
} catch (IOException e1) {
log.error("SYSTRAY: could not access system browser, access to "+label+" disabled");
} catch (URISyntaxException e1) {
log.error("SYSTRAY: could not build URI to administration service, access to "+label+" disabled");
}
}
};
entry.addActionListener(adminBrowserListener);
} else {
entry.setEnabled(false);
}
} else {
entry.setEnabled(false);
}
return entry;
}
private void performServerShutdown() {
try{
MBeanServer server = (MBeanServer)Class.forName("org.apache.catalina.mbeans.MBeanUtils").getMethod("createServer").invoke(null);
ObjectName name;
if(isTomcat6()) {
// Tomcat 6.x
name = new ObjectName("Catalina:type=Service,serviceName=Catalina");
server.invoke(name, "stop", new Object[0], new String[0]);
log.warn("shutting down Apache Tomcat server on user request");
} else if(isTomcat7()) {
// Tomcat 7.x
name = new ObjectName("Catalina", "type", "Service");
server.invoke(name, "stop", new Object[0], new String[0]);
log.warn("shutting down Apache Tomcat server on user request");
}
} catch (Exception ex) {
log.error("shutting down other servers than Apache Tomcat is not supported",ex);
}
// ensure complete shutdown
System.exit(0);
}
/**
* Return true if Tomcat 6.x is detected; tests for presence of class org.apache.catalina.ServerFactory
* @return
*/
private boolean isTomcat6() {
try {
Class.forName("org.apache.catalina.ServerFactory");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
/**
* Return true if Tomcat 7.x is detected; tests for presence of class org.apache.catalina.CatalinaFactory
* @return
*/
private boolean isTomcat7() {
try {
Class.forName("org.apache.catalina.CatalinaFactory");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}