/******************************************************************************* * Copyright (c) 2008, 2009 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.base; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.Calendar; import java.util.Date; import java.util.Dictionary; import java.util.Hashtable; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; import com.buglabs.bug.base.bug20.pub.IBUG20BaseControl; import com.buglabs.bug.base.bug20.pub.ITimeProvider; import com.buglabs.bug.buttons.ButtonEvent; import com.buglabs.bug.buttons.IButtonEventListener; import com.buglabs.bug.buttons.IButtonEventProvider; import com.buglabs.bug.input.pub.InputEventProvider; import com.buglabs.support.SupportInfoTextFormatter; import com.buglabs.support.SupportInfoXMLFormatter; import com.buglabs.util.osgi.BUGBundleConstants; import com.buglabs.util.osgi.LogServiceUtil; import com.buglabs.util.osgi.ServiceTrackerUtil; import com.buglabs.util.osgi.ServiceTrackerUtil.ManagedRunnable; /** * This bundle offers base unit features to the runtime, such as date/time and * power information. * * @author kgilmer * */ public class Activator implements BundleActivator, ITimeProvider, IButtonEventListener, ManagedRunnable { private static final String BUG_BASE_VERSION_KEY = "bug.base.version"; private static final String INFO_SERVLET_PATH = "/support"; private static final String INFO_SERVLET_HTML_PATH = "/support.html"; private static final String DEVNODE_BUGNAV = "/dev/input/user_button"; private static final String DEVNODE_BUGPOWER = "/dev/input/power_button"; /** * Location where static web content will be registered with web server. */ private static final String ROOT_ALIAS = "/"; /** * Sleep delay for blinking LED. */ protected static final long LED_SLEEP_DELAY = 300; private static Activator ref; private ServiceRegistration timeReg; private static LogService logService; private BUGBaseControl bbc; private ServiceRegistration baseControlReg; private ServiceTracker httpTracker; private InputEventProvider userbep; private ServiceRegistration userBepReg; private BundleContext context; private InputEventProvider powerbep; private ServiceRegistration powerBepReg; private HttpService httpService; /* * (non-Javadoc) * * @see com.buglabs.bug.base.pub.ITimeProvider#getTime() */ public Date getTime() { return Calendar.getInstance().getTime(); } /** * Register all the OSGi services that this bundle provides. * * @param context * BundleContext */ private void registerServices(BundleContext context) { timeReg = context.registerService(ITimeProvider.class.getName(), this, null); userBepReg = context.registerService(IButtonEventProvider.class.getName(), userbep, getUserButtonProperties()); powerBepReg = context.registerService(IButtonEventProvider.class.getName(), powerbep, getPowerButtonProperties()); if (bbc != null) { baseControlReg = context.registerService(IBUG20BaseControl.class.getName(), bbc, getBaseControlServiceProperties()); } } /** * @return Dictionary of properties for power button. */ private Dictionary<String, String> getPowerButtonProperties() { Dictionary<String, String> d = new Hashtable<String, String>(); d.put(BUGBundleConstants.MODULE_PROVIDER_KEY, this.getClass().getName()); d.put("Button", "Power"); return d; } /** * @return Dictionary of properties for user button. */ private Dictionary<String, String> getUserButtonProperties() { Dictionary<String, String> d = new Hashtable<String, String>(); d.put(BUGBundleConstants.MODULE_PROVIDER_KEY, this.getClass().getName()); d.put("Button", "User"); return d; } /** * @return A dictionary with properties for base control */ private Dictionary<String, String> getBaseControlServiceProperties() { Dictionary<String, String> d = new Hashtable<String, String>(); d.put(BUG_BASE_VERSION_KEY, getBaseVersion()); return d; } /** * @return version of BUG base this code is running on. */ private String getBaseVersion() { return "2.0"; } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext * ) */ public void start(final BundleContext context) throws Exception { this.context = context; ref = this; logService = LogServiceUtil.getLogService(context); // Set base version property. System.setProperty(BUG_BASE_VERSION_KEY, getBaseVersion()); try { bbc = new BUGBaseControl(); // see http://redmine.buglabs.net/issues/show/1424 bbc.setLEDTrigger(IBUG20BaseControl.LED_POWER, IBUG20BaseControl.COLOR_BLUE, "none"); bbc.setLEDBrightness(IBUG20BaseControl.LED_POWER, 255); } catch (FileNotFoundException e) { logService.log(LogService.LOG_ERROR, "Unable to initialize LEDs. " + e.getMessage()); } userbep = new InputEventProvider(DEVNODE_BUGNAV, logService); userbep.start(); powerbep = new InputEventProvider(DEVNODE_BUGPOWER, logService); powerbep.start(); // listen for the power button to be hit, then toggle the LED sequence // for user feedback. see // http://redmine.buglabs.net/issues/show/1429#note-4 powerbep.addListener(this); registerServices(context); httpTracker = ServiceTrackerUtil.openServiceTracker(context, this, new String[] { HttpService.class.getName() }); signalStartup(); } /** * Signal to user that OSGi runtime is up and running. */ private void signalStartup() { (new Thread(new Runnable() { public void run() { try { bbc.setLEDColor(IBUG20BaseControl.LED_POWER, IBUG20BaseControl.COLOR_RED, true); Thread.sleep(LED_SLEEP_DELAY); bbc.setLEDColor(IBUG20BaseControl.LED_POWER, IBUG20BaseControl.COLOR_GREEN, true); Thread.sleep(LED_SLEEP_DELAY); bbc.setLEDColor(IBUG20BaseControl.LED_POWER, IBUG20BaseControl.COLOR_BLUE, true); } catch (Exception e) { // Ignore error } } })).start(); } private void signalShutdown() { Thread t = new Thread(new Runnable() { public void run() { try { logService.log(LogService.LOG_INFO, "Power Button engaged: base bundle signalling via LEDs shutdown sequence initiated"); bbc.setLEDTrigger(IBUG20BaseControl.LED_POWER, IBUG20BaseControl.COLOR_BLUE, "heartbeat"); } catch (Exception e) { } } }); t.start(); } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { httpTracker.close(); unregisterServices(context); } /** * @param context BundleContext */ private void unregisterServices(BundleContext context) { timeReg.unregister(); if (baseControlReg != null) { baseControlReg.unregister(); } userBepReg.unregister(); powerBepReg.unregister(); } /** * @return Activator instance */ public static Activator getDefault() { return ref; } /** * @return BundleContext */ public BundleContext getBundleContext() { return context; } @Override public void buttonEvent(ButtonEvent event) { if (event.getButton() == ButtonEvent.BUTTON_BUG20_POWER && event.getAction() == ButtonEvent.KEY_UP) { logService.log(LogService.LOG_DEBUG, "base bundle received Power Button event: " + event.getButton()); signalShutdown(); } } @Override public void run(Map<String, Object> services) { this.httpService = (HttpService) services.get(HttpService.class.getName()); try { logService.log(LogService.LOG_INFO, "Registering base servlets."); // register xml version httpService.registerServlet( INFO_SERVLET_PATH, new SupportServlet( new BUGSupportInfo(context), new SupportInfoXMLFormatter()), null, null); // register html version httpService.registerServlet( INFO_SERVLET_HTML_PATH, new SupportServlet( new BUGSupportInfo(context), new SupportInfoTextFormatter()), null, null); // register static root web content httpService.registerResources(ROOT_ALIAS, "static", new StaticResourceContext("static" + ROOT_ALIAS)); } catch (Exception e) { logService.log(LogService.LOG_ERROR, "An error occurred registering servlet or resource: " + e.getMessage()); } } @Override public void shutdown() { if (httpService != null) { httpService.unregister(INFO_SERVLET_PATH); httpService.unregister(INFO_SERVLET_HTML_PATH); httpService.unregister(ROOT_ALIAS); httpService = null; } } /** * HttpContext for static resource included in bundle. * TODO: Determine if this class is necessary or servlet can be registered w/ null HttpContext. */ private class StaticResourceContext implements HttpContext { private final String root; public StaticResourceContext(String root) { this.root = root; } /* (non-Javadoc) * @see org.osgi.service.http.HttpContext#getMimeType(java.lang.String) */ public String getMimeType(String name) { return null; } /* (non-Javadoc) * @see org.osgi.service.http.HttpContext#getResource(java.lang.String) */ public URL getResource(String name) { if (name.equals(root)) name = name + "index.html"; return context.getBundle().getResource(name); } /* (non-Javadoc) * @see org.osgi.service.http.HttpContext#handleSecurity(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException { return true; } } /** * @return Activator's instance of log service. */ public static LogService getLog() { return logService; } }