blob: b2b8a4b1830d865e208565af98d12f2ce22275f1 [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.sling.javax.activation.internal;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.activation.CommandInfo;
import javax.activation.CommandMap;
import javax.activation.DataContentHandler;
import org.osgi.framework.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.activation.registries.MailcapFile;
/**
* The <tt>OsgiMailcapCommandMap</tt> is a <tt>CommandMap</tt> which ensures that {@link DataContentHandler} classes are
* loaded by their containing bundles.
*
* <p>
* This allows the javax.activation bundle to obey classloading contraints in an OSGi environment, while preserving most
* of the functionality available in an unmodified version of the bundle. Notably, this implementation does not support
* loading <tt>mailcap</tt> files which are not placed inside a bundle.
* </p>
*
*/
public class OsgiMailcapCommandMap extends CommandMap {
private static final Logger log = LoggerFactory.getLogger(OsgiMailcapCommandMap.class);
private final Map<Bundle, MailcapFile> db = new HashMap<Bundle, MailcapFile>();
private final Object sync = new Object();
public void addMailcapEntries(InputStream mailcapFile, Bundle originatingBundle) throws IOException {
synchronized (sync) {
db.put(originatingBundle, new MailcapFile(mailcapFile));
}
log.debug("Added mailcap entries from bundle {}", originatingBundle);
}
public void removeMailcapEntriesForBundle(Bundle bundle) {
boolean removed;
synchronized (sync) {
removed = db.remove(bundle) != null;
}
if (removed) {
log.debug("Removed mailcap entries from bundle {}", bundle);
}
}
@Override
public CommandInfo[] getPreferredCommands(String mimeType) {
List<CommandInfo> commands = new ArrayList<CommandInfo>();
if (mimeType != null) {
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
}
synchronized (sync) {
getPreferredCommands(mimeType, commands, false);
getPreferredCommands(mimeType, commands, true);
}
return commands.toArray(new CommandInfo[commands.size()]);
}
private void getPreferredCommands(String mimeType, List<CommandInfo> accumulator, boolean fallback) {
for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) {
Map<?, ?> commandMap = fallback ? entry.getValue().getMailcapFallbackList(mimeType) : entry.getValue()
.getMailcapList(mimeType);
if (commandMap == null) {
continue;
}
for (Object verbObject : commandMap.keySet()) {
String verb = (String) verbObject;
if (!commandsHaveVerb(accumulator, verb)) {
List<?> commands = (List<?>) commandMap.get(verb);
String className = (String) commands.get(0);
accumulator.add(new CommandInfo(verb, className));
}
}
}
}
@Override
public CommandInfo[] getAllCommands(String mimeType) {
List<CommandInfo> commands = new ArrayList<CommandInfo>();
if (mimeType != null) {
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
}
synchronized (sync) {
getAllCommands(mimeType, commands, false);
getAllCommands(mimeType, commands, true);
}
return commands.toArray(new CommandInfo[commands.size()]);
}
private void getAllCommands(String mimeType, List<CommandInfo> accumulator, boolean fallback) {
for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) {
Map<?, ?> commandMap = fallback ? entry.getValue().getMailcapFallbackList(mimeType) :
entry.getValue() .getMailcapList(mimeType);
if (commandMap == null) {
continue;
}
for (Object verbAsObject : commandMap.keySet()) {
String verb = (String) verbAsObject;
List<?> commands = (List<?>) commandMap.get(verb);
for (Object command : commands) {
accumulator.add(new CommandInfo(verb, (String) command));
}
}
}
}
@Override
public CommandInfo getCommand(String mimeType, String cmdName) {
if (mimeType != null) {
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
}
CommandInfo command = null;
synchronized (sync) {
command = getCommand(mimeType, cmdName, false);
if (command != null) {
return command;
}
command = getCommand(mimeType, cmdName, true);
}
return command;
}
private CommandInfo getCommand(String mimeType, String commandName, boolean fallback) {
for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) {
Map<?, ?> commandMap = fallback ? entry.getValue().getMailcapFallbackList(mimeType)
: entry.getValue().getMailcapList(mimeType);
if (commandMap != null) {
List<?> commands = (List<?>) commandMap.get(commandName);
if (commands == null) {
continue;
}
String cmdClassName = (String) commands.get(0);
if (cmdClassName != null) {
return new CommandInfo(commandName, cmdClassName);
}
}
}
return null;
}
@Override
public DataContentHandler createDataContentHandler(String mimeType) {
if (mimeType != null) {
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
}
synchronized (sync) {
DataContentHandler dch = findDataContentHandler(mimeType, false);
if (dch != null) {
return dch;
}
return findDataContentHandler(mimeType, true);
}
}
private DataContentHandler findDataContentHandler(String mimeType, boolean fallback) {
for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) {
Map<?, ?> commandMap = fallback ? entry.getValue().getMailcapFallbackList(mimeType) : entry.getValue()
.getMailcapList(mimeType);
if (commandMap != null) {
List<?> v = (List<?>) commandMap.get("content-handler");
if (v == null) {
continue;
}
String name = (String) v.get(0);
DataContentHandler dch = getDataContentHandler(name, entry.getKey());
if (dch != null) {
return dch;
}
}
}
return null;
}
public String[] getMimeTypes() {
List<String> mimeTypesList = new ArrayList<String>();
synchronized (sync) {
for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) {
String[] mimeTypes = entry.getValue().getMimeTypes();
for (String mimeType : mimeTypes) {
if (!mimeTypesList.contains(mimeType)) {
mimeTypesList.add(mimeType);
}
}
}
}
return mimeTypesList.toArray(new String[mimeTypesList.size()]);
}
private DataContentHandler getDataContentHandler(String name, Bundle bundle) {
try {
return (DataContentHandler) bundle.loadClass(name).newInstance();
} catch (InstantiationException e) {
log.warn("Unable to instantiate " + DataContentHandler.class.getSimpleName() + " class ' " + name
+ " ' from bundle " + bundle, e);
} catch (IllegalAccessException e) {
log.warn("Unable to instantiate " + DataContentHandler.class.getSimpleName() + " class ' " + name
+ " ' from bundle " + bundle, e);
} catch (ClassNotFoundException e) {
log.warn("Unable to instantiate " + DataContentHandler.class.getSimpleName() + " class ' " + name
+ " ' from bundle " + bundle, e);
}
return null;
}
private boolean commandsHaveVerb(List<CommandInfo> commands, String verb) {
for (CommandInfo commandInfo : commands) {
if (commandInfo.getCommandName().equals(verb)) {
return true;
}
}
return false;
}
}