package org.jolokia.osgi.servlet;
/*
* Copyright 2009-2013 Roland Huss
*
* 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.
*/
import javax.servlet.*;
import org.jolokia.http.AgentServlet;
import org.jolokia.restrictor.Restrictor;
import org.jolokia.util.LogHandler;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
/**
* Extended here for the sole purpose of exporting
* this servlet to the outside in order that
* it can be instantiated from another bundle.
*
* This service also tracks the availability of a log
* service in order redirect the servlet logging to
* the log service (if available). Otherwise it uses
* the servlet's logging facility as fallback.
*
* @author roland
* @since 10.02.11
*/
public class JolokiaServlet extends AgentServlet {
private static final long serialVersionUID = 23L;
// Context given in the constructor
private BundleContext bundleContextGiven;
// Tracker to be used for the LogService
private ServiceTracker logTracker;
// Thread-Locals which will be used for holding the bundle context and
// the https service during initialization
private static final ThreadLocal<BundleContext> BUNDLE_CONTEXT_THREAD_LOCAL = new ThreadLocal<BundleContext>();
/**
* Constructor with an empty context
*/
public JolokiaServlet() {
this(null);
}
/**
* Constructor which associates this servlet with a bundle context
*
* @param pContext bundle context to associate with
*/
public JolokiaServlet(BundleContext pContext) {
this (pContext,null);
}
/**
* Constructor with a bundle context and a given restrictor
*
* @param pContext associated bundle context
* @param pRestrictor restrictor to use or <code>null</code> if the default
* lookup mechanism should be used
*/
public JolokiaServlet(BundleContext pContext,Restrictor pRestrictor) {
super(pRestrictor);
bundleContextGiven = pContext;
}
/** {@inheritDoc} */
@Override
public void init(ServletConfig pServletConfig) throws ServletException {
// We are making the bundle context available here as a thread local
// so that the server detector has access to the bundle in order to detect
// the Osgi-Environment
BUNDLE_CONTEXT_THREAD_LOCAL.set(getBundleContext(pServletConfig));
try {
super.init(pServletConfig);
} finally {
BUNDLE_CONTEXT_THREAD_LOCAL.remove();
}
}
/**
* Create a log handler which tracks a {@link LogService} and, if available, use the log service
* for logging, in the other time uses the servlet's default logging facility
*
* @param pServletConfig servlet configuration
* @param pDebug
*/
@Override
protected LogHandler createLogHandler(ServletConfig pServletConfig, boolean pDebug) {
// If there is a bundle context available, set up a tracker for tracking the logging
// service
BundleContext ctx = getBundleContext(pServletConfig);
if (ctx != null) {
// Track logging service
logTracker = new ServiceTracker(ctx, LogService.class.getName(), null);
logTracker.open();
return new ActivatorLogHandler(logTracker,pDebug);
} else {
// Use default log handler
return super.createLogHandler(pServletConfig, pDebug);
}
}
/** {@inheritDoc} */
@Override
public void destroy() {
if (logTracker != null) {
logTracker.close();
logTracker = null;
}
bundleContextGiven = null;
super.destroy();
}
/**
* Get the current bundle context. This static method can be used during startup
* of the agent servlet. At other times, this method will return null
*
* @return the current bundle context during adding of a HttpService, null at other
* times
*/
public static BundleContext getCurrentBundleContext() {
return BUNDLE_CONTEXT_THREAD_LOCAL.get();
}
private BundleContext getBundleContext(ServletConfig pServletConfig) {
// If no bundle context was provided, we are looking up the servlet context
// for the bundlect context, which will be available usually in servlet extender
if (bundleContextGiven == null) {
// try to lookup bundle context from the servlet context
ServletContext servletContext = pServletConfig.getServletContext();
return (BundleContext) servletContext.getAttribute("osgi-bundlecontext");
} else {
return bundleContextGiven;
}
}
// LogHandler which logs to a LogService if available, otherwise
// it uses simply the servlets log facility
private final class ActivatorLogHandler implements LogHandler {
private final boolean doDebug;
private final ServiceTracker logTracker;
private ActivatorLogHandler(ServiceTracker pLogTracker, boolean pDebug) {
logTracker = pLogTracker;
doDebug = pDebug;
}
/** {@inheritDoc} */
public void debug(String message) {
doLog(LogService.LOG_DEBUG, message);
}
/** {@inheritDoc} */
public void info(String message) {
doLog(LogService.LOG_INFO, message);
}
private void doLog(int level, String message) {
LogService logService = (LogService) logTracker.getService();
if (logService != null) {
logService.log(level,message);
} else {
if (level != LogService.LOG_DEBUG || doDebug) {
log(message);
}
}
}
/** {@inheritDoc} */
public void error(String message, Throwable t) {
LogService logService = (LogService) logTracker.getService();
if (logService != null) {
logService.log(LogService.LOG_ERROR,message,t);
} else {
log(message,t);
}
}
}
}