/*******************************************************************************
* Copyright (c) 2011 Bug Labs, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of Bug Labs, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
package com.buglabs.bug.appui;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Hashtable;
import java.util.Map;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import com.buglabs.bug.module.lcd.pub.IModuleDisplay;
import com.buglabs.util.osgi.LogServiceUtil;
import com.buglabs.util.osgi.BundleUtils;
import com.buglabs.util.osgi.FilterUtil;
import com.buglabs.util.ui.IDesktopApp;
/**
* Activator for AppUI. Listens to bundle and IDesktopApp service events.
* @author kgilmer
*
*/
public class Activator implements BundleActivator, ServiceTrackerCustomizer, BundleListener, ServiceListener {
private ServiceTracker st;
private static BundleContext context;
private AppWindow appWindow;
private static LogService log;
private Map<String, Bundle> appBundles;
private Map<String, IDesktopApp> launchListeners;
private Frame appFrame;
protected static final Toolkit AWT_TOOLKIT = Toolkit.getDefaultToolkit();
protected static Image BUNDLE_STOPPED;
protected static Image APP_ACTIVE;
protected static Image APP_INVERTED;
protected static Image BUNDLE_STARTED;
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
Activator.context = context;
APP_ACTIVE = AWT_TOOLKIT.createImage(context.getBundle().getResource("app_started.png"));
BUNDLE_STOPPED = AWT_TOOLKIT.createImage(context.getBundle().getResource("bundle_stopped.png"));
BUNDLE_STARTED = AWT_TOOLKIT.createImage(context.getBundle().getResource("bundle_started.png"));
APP_INVERTED = AWT_TOOLKIT.createImage(context.getBundle().getResource("app_invert.png"));
appBundles = loadModel(context.getBundles());
launchListeners = loadLaunchListeners();
st = new ServiceTracker(context, IModuleDisplay.class.getName(), this);
st.open();
context.addBundleListener(this);
context.addServiceListener(this, FilterUtil.generateServiceFilter(IDesktopApp.class.getName()));
}
/**
* @return A log service
*/
public static LogService getLogService() {
if (log == null) {
log = LogServiceUtil.getLogService(context);
}
return log;
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
st.close();
if (appFrame != null) {
appFrame.dispose();
}
context.removeBundleListener(this);
context.removeServiceListener(this);
}
/**
* @return A map containing bundle names and launch listeners.
* @throws InvalidSyntaxException Thrown if errors in filter expression.
*/
private Map<String, IDesktopApp> loadLaunchListeners() throws InvalidSyntaxException {
ServiceReference[] srs = context.getServiceReferences(IDesktopApp.class.getName(), null);
Map<String, IDesktopApp> model = new Hashtable<String, IDesktopApp>();
if (srs != null) {
for (int i = 0; i < srs.length; ++i) {
Bundle b = srs[i].getBundle();
String name = BundleUtils.getBestName(b);
if (!model.containsKey(name)) {
model.put(name, (IDesktopApp) context.getService(srs[i]));
}
}
}
return model;
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
public Object addingService(ServiceReference reference) {
IModuleDisplay display = (IModuleDisplay) context.getService(reference);
appFrame = display.getFrame();
addWindowListeners(appFrame);
appWindow = new AppWindow(appFrame);
appWindow.setLaunchClients(launchListeners);
appWindow.setVisible(true);
appWindow.setBundles(appBundles);
appWindow.refresh();
return display;
}
/**
* @param bundles Array of Bundles
* @return a map of existing app bundles.
*/
private Map<String, Bundle> loadModel(Bundle[] bundles) {
Map<String, Bundle> model = new Hashtable<String, Bundle>();
for (int i = 0; i < bundles.length; ++i) {
Bundle b = bundles[i];
if (isApp(b)) {
String name = BundleUtils.getBestName(b);
model.put(name, b);
}
}
return model;
}
/**
* @param b Bundle to check
* @return true if a given bundle is a BUG app
*/
private boolean isApp(Bundle b) {
Object o = b.getHeaders().get("Bug-Bundle-Type");
if (o != null && ((String) o).equals("Application")) {
return true;
}
return false;
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void modifiedService(ServiceReference reference, Object service) {
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void removedService(ServiceReference reference, Object service) {
if (appWindow != null) {
appWindow.dispose();
}
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
*/
public void bundleChanged(BundleEvent event) {
if (!isApp(event.getBundle())) {
return;
}
String name = BundleUtils.getBestName(event.getBundle());
boolean refresh = false;
switch (event.getType()) {
case BundleEvent.INSTALLED:
case BundleEvent.UPDATED:
case BundleEvent.STARTED:
case BundleEvent.STOPPED:
appBundles.put(name, event.getBundle());
refresh = true;
break;
case BundleEvent.UNINSTALLED:
if (appBundles.containsKey(name)) {
appBundles.remove(name);
refresh = true;
}
break;
}
if (refresh && appWindow != null) {
appWindow.refresh();
}
}
/* (non-Javadoc)
* @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
*/
public void serviceChanged(ServiceEvent event) {
String name = BundleUtils.getBestName(event.getServiceReference().getBundle());
switch (event.getType()) {
case ServiceEvent.REGISTERED:
if (!launchListeners.containsKey(name)) {
launchListeners.put(name, (IDesktopApp) context.getService(event.getServiceReference()));
}
break;
case ServiceEvent.UNREGISTERING:
if (launchListeners.containsKey(name)) {
launchListeners.remove(name);
}
break;
default:
}
}
/**
* Add hooks to shutdown application from UI.
*
* @param f2 AWT Window Frame
*/
private void addWindowListeners(final Frame f2) {
f2.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent arg0) {
}
public void windowClosed(WindowEvent arg0) {
}
public void windowClosing(WindowEvent arg0) {
appFrame.dispose();
appFrame = null;
}
public void windowDeactivated(WindowEvent arg0) {
}
public void windowDeiconified(WindowEvent arg0) {
}
public void windowIconified(WindowEvent arg0) {
}
public void windowOpened(WindowEvent arg0) {
}
});
}
}