/******************************************************************************* * Copyright (c) 2008, 2011 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMware Inc. - initial contribution *******************************************************************************/ package org.eclipse.virgo.management.console; import java.util.Dictionary; import java.util.Hashtable; import org.eclipse.virgo.management.console.internal.AdminHttpContext; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpService; import org.osgi.service.url.URLStreamHandlerService; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.jolokia.osgi.servlet.JolokiaServlet; /** * * This class is ThreadSafe * */ public class Activator implements BundleActivator { private static final Logger log = LoggerFactory.getLogger(Activator.class); protected static final String APPLICATION_NAME = "Virgo Admin Console"; private static final String CONTENT_CONTEXT_PATH = "/content"; private static final String RESOURCES_CONTEXT_PATH = "/resources"; private static final String UPLOAD_CONTEXT_PATH = "/upload"; private static final String JOLOKIA_CONTEXT_PATH = "/jolokia"; protected static String contextPath = null; private ServiceTracker<HttpService, HttpService> httpServiceTracker; private ServiceTracker<URLStreamHandlerService, URLStreamHandlerService> urlEncoderServiceTracker; private transient HttpService registeredHttpService = null; private transient boolean isRegisteredWithHttpService = false; private final Object lock = new Object(); private BundleContext bundleContext; @Override public void start(BundleContext context) throws Exception { this.bundleContext = context; Activator.contextPath = this.bundleContext.getBundle().getHeaders().get("Web-ContextPath"); this.httpServiceTracker = new ServiceTracker<HttpService, HttpService>(context, HttpService.class, new HttpServiceTrackerCustomizer(context)); Filter createFilter = context.createFilter("(&(" + Constants.OBJECTCLASS + "=" + URLStreamHandlerService.class.getSimpleName() + ")(url.handler.protocol=webbundle))"); this.urlEncoderServiceTracker = new ServiceTracker<URLStreamHandlerService, URLStreamHandlerService>(context, createFilter, new UrlEncoderServiceTrackerCustomizer(context)); this.httpServiceTracker.open(); this.urlEncoderServiceTracker.open(); } @Override public void stop(BundleContext context) throws Exception { this.httpServiceTracker.close(); this.urlEncoderServiceTracker.close(); } private void registerWithHttpService(){ synchronized (this.lock) { if(this.registeredHttpService != null){ try { AdminHttpContext adminHttpContext = new AdminHttpContext(this.bundleContext.getBundle()); Dictionary<String, String> contentServletInitParams = new Hashtable<String, String>(); contentServletInitParams.put(ContentServlet.CONTENT_SERVLET_PREFIX, "/WEB-INF/layouts"); contentServletInitParams.put(ContentServlet.CONTENT_SERVLET_SUFFIX, ".html"); ContentServlet contentServlet = new ContentServlet(); this.registeredHttpService.registerServlet(Activator.contextPath, new IndexServlet(contentServlet), null, adminHttpContext); this.registeredHttpService.registerServlet(Activator.contextPath + CONTENT_CONTEXT_PATH, contentServlet, contentServletInitParams, adminHttpContext); this.registeredHttpService.registerServlet(Activator.contextPath + RESOURCES_CONTEXT_PATH, new ResourceServlet(), null, adminHttpContext); this.registeredHttpService.registerServlet(Activator.contextPath + UPLOAD_CONTEXT_PATH, new UploadServlet(this.bundleContext), null, adminHttpContext); this.registeredHttpService.registerServlet(Activator.contextPath + JOLOKIA_CONTEXT_PATH, new JolokiaServlet(this.bundleContext), null, null); this.isRegisteredWithHttpService = true; log.info("Admin console registered to HttpService: " + Activator.contextPath); } catch (Exception e) { log.error("Failed to register AdminConsole with HttpService", e); this.unRegisterWithHttpService(); } } } } private void unRegisterWithHttpService(){ synchronized (this.lock) { if(this.registeredHttpService != null){ this.doSafeUnregister(Activator.contextPath + Activator.CONTENT_CONTEXT_PATH); this.doSafeUnregister(Activator.contextPath + Activator.RESOURCES_CONTEXT_PATH); this.doSafeUnregister(Activator.contextPath + Activator.UPLOAD_CONTEXT_PATH); this.doSafeUnregister(Activator.contextPath + Activator.JOLOKIA_CONTEXT_PATH); this.doSafeUnregister(Activator.contextPath); } this.isRegisteredWithHttpService = false; log.info("Admin console unregistering from HttpService at " + Activator.contextPath); } } private void doSafeUnregister(String path){ try{ this.registeredHttpService.unregister(path); }catch(IllegalArgumentException e){ log.warn("Failed to unregister '" + path + "' from HttpService"); } } /** * Tracker event handler for HttpService */ private class HttpServiceTrackerCustomizer implements ServiceTrackerCustomizer<HttpService, HttpService> { private final BundleContext context; public HttpServiceTrackerCustomizer(BundleContext context) { this.context = context; } @Override public HttpService addingService(ServiceReference<HttpService> reference) { HttpService service = this.context.getService(reference); if(urlEncoderServiceTracker.isEmpty() && !isRegisteredWithHttpService){ registeredHttpService = service; registerWithHttpService(); } return service; } @Override public void modifiedService(ServiceReference<HttpService> reference, HttpService service) { // no-op } @Override public void removedService(ServiceReference<HttpService> reference, HttpService service) { if(registeredHttpService != null && service.equals(registeredHttpService)){ unRegisterWithHttpService(); registeredHttpService = null; } } } /** * Tracker event handler for URLStreamHandlerService */ private class UrlEncoderServiceTrackerCustomizer implements ServiceTrackerCustomizer<URLStreamHandlerService, URLStreamHandlerService>{ private final BundleContext context; public UrlEncoderServiceTrackerCustomizer(BundleContext context) { this.context = context; } @Override public URLStreamHandlerService addingService(ServiceReference<URLStreamHandlerService> reference) { if(registeredHttpService != null){ unRegisterWithHttpService(); } return this.context.getService(reference); } @Override public void modifiedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service) { // no-op } @Override public void removedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service) { if(urlEncoderServiceTracker.isEmpty() && !isRegisteredWithHttpService && registeredHttpService != null){ registerWithHttpService(); } } } }