package org.solmix.fmk.engine.internal.mime;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.service.log.LogService;
import org.solmix.fmk.engine.MimeTypeProvider;
import org.solmix.fmk.engine.MimeTypeService;
/**
* The <code>MimeTypeServiceImpl</code> is the official implementation of the {@link MimeTypeService} interface.
*/
public class MimeTypeServiceImpl implements MimeTypeService, BundleListener
{
public static final String CORE_MIME_TYPES = "/META-INF/core_mime.types";
public static final String MIME_TYPES = "/META-INF/mime.types";
// private static final String PROP_MIME_TYPES = "mime.types";
private LogService logService;
private Map<String, String> mimeTab = new HashMap<String, String>();
private Map<String, String> extensionMap = new HashMap<String, String>();
private MimeTypeProvider[] typeProviders;
private List<MimeTypeProvider> typeProviderList = new ArrayList<MimeTypeProvider>();
// private ServiceRegistration webConsolePluginService;
// --------- MimeTypeService interface
public String getMimeType(String name) {
if (name == null) {
return null;
}
String ext = name.substring(name.lastIndexOf('.') + 1);
ext = ext.toLowerCase();
String type = this.mimeTab.get(ext);
if (type == null) {
MimeTypeProvider[] mtp = this.getMimeTypeProviders();
for (int i = 0; type == null && i < mtp.length; i++) {
type = mtp[i].getMimeType(ext);
}
}
return type;
}
public String getExtension(String mimeType) {
if (mimeType == null) {
return null;
}
// compare using lowercase only
mimeType = mimeType.toLowerCase();
String ext = this.extensionMap.get(mimeType);
if (ext == null) {
MimeTypeProvider[] mtp = this.getMimeTypeProviders();
for (int i = 0; ext == null && i < mtp.length; i++) {
ext = mtp[i].getExtension(mimeType);
}
}
return ext;
}
public void registerMimeType(String mimeType, String... extensions) {
if (mimeType == null || mimeType.length() == 0 || extensions == null || extensions.length == 0) {
return;
}
mimeType = mimeType.toLowerCase();
String defaultExtension = extensionMap.get(mimeType);
for (String extension : extensions) {
if (extension != null && extension.length() > 0) {
extension = extension.toLowerCase();
String oldMimeType = mimeTab.get(extension);
if (oldMimeType == null) {
log(LogService.LOG_DEBUG, "registerMimeType: Add mapping " + extension + "=" + mimeType, null);
this.mimeTab.put(extension, mimeType);
if (defaultExtension == null) {
defaultExtension = extension;
}
} else {
log(LogService.LOG_INFO, "registerMimeType: Ignoring mapping " + extension + "=" + mimeType + ": Mapping " + extension + "="
+ oldMimeType + " alread exists", null);
}
}
}
if (defaultExtension != null) {
this.extensionMap.put(mimeType, defaultExtension);
}
}
public void registerMimeType(InputStream mimeTabStream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(mimeTabStream, "ISO-8859-1"));
String line;
while ((line = br.readLine()) != null) {
// ignore comment lines
if (line.startsWith("#")) {
continue;
}
registerMimeType(line);
}
}
// ---------- SCR implementation -------------------------------------------
// protected void activate(ComponentContext context) {
// context.getBundleContext().addBundleListener(this);
//
// // register core and default sling mime types
// Bundle bundle = context.getBundleContext().getBundle();
// registerMimeType(bundle.getEntry(CORE_MIME_TYPES));
// registerMimeType(bundle.getEntry(MIME_TYPES));
//
// // register maps of existing bundles
// Bundle[] bundles = context.getBundleContext().getBundles();
// for (int i = 0; i < bundles.length; i++) {
// if ((bundles[i].getState() & (Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0
// && bundles[i].getBundleId() != bundle.getBundleId()) {
// this.registerMimeType(bundles[i].getEntry(MIME_TYPES));
// }
// }
//
// // register configuration properties
// // String[] configTypes = OsgiUtils.toStringArray(context.getProperties().get(PROP_MIME_TYPES));
// // if (configTypes != null) {
// // for (String configType : configTypes) {
// // registerMimeType(configType);
// // }
// // }
//
// try {
// MimeTypeWebConsolePlugin plugin = new MimeTypeWebConsolePlugin(this);
//
// Dictionary<String, String> props = new Hashtable<String, String>();
// props.put("felix.webconsole.label", MimeTypeWebConsolePlugin.LABEL);
// props.put("felix.webconsole.title", MimeTypeWebConsolePlugin.TITLE);
// props.put("felix.webconsole.css", MimeTypeWebConsolePlugin.CSS_REFS);
//
// webConsolePluginService = context.getBundleContext().registerService("javax.servlet.Servlet", plugin, props);
// } catch (Throwable t) {
// // don't care, we thus don't have the console plugin
// }
// }
//
// // protected void deactivate(ComponentContext context) {
// // context.getBundleContext().removeBundleListener(this);
// //
// // if (webConsolePluginService != null) {
// // webConsolePluginService.unregister();
// // webConsolePluginService = null;
// // }
// // }
protected void bindMimeTypeProvider(MimeTypeProvider mimeTypeProvider) {
synchronized (this.typeProviderList) {
this.typeProviderList.add(mimeTypeProvider);
this.typeProviders = null;
}
}
protected void unbindMimeTypeProvider(MimeTypeProvider mimeTypeProvider) {
synchronized (this.typeProviderList) {
this.typeProviderList.remove(mimeTypeProvider);
this.typeProviders = null;
}
}
// ---------- BundleListener ----------------------------------------------
public void bundleChanged(BundleEvent event) {
if (event.getType() == BundleEvent.RESOLVED) {
this.registerMimeType(event.getBundle().getEntry(MIME_TYPES));
}
}
// ---------- plugin support -----------------------------------------------
Map<String, String> getMimeMap() {
return mimeTab;
}
Map<String, String> getExtensionMap() {
return extensionMap;
}
// ---------- internal -----------------------------------------------------
private MimeTypeProvider[] getMimeTypeProviders() {
MimeTypeProvider[] list = this.typeProviders;
if (list == null) {
synchronized (this.typeProviderList) {
this.typeProviders = this.typeProviderList.toArray(new MimeTypeProvider[this.typeProviderList.size()]);
list = this.typeProviders;
}
}
return list;
}
private void registerMimeType(URL mimetypes) {
if (mimetypes != null) {
InputStream ins = null;
try {
ins = mimetypes.openStream();
this.registerMimeType(ins);
} catch (IOException ioe) {
// log but don't actually care
this.log(LogService.LOG_WARNING, "An error occurred reading " + mimetypes, ioe);
} finally {
if (ins != null) {
try {
ins.close();
} catch (IOException ioe) {
// ignore
}
}
}
}
}
/**
* Splits the <code>line</code> on whitespace an registers the MIME type mappings provided the line contains more
* than one whitespace separated fields.
*
* @throws NullPointerException if <code>line</code> is <code>null</code>.
*/
private void registerMimeType(String line) {
String[] parts = line.split("\\s+");
if (parts.length > 1) {
String[] extensions = new String[parts.length - 1];
System.arraycopy(parts, 1, extensions, 0, extensions.length);
this.registerMimeType(parts[0], extensions);
}
}
private void log(int level, String message, Throwable t) {
LogService log = this.logService;
if (log != null) {
log.log(level, message, t);
} else {
PrintStream out = (level == LogService.LOG_ERROR) ? System.err : System.out;
out.println(message);
if (t != null) {
t.printStackTrace(out);
}
}
}
}