blob: b5e0dac115fd78f654c8e68988cd0eabf2f0297b [file] [log] [blame]
/*
* 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.felix.status.impl.webconsole;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.felix.status.PrinterMode;
import org.apache.felix.status.StatusPrinter;
import org.apache.felix.status.ZipAttachmentProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
*/
public class WebConsoleAdapter implements ServiceTrackerCustomizer {
private final BundleContext bundleContext;
private final ServiceTracker cfgPrinterTracker;
private final Map<ServiceReference, ServiceRegistration> registrations = new HashMap<ServiceReference, ServiceRegistration>();
private final ResourceBundleManager rbManager;
public WebConsoleAdapter(final BundleContext btx) throws InvalidSyntaxException {
this.bundleContext = btx;
this.rbManager = new ResourceBundleManager(btx);
this.cfgPrinterTracker = new ServiceTracker( this.bundleContext,
this.bundleContext.createFilter("(|(" + Constants.OBJECTCLASS + "=" + ConsoleConstants.INTERFACE_CONFIGURATION_PRINTER + ")" +
"(&(" + ConsoleConstants.PLUGIN_LABEL + "=*)(&("
+ ConsoleConstants.PLUGIN_TITLE + "=*)("
+ ConsoleConstants.CONFIG_PRINTER_MODES + "=*))))"),
this );
this.cfgPrinterTracker.open();
}
/**
* Dispose this service
*/
public void dispose() {
this.cfgPrinterTracker.close();
synchronized ( this.registrations ) {
for(final ServiceRegistration reg : this.registrations.values()) {
reg.unregister();
}
this.registrations.clear();
}
this.rbManager.dispose();
}
public void add(final ServiceReference reference, final Object service) {
final ConfigurationPrinterAdapter cpa = ConfigurationPrinterAdapter.createAdapter(service, reference);
if ( cpa != null && cpa.title != null ) {
if ( cpa.title.startsWith("%") ) {
final String key = cpa.title.substring(1);
final ResourceBundle rb = this.rbManager.getResourceBundle(reference.getBundle());
if ( rb == null || !rb.containsKey(key) ) {
cpa.title = key;
} else {
cpa.title = rb.getString(key);
}
}
if ( cpa.label == null ) {
cpa.label = cpa.title;
}
final Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(StatusPrinter.CONFIG_NAME, cpa.label);
props.put(StatusPrinter.CONFIG_TITLE, cpa.title);
props.put(StatusPrinter.CONFIG_PRINTER_MODES, cpa.getPrinterModes());
if ( reference.getProperty(ConsoleConstants.PLUGIN_CATEGORY) != null ) {
props.put(StatusPrinter.CONFIG_CATEGORY, reference.getProperty(ConsoleConstants.PLUGIN_CATEGORY));
}
final ServiceRegistration reg = this.bundleContext.registerService(StatusPrinter.class.getName(), new ZipAttachmentProvider() {
/**
* @see org.apache.felix.status.StatusPrinter#print(org.apache.felix.status.PrinterMode, java.io.PrintWriter)
*/
public void print(final PrinterMode mode, final PrintWriter printWriter) {
final String m;
if ( mode == PrinterMode.HTML_BODY ) {
m = ConsoleConstants.MODE_WEB;
} else if ( mode == PrinterMode.TEXT ) {
m = ConsoleConstants.MODE_TXT;
} else if ( mode == PrinterMode.ZIP_FILE_BIN ) {
m = ConsoleConstants.MODE_ZIP;
} else {
m = null;
}
if ( m != null ) {
cpa.printConfiguration(printWriter, m);
}
}
/**
* @see org.apache.felix.status.ZipAttachmentProvider#addAttachments(java.lang.String, java.util.zip.ZipOutputStream)
*/
public void addAttachments(final String namePrefix, final ZipOutputStream zos)
throws IOException {
final URL[] attachments = cpa.getAttachments();
if ( attachments != null ) {
for(final URL current : attachments) {
final String path = current.getPath();
final String name;
if ( path == null || path.length() == 0 ) {
// sanity code, we should have a path, but if not let's
// just create some random name
name = "file" + Double.doubleToLongBits( Math.random() );
} else {
final int pos = path.lastIndexOf('/');
name = (pos == -1 ? path : path.substring(pos + 1));
}
final ZipEntry entry = new ZipEntry(namePrefix + name);
zos.putNextEntry(entry);
final InputStream is = current.openStream();
try {
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = is.read(buffer))) {
zos.write(buffer, 0, n);
}
} finally {
if ( is != null ) {
try { is.close(); } catch (final IOException ignore) {}
}
}
zos.closeEntry();
}
}
}
}, props);
synchronized ( this.registrations ) {
this.registrations.put(reference, reg);
}
}
}
private final void remove(final ServiceReference reference) {
final ServiceRegistration reg;
synchronized ( this.registrations ) {
reg = this.registrations.remove(reference);
}
if ( reg != null ) {
reg.unregister();
}
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
public Object addingService(final ServiceReference reference) {
final Object service = this.bundleContext.getService(reference);
if ( service != null ) {
this.add(reference, service);
}
return service;
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void modifiedService(final ServiceReference reference, final Object service) {
this.remove(reference);
this.add(reference, service);
}
/**
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void removedService(final ServiceReference reference, final Object service) {
this.remove(reference);
this.bundleContext.ungetService(reference);
}
}