/******************************************************************************* * 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.ws.module; import java.io.IOException; import java.util.ArrayList; import java.util.Dictionary; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import com.buglabs.util.xml.XmlNode; public class PackageServlet extends HttpServlet { private static final long serialVersionUID = -2460404903765995674L; private final BundleContext context; private List<String> serviceList; public PackageServlet(BundleContext context) { this.context = context; } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Flush known services per request. serviceList = null; resp.setContentType("text/xml"); resp.getWriter().print(buildPackageModel().toString()); } private XmlNode buildPackageModel() { Bundle[] bundles = context.getBundles(); XmlNode root = new XmlNode("packages"); for (int i = 0; i < bundles.length; ++i) { Bundle b = bundles[i]; if (b != null) { String exportPackage = (String) b.getHeaders().get("Export-Package"); if (exportPackage != null) { splitHeaderValue(b, exportPackage, root); } } } return root; } private void splitHeaderValue(Bundle b, String value, XmlNode root) { String[] packages = value.split(","); for (int i = 0; i < packages.length; ++i) { if (!omitPackage(packages[i])) { XmlNode n = new XmlNode("package"); n.addAttribute("name", stripName(packages[i])); n.addAttribute("provider", getBestName(b)); addAttribs(n, packages[i]); root.addChild(n); } } } /** * This method looks for a corresponding OSGi service to match against a * package to determine if a given package should be usable. This is hack * due to the IModlet design. Essentially all packages for all known modules * are always exported. This method is a bandaid by manually omiting * packages that don't have corresponding services with the same root * namespace of com.buglabs.bug.module. * * @param packageName * @return */ private boolean omitPackage(String packageName) { if (!packageName.startsWith("com.buglabs.bug.module.")) { return false; } if (serviceList == null) { serviceList = populateServiceList(); } return !serviceList.contains(packageName); } private List<String> populateServiceList() { Bundle[] bundles = context.getBundles(); List<String> services = new ArrayList<String>(); for (int i = 0; i < bundles.length; ++i) { Bundle b = bundles[i]; if (b != null && b.getRegisteredServices() != null) { services.addAll(getServiceRoots(b.getRegisteredServices())); } } return services; } private List<String> getServiceRoots(ServiceReference[] registeredServices) { List<String> s = new ArrayList<String>(); for (int i = 0; i < registeredServices.length; ++i) { Object props = registeredServices[i].getProperty("objectClass"); String svcName = ((String[]) props)[0]; s.add(stripServiceName(svcName)); } return s; } private String stripServiceName(String svcName) { return svcName.substring(0, svcName.lastIndexOf('.')); } private void addAttribs(XmlNode n, String headerValue) { String[] elems = headerValue.split(";"); if (elems.length > 1) { elems = elems[1].split(","); for (int i = 0; i < elems.length; ++i) { addAttrib(n, elems[i]); } } } private void addAttrib(XmlNode n, String nameValue) { String[] elems = nameValue.split("="); if (elems.length == 2) { n.addChild(new XmlNode(stripNonAlphaNumeric(elems[0].trim()), elems[1].trim())); } } /** * Strip non alpha numeric characters from a String. * @param instr * @return */ private String stripNonAlphaNumeric(String instr) { return instr.replaceAll("[^A-Za-z0-9]", ""); } private String stripName(String headerValue) { return headerValue.split(";")[0]; } /** * Get the best available name for a bundle given it's metadata. * * @param bundle * @return */ private static String getBestName(Bundle bundle) { if (hasHeader(bundle, "Bundle-SymbolicName")) { return formatName(getHeader(bundle, "Bundle-SymbolicName")); } if (hasHeader(bundle, "Bundle-Name")) { return formatName(getHeader(bundle, "Bundle-Name")); } return bundle.getLocation(); } private static String formatName(String name) { String ss[] = name.split(";"); return ss[0]; } public static boolean hasHeader(Bundle bundle, String headerName) { Dictionary d = bundle.getHeaders(); if (d != null) { return d.get(headerName) != null; } return false; } public static String getHeader(Bundle bundle, String headerName) { Dictionary d = bundle.getHeaders(); if (d != null) { return (String) d.get(headerName); } return null; } }