/* * Copyright 2011 Future Systems * * 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 org.krakenapps.webconsole.impl; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Locale; import java.util.Properties; import org.apache.felix.ipojo.annotations.Component; import org.apache.felix.ipojo.annotations.Invalidate; import org.apache.felix.ipojo.annotations.Requires; import org.apache.felix.ipojo.annotations.Validate; import org.krakenapps.httpd.BundleResourceServlet; import org.krakenapps.httpd.HttpContext; import org.krakenapps.httpd.HttpService; import org.krakenapps.webconsole.PackageApi; import org.krakenapps.webconsole.ProgramApi; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "webconsole-bundle-monitor") public class BundleMetadataMonitor implements BundleListener { private static String PROGRAM_METADATA = "/OSGI-INF/kraken-webconsole/program.properties"; private final Logger logger = LoggerFactory.getLogger(BundleMetadataMonitor.class.getName()); private BundleContext bc; @Requires private PackageApi packageApi; @Requires private ProgramApi programApi; @Requires private HttpService httpd; public BundleMetadataMonitor(BundleContext bc) { this.bc = bc; } @Validate public void start() { bc.addBundleListener(this); // inspect existing bundles for (Bundle bundle : bc.getBundles()) bundleChanged(new BundleEvent(BundleEvent.STARTED, bundle)); } @Invalidate public void stop() { if (bc != null) bc.removeBundleListener(this); } @Override public void bundleChanged(BundleEvent ev) { Bundle bundle = ev.getBundle(); int type = ev.getType(); try { if (ev.getType() == BundleEvent.STARTED) { loadProgramMetadata(bundle); } else if (type == BundleEvent.STOPPED) { unloadProgramMetadata(bundle); } } catch (IllegalStateException e) { if (e.getMessage() != null && e.getMessage().contains("bundle is uninstalled")) return; logger.error("kraken webconsole: cannot handle program metadata", e); } catch (Exception e) { logger.error("kraken webconsole: cannot handle program metadata", e); } } private void loadProgramMetadata(Bundle bundle) { Properties p = loadProperties(bundle); if (p != null) registerMetadata(bundle.getBundleId(), p, Locale.ENGLISH); } private void unloadProgramMetadata(Bundle bundle) { Properties p = loadProperties(bundle); if (p == null) return; unregisterStaticResource(bundle, p.getProperty("prefix")); logger.info("kraken webconsole: unloading program metadata for bundle " + bundle.getSymbolicName()); programApi.unregister(bundle.getBundleId()); } private Properties loadProperties(Bundle bundle) { URL url = bundle.getEntry(PROGRAM_METADATA); if (url == null) { logger.trace("kraken webconsole: program metadata not found for {}", bundle.getSymbolicName()); return null; } InputStream is = null; try { is = url.openStream(); Properties p = new Properties(); p.load(is); return p; } catch (Exception e) { logger.error("kraken webconsole: cannot load program metadata", e); return null; } finally { if (is != null) try { is.close(); } catch (IOException e) { } } } private void registerMetadata(long bundleId, Properties p, Locale locale) { String packageId = null; String packageLabel = null; for (Object k : p.keySet()) { String key = k.toString(); if (key.startsWith("package.")) { packageId = key.split("\\.")[1]; packageLabel = p.getProperty(key); break; } } registerStaticResource(bundleId, p); packageApi.register(packageId); packageApi.localize(packageId, locale, packageLabel); String prefix = p.getProperty("prefix"); if (prefix == null) prefix = ""; else if (!prefix.endsWith("/")) prefix += "/"; for (Object k : p.keySet()) { String key = k.toString(); if (key.startsWith("program.") && !key.endsWith(".label")) { String programId = key.substring("program.".length()); String path = prefix + (String) p.get(key); String label = (String) p.get(key + ".label"); programApi.register(bundleId, packageId, programId, path); programApi.localize(bundleId, packageId, programId, locale, label); } } } private void registerStaticResource(long bundleId, Properties p) { Bundle bundle = bc.getBundle(bundleId); String prefix = p.getProperty("prefix"); if (prefix != null) { URL url = bundle.getEntry("/WEB-INF"); if (url != null) { HttpContext ctx = httpd.ensureContext("webconsole"); ctx.addServlet("bundle" + bundle.getBundleId(), new BundleResourceServlet(bundle, "/WEB-INF"), prefix); logger.info("kraken webconsole: prefix [{}] is mapped to bundle {}/WEB-INF", prefix, bundleId); } else { logger.warn("kraken webconsole: WEB-INF directory not found in bundle {}", bundleId); } } else { logger.warn("kraken webconsole: prefix property not found in bundle {}", bundleId); } } private void unregisterStaticResource(Bundle bundle, String prefix) { } }