/* * 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.karaf.webconsole.http; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.servlet.Servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.felix.webconsole.AbstractWebConsolePlugin; import org.apache.felix.webconsole.WebConsoleConstants; import org.json.JSONException; import org.json.JSONWriter; import org.ops4j.pax.web.service.spi.ServletEvent; import org.ops4j.pax.web.service.spi.WebEvent; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * WebConsole plugin to use with HTTP service. */ public class HttpPlugin extends AbstractWebConsolePlugin { private final Logger log = LoggerFactory.getLogger(HttpPlugin.class); public static final String NAME = "http"; public static final String LABEL = "Http"; private ClassLoader classLoader; private String featuresJs = "/http/res/ui/http-contexts.js"; private ServletEventHandler servletEventHandler; private WebEventHandler webEventHandler; private BundleContext bundleContext; @Override protected boolean isHtmlRequest(HttpServletRequest request) { return true; } public void start() { super.activate(bundleContext); this.classLoader = this.getClass().getClassLoader(); this.log.info(LABEL + " plugin activated"); } public void stop() { this.log.info(LABEL + " plugin deactivated"); super.deactivate(); } @Override public String getLabel() { return NAME; } @Override public String getTitle() { return LABEL; } @Override protected void renderContent(HttpServletRequest request, HttpServletResponse response) throws IOException { // get request info from request attribute final PrintWriter pw = response.getWriter(); String appRoot = (String) request.getAttribute(WebConsoleConstants.ATTR_APP_ROOT); final String featuresScriptTag = "<script src='" + appRoot + this.featuresJs + "' language='JavaScript'></script>"; pw.println(featuresScriptTag); pw.println("<script type='text/javascript'>"); pw.println("// <![CDATA["); pw.println("var imgRoot = '" + appRoot + "/res/imgs';"); pw.println("// ]]>"); pw.println("</script>"); pw.println("<div id='plugin_content'/>"); pw.println("<script type='text/javascript'>"); pw.println("// <![CDATA["); pw.print("renderFeatures( "); writeJSON(pw); pw.println(" )"); pw.println("// ]]>"); pw.println("</script>"); } protected URL getResource(String path) { path = path.substring(NAME.length() + 1); if (path == null || path.isEmpty()) { return null; } URL url = this.classLoader.getResource(path); if (url != null) { InputStream ins = null; try { ins = url.openStream(); if (ins == null) { this.log.error("failed to open " + url); url = null; } } catch (IOException e) { this.log.error(e.getMessage(), e); url = null; } finally { if (ins != null) { try { ins.close(); } catch (IOException e) { this.log.error(e.getMessage(), e); } } } } return url; } private void writeJSON(final PrintWriter pw) throws IOException { final List<ServletDetails> servlets = this.getServletDetails(); final List<WebDetail> web = this.getWebDetails(); final String statusLine = this.getStatusLine(servlets, web); final JSONWriter jw = new JSONWriter(pw); try { jw.object(); jw.key("status"); jw.value(statusLine); jw.key("contexts"); jw.array(); for (ServletDetails servlet : servlets) { jw.object(); jw.key("id"); jw.value(servlet.getId()); jw.key("servlet"); jw.value(servlet.getServlet()); jw.key("servletName"); jw.value(servlet.getServletName()); jw.key("state"); jw.value(servlet.getState()); jw.key("alias"); jw.value(servlet.getAlias()); jw.key("urls"); jw.array(); for (String url : servlet.getUrls()) { jw.value(url); } jw.endArray(); jw.endObject(); } jw.endArray(); jw.key("web"); jw.array(); for (WebDetail webDetail : web) { jw.object(); jw.key("id"); jw.value(webDetail.getBundleId()); jw.key("bundlestate"); jw.value(webDetail.getState()); jw.key("contextpath"); jw.value(webDetail.getContextPath()); jw.key("state"); jw.value(webDetail.getWebState()); jw.endObject(); } jw.endArray(); jw.endObject(); } catch (JSONException je) { throw new IOException(je.toString()); } } protected List<ServletDetails> getServletDetails() { Collection<ServletEvent> events = servletEventHandler.getServletEvents(); List<ServletDetails> result = new ArrayList<ServletDetails>(events.size()); for (ServletEvent event : events) { Servlet servlet = event.getServlet(); String servletClassName = " "; if (servlet != null) { servletClassName = servlet.getClass().getName(); servletClassName = servletClassName.substring(servletClassName.lastIndexOf(".") + 1, servletClassName.length()); } String servletName = event.getServletName() != null ? event.getServletName() : " "; if (servletName.contains(".")) { servletName = servletName.substring(servletName.lastIndexOf(".") + 1, servletName.length()); } String alias = event.getAlias() != null ? event.getAlias() : " "; String[] urls = (String[]) (event.getUrlParameter() != null ? event.getUrlParameter() : new String[]{""}); ServletDetails details = new ServletDetails(); details.setId(event.getBundle().getBundleId()); details.setAlias(alias); details.setServlet(servletClassName); details.setServletName(servletName); details.setState(getStateString(event.getType())); details.setUrls(urls); result.add(details); } return result; } protected List<WebDetail> getWebDetails() { Map<Long, WebEvent> bundleEvents = webEventHandler.getBundleEvents(); List<WebDetail> result = new ArrayList<WebDetail>(); for (WebEvent event : bundleEvents.values()) { WebDetail webDetail = new WebDetail(); webDetail.setBundleId(event.getBundle().getBundleId()); webDetail.setContextPath(event.getContextPath().trim().concat("/")); int state = bundleContext.getBundle(event.getBundle().getBundleId()).getState(); String stateStr; if (state == Bundle.ACTIVE) { stateStr = "Active"; } else if (state == Bundle.INSTALLED) { stateStr = "Installed"; } else if (state == Bundle.RESOLVED) { stateStr = "Resolved"; } else if (state == Bundle.STARTING) { stateStr = "Starting"; } else if (state == Bundle.STOPPING) { stateStr = "Stopping"; } else { stateStr = "Unknown"; } webDetail.setState(stateStr); webDetail.setWebState(getStateString(event.getType())); result.add(webDetail); } return result; } public String getStatusLine(List<ServletDetails> servlets, List<WebDetail> web) { Map<String, Integer> states = new HashMap<String, Integer>(); for (ServletDetails servlet : servlets) { Integer count = states.get(servlet.getState()); if (count == null) { states.put(servlet.getState(), 1); } else { states.put(servlet.getState(), 1 + count); } } StringBuilder stateSummary = new StringBuilder(); boolean first = true; for (Entry<String, Integer> state : states.entrySet()) { if (!first) { stateSummary.append(", "); } first = false; stateSummary.append(state.getValue()).append(" ").append(state.getKey()); } return "Http contexts: " + stateSummary.toString(); } public String getStateString(int type) { switch (type) { case WebEvent.DEPLOYING: return "Deploying"; case WebEvent.DEPLOYED: return "Deployed"; case WebEvent.UNDEPLOYING: return "Undeploying"; case WebEvent.UNDEPLOYED: return "Undeployed"; case WebEvent.FAILED: return "Failed"; case WebEvent.WAITING: return "Waiting"; default: return "Failed"; } } public void setServletEventHandler(ServletEventHandler eventHandler) { this.servletEventHandler = eventHandler; } public void setWebEventHandler(WebEventHandler eventHandler) { this.webEventHandler = eventHandler; } public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } }