| /* |
| * 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.DataContentHandler; |
| import javax.activation.MailcapCommandMap; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.FrameworkUtil; |
| 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 MailcapCommandMap { |
| |
| 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(); |
| private Caller caller = null; |
| |
| @Override |
| public synchronized void addMailcap(String mailcap) { |
| if (caller == null) { |
| caller = new Caller(); |
| } |
| Bundle bundle = caller.get(); |
| if (bundle != null) { |
| db.computeIfAbsent(bundle, x -> new MailcapFile()) |
| .appendToMailcap(mailcap); |
| } |
| } |
| |
| 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 synchronized CommandInfo[] getPreferredCommands(String mimeType) { |
| |
| List<CommandInfo> commands = new ArrayList<CommandInfo>(); |
| |
| if (mimeType != null) { |
| mimeType = mimeType.toLowerCase(Locale.ENGLISH); |
| } |
| |
| 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 synchronized CommandInfo[] getAllCommands(String mimeType) { |
| List<CommandInfo> commands = new ArrayList<CommandInfo>(); |
| if (mimeType != null) { |
| mimeType = mimeType.toLowerCase(Locale.ENGLISH); |
| } |
| |
| 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 synchronized CommandInfo getCommand(String mimeType, String cmdName) { |
| if (mimeType != null) { |
| mimeType = mimeType.toLowerCase(Locale.ENGLISH); |
| } |
| |
| CommandInfo command = null; |
| |
| 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 synchronized DataContentHandler createDataContentHandler(String mimeType) { |
| if (mimeType != null) { |
| mimeType = mimeType.toLowerCase(Locale.ENGLISH); |
| } |
| |
| 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; |
| } |
| |
| @Override |
| public synchronized String[] getMimeTypes() { |
| List<String> mimeTypesList = new ArrayList<String>(); |
| |
| 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()]); |
| } |
| |
| @Override |
| public synchronized String[] getNativeCommands(String mimeType) { |
| List<String> cmdList = new ArrayList<>(); |
| if (mimeType != null) { |
| mimeType = mimeType.toLowerCase(Locale.ENGLISH); |
| } |
| |
| for (Map.Entry<Bundle, MailcapFile> entry : db.entrySet()) { |
| String[] cmds = entry.getValue().getNativeCommands(mimeType); |
| if (cmds != null) { |
| for (String cmd : cmds) { |
| if (!cmdList.contains(cmd)) { |
| cmdList.add(cmd); |
| } |
| } |
| } |
| } |
| |
| return cmdList.toArray(new String[cmdList.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; |
| } |
| |
| private static final class Caller extends SecurityManager { |
| Bundle get() { |
| Class[] stack = getClassContext(); |
| for (int i = 0; i < stack.length; i++) { |
| Bundle bundle = FrameworkUtil.getBundle(stack[i]); |
| if (bundle != null && !bundle.equals(FrameworkUtil.getBundle(getClass()))) { |
| return bundle; |
| } |
| } |
| return null; |
| } |
| } |
| } |