/* * Copyright 2014 - Six Dimensions * * 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. */ package com.sixdimensions.wcm.cq.component.bindings.impl; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Properties; import org.apache.felix.scr.annotations.Property; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.apache.felix.webconsole.AbstractWebConsolePlugin; import org.apache.felix.webconsole.WebConsoleConstants; import org.apache.sling.commons.osgi.OsgiUtil; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sixdimensions.wcm.cq.component.bindings.ComponentBindingsProvider; import com.sixdimensions.wcm.cq.component.bindings.ComponentBindingsProviderFactory; @Component @Service(value = { Servlet.class }) @Properties({ @Property(name = WebConsoleConstants.PLUGIN_LABEL, value = ComponentBindingsProviderWebConsole.LABEL), @Property(name = WebConsoleConstants.PLUGIN_TITLE, value = ComponentBindingsProviderWebConsole.TITLE) }) public class ComponentBindingsProviderWebConsole extends AbstractWebConsolePlugin { /** * This console's label aka url */ public static final String LABEL = "componentbindingsprovider"; /** * The SLF4J Logger */ private static final Logger log = LoggerFactory .getLogger(ComponentBindingsProviderWebConsole.class); /** * The Serialization UID for this class */ private static final long serialVersionUID = -4099861429225408171L; /** * The title for this web console */ public static final String TITLE = "Component Bindings Provider"; /** * A reference to the ComponentBindingsProviderFactory */ @Reference private ComponentBindingsProviderFactory factory; /** * A reference to the ComponentBindingsValuesProvider service */ @Reference private ComponentBindingsValuesProvider componentBindingsValuesProvider; /* * (non-Javadoc) * * @see * org.apache.felix.webconsole.AbstractWebConsolePlugin#getCssReferences() */ @Override protected String[] getCssReferences() { return new String[] { "/res/ui/bundles.css" }; } /* * (non-Javadoc) * * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getLabel() */ @Override public String getLabel() { return LABEL; } /* * (non-Javadoc) * * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getTitle() */ @Override public String getTitle() { return TITLE; } /** * Loads the properties from the specified Service Reference into a map. * * @param reference * the reference from which to load the properties * @return the properties */ private Map<String, String> loadProperties(ServiceReference reference) { log.trace("loadProperties"); Map<String, String> properties = new HashMap<String, String>(); properties.put("id", OsgiUtil.toString( reference.getProperty(Constants.SERVICE_ID), "")); properties.put("class", OsgiUtil.toString( reference.getProperty(Constants.SERVICE_PID), "")); properties.put("description", OsgiUtil.toString( reference.getProperty(Constants.SERVICE_DESCRIPTION), "")); properties.put( "vendor", OsgiUtil.toString( reference.getProperty(Constants.SERVICE_VENDOR), "")); properties .put("resourceTypes", Arrays.toString(OsgiUtil.toStringArray( reference .getProperty(ComponentBindingsProvider.RESOURCE_TYPE_PROP), new String[0]))); properties.put("priority", OsgiUtil.toString( reference.getProperty(ComponentBindingsProvider.PRIORITY), "")); properties.put("bundle_id", String.valueOf(reference.getBundle().getBundleId())); properties.put("bundle_name", reference.getBundle().getSymbolicName()); log.debug("Loaded properties {}", properties); return properties; } /** * Loads the template with the specified name from the classloader and uses * it to templatize the properties using Apache Commons Lang's * StrSubstitutor and writes it to the response. * * @param res * the response to write to * @param template * the template file to load from the classpath * @param properties * the properties to templatize * @throws IOException */ private void renderBlock(HttpServletResponse res, String templateName, Map<String, String> properties) throws IOException { InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); String template = null; try { is = getClass().getClassLoader().getResourceAsStream(templateName); if (is != null) { IOUtils.copy(is, baos); template = baos.toString(); } else { throw new IOException("Unable to load template " + templateName); } } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(baos); } StrSubstitutor sub = new StrSubstitutor(properties); res.getWriter().write(sub.replace(template)); } /* * (non-Javadoc) * * @see * org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(javax * .servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void renderContent(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { log.trace("renderContent"); Map<String, String> pageProps = new HashMap<String, String>(); pageProps.put("message", ""); pageProps.put("searchAllChecked", ""); pageProps.put("resourceType", ""); ComponentBindingsProviderFactoryImpl factoryImpl = (ComponentBindingsProviderFactoryImpl) factory; if ("true".equals(req.getParameter("reloadCache"))) { factoryImpl.reloadCache(); pageProps.put("message", "Cache Reloaded"); } List<ServiceReference> bindingProviders = new ArrayList<ServiceReference>(); String resourceType = req.getParameter("resourceType"); if (!StringUtils.isEmpty(resourceType)) { log.debug("Searching for resource type: {}", resourceType); pageProps.put("resourceType", resourceType); bindingProviders = factoryImpl.getReferences(req .getParameter("resourceType")); } else if ("true".equals(req.getParameter("searchAll"))) { pageProps.put("searchAllChecked", "checked"); log.debug("Searching for all binding providers"); for (String rt : factoryImpl.getLoadedResourceTypes()) { log.debug("Searching for resource type: {}", rt); for (ServiceReference reference : factoryImpl.getReferences(rt)) { if (!bindingProviders.contains(reference)) { bindingProviders.add(reference); } } } } renderBlock(res, "header.html", pageProps); renderBlock(res, "search.html", pageProps); for (int i = 0; i < bindingProviders.size(); i++) { Map<String, String> properties = loadProperties(bindingProviders .get(i)); properties.put("state", (i + 1) % 2 == 0 ? "even" : "odd"); renderBlock(res, "result.html", properties); } res.getWriter().write("</tbody></table>"); res.getWriter() .write("<table><tr><th class=\"content ui-state-default\">Recent Exceptions</th></tr>"); for (final Object obj : componentBindingsValuesProvider .getRecentExceptions()) { renderBlock(res, "exception.html", new HashMap<String, String>() { private static final long serialVersionUID = 1L; { put("ex", obj.toString()); } }); } res.getWriter().write("</table>"); } }