[SM-4760] Add activation-api 2.0.1 bundle
diff --git a/activation-api-2.0.1/pom.xml b/activation-api-2.0.1/pom.xml
new file mode 100644
index 0000000..0094028
--- /dev/null
+++ b/activation-api-2.0.1/pom.xml
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.specs</groupId>
+        <artifactId>specs-pom</artifactId>
+        <version>2</version>
+        <relativePath>../specs-pom/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.servicemix.specs</groupId>
+    <artifactId>org.apache.servicemix.specs.activation-api-2.0.1</artifactId>
+    <packaging>bundle</packaging>
+    <version>2.0.1_1-SNAPSHOT</version>
+    <name>Apache ServiceMix :: Specs :: Activation API 2.0.1</name>
+
+    <scm>
+        <connection>scm:git:https://gitbox.apache.org/repos/asf/servicemix-specs.git</connection>
+        <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/servicemix-specs.git</developerConnection>
+        <url>https://gitbox.apache.org/repos/asf?p=servicemix-specs.git</url>
+  </scm>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.servicemix.specs</groupId>
+            <artifactId>org.apache.servicemix.specs.locator</artifactId>
+            <version>2.10</version>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.activation</groupId>
+            <artifactId>jakarta.activation-api</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>1.4.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-compiler-plugin</artifactId>
+              <inherited>true</inherited>
+              <configuration>
+                <compilerArgument>-Xbootclasspath/p:${settings.localRepository}/org/apache/geronimo/specs/geronimo-activation_1.1_spec/1.1/geronimo-activation_1.1_spec-1.1.jar</compilerArgument>
+              </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Description>${project.description}</Bundle-Description>
+                        <Export-Package>
+                          javax.activation*;version=2.0.1;-split-package:=merge-first;-noimport:=true,
+                          jakarta.activation*;version=2.0.1;-split-package:=merge-first;-noimport:=true
+                        </Export-Package>
+                        <Import-Package>
+                            *,
+                            !org.apache.servicemix.specs.activation
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.servicemix.specs.locator;-split-package:=merge-first,
+                            org.apache.servicemix.specs.activation;-split-package:=merge-first
+                        </Private-Package>
+                        <Bundle-Activator>org.apache.servicemix.specs.activation.Activator</Bundle-Activator>
+                        <Implementation-Title>Apache ServiceMix</Implementation-Title>
+                        <Implementation-Version>${project.version}</Implementation-Version>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>jakarta.activation:jakarta.activation-api</include>
+                                    <include>org.apache.servicemix.specs:org.apache.servicemix.specs.locator</include>
+                                    <include>${project.groupId}:${project.artifactId}</include>
+                                </includes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>jakarta.activation:jakarta.activation-api</artifact>
+                                    <excludes>
+                                        <exclude>javax/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.servicemix.specs:org.apache.servicemix.specs.locator</artifact>
+                                    <excludes>
+                                        <exclude>org/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <createSourcesJar>${createSourcesJar}</createSourcesJar>
+                            <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>deploy</id>
+            <properties>
+                <createSourcesJar>true</createSourcesJar>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>process-classes</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-sources</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.apache.servicemix.specs</groupId>
+                                            <artifactId>org.apache.servicemix.specs.locator</artifactId>
+                                            <classifier>sources</classifier>
+                                        </artifactItem>
+                                    </artifactItems>
+                                    <outputDirectory>${project.build.directory}/sources</outputDirectory>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>package</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <minmemory>128m</minmemory>
+                            <maxmemory>512m</maxmemory>
+                            <sourcepath>${project.build.directory}/sources</sourcepath>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/activation-api-2.0.1/src/main/java/javax/activation/DataHandler.java b/activation-api-2.0.1/src/main/java/javax/activation/DataHandler.java
new file mode 100644
index 0000000..b4b4bcf
--- /dev/null
+++ b/activation-api-2.0.1/src/main/java/javax/activation/DataHandler.java
@@ -0,0 +1,305 @@
+/*
+ * 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 javax.activation;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.net.URL;
+
+public class DataHandler implements Transferable {
+    private final DataSource ds;
+    private final DataFlavor flavor;
+
+    private CommandMap commandMap;
+    private DataContentHandler dch;
+
+    public DataHandler(DataSource ds) {
+        this.ds = ds;
+        this.flavor = new ActivationDataFlavor(ds.getContentType(), null);
+    }
+
+    public DataHandler(Object data, String type) {
+        this.ds = new ObjectDataSource(data, type);
+        this.flavor = new ActivationDataFlavor(data.getClass(), null);
+    }
+
+    public DataHandler(URL url) {
+        this.ds = new URLDataSource(url);
+        this.flavor = new ActivationDataFlavor(ds.getContentType(), null);
+    }
+
+    public DataSource getDataSource() {
+        return ds;
+    }
+
+    public String getName() {
+        return ds.getName();
+    }
+
+    public String getContentType() {
+        return ds.getContentType();
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return ds.getInputStream();
+    }
+
+    public void writeTo(OutputStream os) throws IOException {
+        if (ds instanceof ObjectDataSource) {
+            ObjectDataSource ods = (ObjectDataSource) ds;
+            DataContentHandler dch = getDataContentHandler();
+            if (dch == null) {
+                throw new UnsupportedDataTypeException(ods.mimeType);
+            }
+            dch.writeTo(ods.data, ods.mimeType, os);
+        } else {
+            byte[] buffer = new byte[1024];
+            InputStream is = getInputStream();
+            try {
+                int count;
+                while ((count = is.read(buffer)) != -1) {
+                    os.write(buffer, 0, count);
+                }
+            } finally {
+                is.close();
+            }
+        }
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        return ds.getOutputStream();
+    }
+
+    public synchronized DataFlavor[] getTransferDataFlavors() {
+        return getDataContentHandler().getTransferDataFlavors();
+    }
+
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+        DataFlavor[] flavors = getTransferDataFlavors();
+        for (int i = 0; i < flavors.length; i++) {
+            DataFlavor dataFlavor = flavors[i];
+            if (dataFlavor.equals(flavor)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+        DataContentHandler dch = getDataContentHandler();
+        if (dch != null) {
+            return dch.getTransferData(flavor, ds);
+        } else if (this.flavor.match(flavor)) {
+            if (ds instanceof ObjectDataSource) {
+                return ((ObjectDataSource) ds).data;
+            } else {
+                return ds.getInputStream();
+            }
+        } else {
+            throw new UnsupportedFlavorException(flavor);
+        }
+    }
+
+    public CommandInfo[] getPreferredCommands() {
+        return getCommandMap().getPreferredCommands(ds.getContentType());
+    }
+
+    public CommandInfo[] getAllCommands() {
+        return getCommandMap().getAllCommands(ds.getContentType());
+    }
+
+    public CommandInfo getCommand(String cmdName) {
+        return getCommandMap().getCommand(ds.getContentType(), cmdName);
+    }
+
+    public Object getContent() throws IOException {
+        if (ds instanceof ObjectDataSource) {
+            return ((ObjectDataSource) ds).data;
+        } else {
+            DataContentHandler dch = getDataContentHandler();
+            if (dch != null) {
+                return dch.getContent(ds);
+            } else {
+                return ds.getInputStream();
+            }
+        }
+    }
+
+    public Object getBean(CommandInfo cmdinfo) {
+        try {
+            return cmdinfo.getCommandObject(this, this.getClass().getClassLoader());
+        } catch (IOException e) {
+            return null;
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * A local implementation of DataSouce used to wrap an Object and mime-type.
+     */
+    private class ObjectDataSource implements DataSource {
+        private final Object data;
+        private final String mimeType;
+
+        public ObjectDataSource(Object data, String mimeType) {
+            this.data = data;
+            this.mimeType = mimeType;
+        }
+
+        public String getName() {
+            return null;
+        }
+
+        public String getContentType() {
+            return mimeType;
+        }
+
+        public InputStream getInputStream() throws IOException {
+            final DataContentHandler dch = getDataContentHandler();
+            if (dch == null) {
+                throw new UnsupportedDataTypeException(mimeType);
+            }
+            final PipedInputStream is = new PipedInputStream();
+            final PipedOutputStream os = new PipedOutputStream(is);
+            Thread thread = new Thread("DataHandler Pipe Pump") {
+                public void run() {
+                    try {
+                        try {
+                            dch.writeTo(data, mimeType, os);
+                        } finally {
+                            os.close();
+                        }
+                    } catch (IOException e) {
+                        // ignore, per spec - doh!
+                    }
+                }
+            };
+            thread.start();
+            return is;
+        }
+
+        public OutputStream getOutputStream() throws IOException {
+            return null;
+        }
+    }
+
+    public synchronized void setCommandMap(CommandMap commandMap) {
+        this.commandMap = commandMap;
+        this.dch = null;
+    }
+
+    private synchronized CommandMap getCommandMap() {
+        return commandMap != null ? commandMap : CommandMap.getDefaultCommandMap();
+    }
+
+    /**
+     * Search for a DataContentHandler for our mime type.
+     * The search is performed by first checking if a global factory has been set using
+     * {@link #setDataContentHandlerFactory(DataContentHandlerFactory)};
+     * if found then it is called to attempt to create a handler.
+     * If this attempt fails, we then call the command map set using {@link #setCommandMap(CommandMap)}
+     * (or if that has not been set, the default map returned by {@link CommandMap#getDefaultCommandMap()})
+     * to create the handler.
+     *
+     * The resulting handler is cached until the global factory is changed.
+     *
+     * @return
+     */
+    private synchronized DataContentHandler getDataContentHandler() {
+        DataContentHandlerFactory localFactory;
+        synchronized (DataHandler.class) {
+            if (factory != originalFactory) {
+                // setDCHF was called - clear our cached copy of the DCH and DCHF
+                dch = null;
+                originalFactory = factory;
+            }
+            localFactory = originalFactory;
+        }
+        if (dch == null) {
+            // get the main mime-type portion of the content.
+            String mimeType = getMimeType(ds.getContentType());
+            if (localFactory != null) {
+                dch = localFactory.createDataContentHandler(mimeType);
+            }
+            if (dch == null) {
+                dch = getCommandMap().createDataContentHandler(mimeType);
+            }
+        }
+        return dch;
+    }
+
+    /**
+     * Retrieve the base MIME type from a content type.  This parses
+     * the type into its base components, stripping off any parameter
+     * information.
+     *
+     * @param contentType
+     *               The content type string.
+     *
+     * @return The MIME type identifier portion of the content type.
+     */
+    private String getMimeType(String contentType) {
+        try {
+            MimeType mimeType = new MimeType(contentType);
+            return mimeType.getBaseType();
+        } catch (MimeTypeParseException e) {
+        }
+        return contentType;
+    }
+
+    /**
+     * This is used to check if the DataContentHandlerFactory has been changed.
+     * This is not specified behaviour but this check is required to make this work like the RI.
+     */
+    private DataContentHandlerFactory originalFactory;
+
+    {
+        synchronized (DataHandler.class) {
+            originalFactory = factory;
+        }
+    }
+
+    private static DataContentHandlerFactory factory;
+
+    /**
+     * Set the DataContentHandlerFactory to use.
+     * If this method has already been called then an Error is raised.
+     *
+     * @param newFactory the new factory
+     * @throws SecurityException if the caller does not have "SetFactory" RuntimePermission
+     */
+    public static synchronized void setDataContentHandlerFactory(DataContentHandlerFactory newFactory) {
+        if (factory != null) {
+            throw new Error("javax.activation.DataHandler.setDataContentHandlerFactory has already been defined");
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSetFactory();
+        }
+        factory = newFactory;
+    }
+}
diff --git a/activation-api-2.0.1/src/main/java/javax/activation/MailcapCommandMap.java b/activation-api-2.0.1/src/main/java/javax/activation/MailcapCommandMap.java
new file mode 100644
index 0000000..536083f
--- /dev/null
+++ b/activation-api-2.0.1/src/main/java/javax/activation/MailcapCommandMap.java
@@ -0,0 +1,515 @@
+/*
+ * 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 javax.activation;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class MailcapCommandMap extends CommandMap {
+    /**
+     * A string that holds all the special chars.
+     */
+    private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
+    private final Map mimeTypes = new HashMap();
+    private final Map preferredCommands = new HashMap();
+    private final Map allCommands = new HashMap();
+    // the unparsed commands from the mailcap file.
+    private final Map nativeCommands = new HashMap();
+    // commands identified as fallbacks...these are used last, and also used as wildcards.
+    private final Map fallbackCommands = new HashMap();
+    private URL url;
+
+    public MailcapCommandMap() {
+        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+        // process /META-INF/mailcap.default
+        try {
+            InputStream is = MailcapCommandMap.class.getResourceAsStream("/META-INF/mailcap.default");
+            if (is != null) {
+                try {
+                    parseMailcap(is);
+                } finally {
+                    is.close();
+                }
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // process /META-INF/mailcap resources
+        try {
+            Enumeration e = contextLoader.getResources("META-INF/mailcap");
+            while (e.hasMoreElements()) {
+                url = ((URL) e.nextElement());
+                try {
+                    InputStream is = url.openStream();
+                    try {
+                        parseMailcap(is);
+                    } finally {
+                        is.close();
+                    }
+                } catch (IOException e1) {
+                    continue;
+                }
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // process ${java.home}/lib/mailcap
+        try {
+            File file = new File(System.getProperty("java.home"), "lib/mailcap");
+            InputStream is = new FileInputStream(file);
+            try {
+                parseMailcap(is);
+            } finally {
+                is.close();
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // process ${user.home}/lib/mailcap
+        try {
+            File file = new File(System.getProperty("user.home"), ".mailcap");
+            InputStream is = new FileInputStream(file);
+            try {
+                parseMailcap(is);
+            } finally {
+                is.close();
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    public MailcapCommandMap(String fileName) throws IOException {
+        this();
+        FileReader reader = new FileReader(fileName);
+        try {
+            parseMailcap(reader);
+        } finally {
+            reader.close();
+        }
+    }
+
+    public MailcapCommandMap(InputStream is) {
+        this();
+        parseMailcap(is);
+    }
+
+    private void parseMailcap(InputStream is) {
+        try {
+            parseMailcap(new InputStreamReader(is));
+        } catch (IOException e) {
+            // spec API means all we can do is swallow this
+        }
+    }
+
+    void parseMailcap(Reader reader) throws IOException {
+        BufferedReader br = new BufferedReader(reader);
+        String line;
+        while ((line = br.readLine()) != null) {
+            addMailcap(line);
+        }
+    }
+
+    public synchronized void addMailcap(String mail_cap) {
+        int index = 0;
+        // skip leading whitespace
+        index = skipSpace(mail_cap, index);
+        if (index == mail_cap.length() || mail_cap.charAt(index) == '#') {
+            return;
+        }
+
+        // get primary type
+        int start = index;
+        index = getToken(mail_cap, index);
+        if (start == index) {
+            return;
+        }
+        String mimeType = mail_cap.substring(start, index);
+
+        // skip any spaces after the primary type
+        index = skipSpace(mail_cap, index);
+        if (index == mail_cap.length() || mail_cap.charAt(index) == '#') {
+            return;
+        }
+
+        // get sub-type
+        if (mail_cap.charAt(index) == '/') {
+            index = skipSpace(mail_cap, ++index);
+            start = index;
+            index = getToken(mail_cap, index);
+            mimeType = mimeType + '/' + mail_cap.substring(start, index);
+        } else {
+
+            mimeType = mimeType + "/*";
+        }
+
+        // we record all mappings using the lowercase version.
+        mimeType = mimeType.toLowerCase();
+
+        // skip spaces after mime type
+        index = skipSpace(mail_cap, index);
+
+        // expect a ';' to terminate field 1
+        if (index == mail_cap.length() || mail_cap.charAt(index) != ';') {
+            return;
+        }
+        // ok, we've parsed the mime text field, now parse the view field.  If there's something
+        // there, then we add this to the native text.
+        index = skipSpace(mail_cap, index + 1);
+        // if the next encountered text is not a ";", then we have a view.  This gets added to the
+        // native list.
+        if (index == mail_cap.length() || mail_cap.charAt(index) != ';') {
+            ArrayList nativeCommandList = (ArrayList)nativeCommands.get(mimeType);
+
+            // if this is the first for this mimetype, create a holder
+            if (nativeCommandList == null) {
+                nativeCommandList = new ArrayList();
+                nativeCommands.put(mimeType, nativeCommandList);
+            }
+
+            // now add this as an entry in the list.
+            nativeCommandList.add(mail_cap);
+            // now skip forward to the next field marker, if any
+            index = getMText(mail_cap, index);
+        }
+
+        // we don't know which list this will be added to until we finish parsing, as there
+        // can be an x-java-fallback-entry parameter that moves this to the fallback list.
+        List commandList = new ArrayList();
+        // but by default, this is not a fallback.
+        boolean fallback = false;
+
+        int fieldNumber = 0;
+
+        // parse fields
+        while (index < mail_cap.length() && mail_cap.charAt(index) == ';') {
+            index = skipSpace(mail_cap, index + 1);
+            start = index;
+            index = getToken(mail_cap, index);
+            String fieldName = mail_cap.substring(start, index).toLowerCase();
+            index = skipSpace(mail_cap, index);
+            if (index < mail_cap.length() && mail_cap.charAt(index) == '=') {
+                index = skipSpace(mail_cap, index + 1);
+                start = index;
+                index = getMText(mail_cap, index);
+                String value = mail_cap.substring(start, index);
+                index = skipSpace(mail_cap, index);
+                if (fieldName.startsWith("x-java-") && fieldName.length() > 7) {
+                    String command = fieldName.substring(7);
+                    value = value.trim();
+                    if (command.equals("fallback-entry")) {
+                        if (value.equals("true")) {
+                            fallback = true;
+                        }
+                    }
+                    else {
+                        // create a CommandInfo item and add it the accumulator
+                        CommandInfo info = new CommandInfo(command, value);
+                        commandList.add(info);
+                    }
+                }
+            }
+        }
+        addCommands(mimeType, commandList, fallback);
+    }
+
+    /**
+     * Add a parsed list of commands to the appropriate command list.
+     *
+     * @param mimeType The mimeType name this is added under.
+     * @param commands A List containing the command information.
+     * @param fallback The target list identifier.
+     */
+    protected void addCommands(String mimeType, List commands, boolean fallback) {
+        // add this to the mimeType set
+        mimeTypes.put(mimeType, mimeType);
+        // the target list changes based on the type of entry.
+        Map target = fallback ? fallbackCommands : preferredCommands;
+
+        // now process
+        for (Iterator i = commands.iterator(); i.hasNext();) {
+            CommandInfo info = (CommandInfo)i.next();
+            addCommand(target, mimeType, info);
+            // if this is not a fallback position, then this to the allcommands list.
+            if (!fallback) {
+                List cmdList = (List) allCommands.get(mimeType);
+                if (cmdList == null) {
+                    cmdList = new ArrayList();
+                    allCommands.put(mimeType, cmdList);
+                }
+                cmdList.add(info);
+            }
+        }
+    }
+
+
+    /**
+     * Add a command to a target command list (preferred or fallback).
+     *
+     * @param commandList
+     *                 The target command list.
+     * @param mimeType The MIME type the command is associated with.
+     * @param command  The command information.
+     */
+    protected void addCommand(Map commandList, String mimeType, CommandInfo command) {
+
+        Map commands = (Map) commandList.get(mimeType);
+        if (commands == null) {
+            commands = new HashMap();
+            commandList.put(mimeType, commands);
+        }
+        commands.put(command.getCommandName(), command);
+    }
+
+
+    private int skipSpace(String s, int index) {
+        while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
+            index++;
+        }
+        return index;
+    }
+
+    private int getToken(String s, int index) {
+        while (index < s.length() && s.charAt(index) != '#' && !isSpecialCharacter(s.charAt(index))) {
+            index++;
+        }
+        return index;
+    }
+
+    private int getMText(String s, int index) {
+        while (index < s.length()) {
+            char c = s.charAt(index);
+            if (c == '#' || c == ';' || Character.isISOControl(c)) {
+                return index;
+            }
+            if (c == '\\') {
+                index++;
+                if (index == s.length()) {
+                    return index;
+                }
+            }
+            index++;
+        }
+        return index;
+    }
+
+    public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
+        // get the mimetype as a lowercase version.
+        mimeType = mimeType.toLowerCase();
+
+        Map commands = (Map) preferredCommands.get(mimeType);
+        if (commands == null) {
+            commands = (Map) preferredCommands.get(getWildcardMimeType(mimeType));
+        }
+
+        Map fallbackCommands = getFallbackCommands(mimeType);
+
+        // if we have fall backs, then we need to merge this stuff.
+        if (fallbackCommands != null) {
+            // if there's no command list, we can just use this as the master list.
+            if (commands == null) {
+                commands = fallbackCommands;
+            }
+            else {
+                // merge the two lists.  The ones in the commands list will take precedence.
+                commands = mergeCommandMaps(commands, fallbackCommands);
+            }
+        }
+
+        // now convert this into an array result.
+        if (commands == null) {
+            return new CommandInfo[0];
+        }
+        return (CommandInfo[]) commands.values().toArray(new CommandInfo[commands.size()]);
+    }
+
+    private Map getFallbackCommands(String mimeType) {
+        Map commands = (Map) fallbackCommands.get(mimeType);
+
+        // now we also need to search this as if it was a wildcard.  If we get a wildcard hit,
+        // we have to merge the two lists.
+        Map wildcardCommands = (Map)fallbackCommands.get(getWildcardMimeType(mimeType));
+        // no wildcard version
+        if (wildcardCommands == null) {
+            return commands;
+        }
+        // we need to merge these.
+        return mergeCommandMaps(commands, wildcardCommands);
+    }
+
+
+    private Map mergeCommandMaps(Map main, Map fallback) {
+        // create a cloned copy of the second map.  We're going to use a PutAll operation to
+        // overwrite any duplicates.
+        Map result = new HashMap(fallback);
+        result.putAll(main);
+
+        return result;
+    }
+
+    public synchronized CommandInfo[] getAllCommands(String mimeType) {
+        mimeType = mimeType.toLowerCase();
+        List exactCommands = (List) allCommands.get(mimeType);
+        if (exactCommands == null) {
+            exactCommands = Collections.EMPTY_LIST;
+        }
+        List wildCommands = (List) allCommands.get(getWildcardMimeType(mimeType));
+        if (wildCommands == null) {
+            wildCommands = Collections.EMPTY_LIST;
+        }
+
+        Map fallbackCommands = getFallbackCommands(mimeType);
+        if (fallbackCommands == null) {
+            fallbackCommands = Collections.EMPTY_MAP;
+        }
+
+
+        CommandInfo[] result = new CommandInfo[exactCommands.size() + wildCommands.size() + fallbackCommands.size()];
+        int j = 0;
+        for (int i = 0; i < exactCommands.size(); i++) {
+            result[j++] = (CommandInfo) exactCommands.get(i);
+        }
+        for (int i = 0; i < wildCommands.size(); i++) {
+            result[j++] = (CommandInfo) wildCommands.get(i);
+        }
+
+        for (Iterator i = fallbackCommands.keySet().iterator(); i.hasNext();) {
+            result[j++] = (CommandInfo) fallbackCommands.get((String)i.next());
+        }
+        return result;
+    }
+
+    public synchronized CommandInfo getCommand(String mimeType, String cmdName) {
+        mimeType = mimeType.toLowerCase();
+        // strip any parameters from the supplied mimeType
+        int i = mimeType.indexOf(';');
+        if (i != -1) {
+            mimeType = mimeType.substring(0, i).trim();
+        }
+        cmdName = cmdName.toLowerCase();
+
+        // search for an exact match
+        Map commands = (Map) preferredCommands.get(mimeType);
+        if (commands == null || commands.get(cmdName) == null) {
+            // then a wild card match
+            commands = (Map) preferredCommands.get(getWildcardMimeType(mimeType));
+            if (commands == null || commands.get(cmdName) == null) {
+                // then fallback searches, both standard and wild card.
+                commands = (Map) fallbackCommands.get(mimeType);
+                if (commands == null || commands.get(cmdName) == null) {
+                    commands = (Map) fallbackCommands.get(getWildcardMimeType(mimeType));
+                }
+                if (commands == null) {
+                    return null;
+                }
+            }
+        }
+        return (CommandInfo) commands.get(cmdName);
+    }
+
+    private String getWildcardMimeType(String mimeType) {
+        int i = mimeType.indexOf('/');
+        if (i == -1) {
+            return mimeType + "/*";
+        } else {
+            return mimeType.substring(0, i + 1) + "*";
+        }
+    }
+
+    public synchronized DataContentHandler createDataContentHandler(String mimeType) {
+
+        CommandInfo info = getCommand(mimeType, "content-handler");
+        if (info == null) {
+            return null;
+        }
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = getClass().getClassLoader();
+        }
+        try {
+            return (DataContentHandler) cl.loadClass(info.getCommandClass()).newInstance();
+        } catch (ClassNotFoundException e) {
+            return null;
+        } catch (IllegalAccessException e) {
+            return null;
+        } catch (InstantiationException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get all MIME types known to this command map.
+     *
+     * @return A String array of the MIME type names.
+     */
+    public synchronized String[] getMimeTypes() {
+        ArrayList types = new ArrayList(mimeTypes.values());
+        return (String[])types.toArray(new String[types.size()]);
+    }
+
+    /**
+     * Return the list of raw command strings parsed
+     * from the mailcap files for a given mimeType.
+     *
+     * @param mimeType The target mime type
+     *
+     * @return A String array of the raw command strings.  Returns
+     *         an empty array if the mimetype is not currently known.
+     */
+    public synchronized String[] getNativeCommands(String mimeType) {
+        ArrayList commands = (ArrayList)nativeCommands.get(mimeType.toLowerCase());
+        if (commands == null) {
+            return new String[0];
+        }
+        return (String[])commands.toArray(new String[commands.size()]);
+    }
+    
+    private boolean isSpecialCharacter(char c) {
+        return Character.isWhitespace(c) || Character.isISOControl(c) || TSPECIALS.indexOf(c) != -1;
+    }
+}
diff --git a/activation-api-2.0.1/src/main/java/javax/activation/MimetypesFileTypeMap.java b/activation-api-2.0.1/src/main/java/javax/activation/MimetypesFileTypeMap.java
new file mode 100644
index 0000000..bf8836a
--- /dev/null
+++ b/activation-api-2.0.1/src/main/java/javax/activation/MimetypesFileTypeMap.java
@@ -0,0 +1,203 @@
+/*
+ * 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 javax.activation;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.Enumeration;
+import java.net.URL;
+
+/**
+ * @version $Rev: 467742 $ $Date: 2006-10-25 21:30:38 +0200 (Wed, 25 Oct 2006) $
+ */
+public class MimetypesFileTypeMap extends FileTypeMap {
+    private static final String DEFAULT_TYPE = "application/octet-stream";
+
+    private final Map types = new HashMap();
+
+    public MimetypesFileTypeMap() {
+        // defaults from /META-INF/mimetypes.default
+        try {
+            InputStream is = MimetypesFileTypeMap.class.getResourceAsStream("/META-INF/mimetypes.default");
+            if (is != null) {
+                try {
+                    loadStream(is);
+                } finally {
+                    is.close();
+                }
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // defaults from resources called /META-INF/mime.types
+        try {
+            ClassLoader cl = MimetypesFileTypeMap.class.getClassLoader();
+            if (cl != null) {
+                Enumeration e = cl.getResources("/META-INF/mime.types");
+                while (e.hasMoreElements()) {
+                    URL url = (URL)e.nextElement();
+                    try {
+                        InputStream is = url.openStream();
+                        try {
+                            loadStream(is);
+                        } finally {
+                            is.close();
+                        }
+                    } catch (IOException e1) {
+                        continue;
+                    }
+                }
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // defaults from ${java.home}/lib/mime.types
+        try {
+            File file = new File(System.getProperty("java.home"), "lib/mime.types");
+            InputStream is = new FileInputStream(file);
+            try {
+                loadStream(is);
+            } finally {
+                is.close();
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (FileNotFoundException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+
+        // defaults from ${user.home}/.mime.types
+        try {
+            File file = new File(System.getProperty("user.home"), ".mime.types");
+            InputStream is = new FileInputStream(file);
+            try {
+                loadStream(is);
+            } finally {
+                is.close();
+            }
+        } catch (SecurityException e) {
+            // ignore
+        } catch (FileNotFoundException e) {
+            // ignore
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException {
+        this();
+        BufferedReader reader = new BufferedReader(new FileReader(mimeTypeFileName));
+        try {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                addMimeTypesOneLine(line);
+            }
+            reader.close();
+        } catch (IOException e) {
+            try {
+                reader.close();
+            } catch (IOException e1) {
+                // ignore to allow original cause through
+            }
+            throw e;
+        }
+    }
+
+    public MimetypesFileTypeMap(InputStream is) {
+        this();
+        try {
+            loadStream(is);
+        } catch (IOException e) {
+            // ignore as the spec's signature says we can't throw IOException - doh!
+        }
+    }
+
+    private void loadStream(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        String line;
+        while ((line = reader.readLine()) != null) {
+            addMimeTypesOneLine(line);
+        }
+    }
+
+    private synchronized void addMimeTypesOneLine(String mime_types) {
+        int hashPos = mime_types.indexOf('#');
+        if (hashPos != -1) {
+            mime_types = mime_types.substring(0, hashPos);
+        }
+        StringTokenizer tok = new StringTokenizer(mime_types);
+        if (!tok.hasMoreTokens()) {
+            return;
+        }
+        String contentType = tok.nextToken();
+        while (tok.hasMoreTokens()) {
+            String fileType = tok.nextToken();
+            types.put(fileType, contentType);
+        }
+    }
+    
+    public synchronized void addMimeTypes(String mime_types) {
+        BufferedReader reader = new BufferedReader(new StringReader(mime_types));
+        try {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                addMimeTypesOneLine(line);
+            }
+            reader.close();
+        } catch (IOException e) {
+            try {
+                reader.close();
+            } catch (IOException e1) {
+                e1.printStackTrace();
+            }
+        }
+    }
+
+
+    public String getContentType(File f) {
+        return getContentType(f.getName());
+    }
+
+    public synchronized String getContentType(String filename) {
+        int index = filename.lastIndexOf('.');
+        if (index == -1 || index == filename.length()-1) {
+            return DEFAULT_TYPE;
+        }
+        String fileType = filename.substring(index + 1);
+        String contentType = (String) types.get(fileType);
+        return contentType == null ? DEFAULT_TYPE : contentType;
+    }
+}
diff --git a/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java b/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java
new file mode 100644
index 0000000..fc2643f
--- /dev/null
+++ b/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/Activator.java
@@ -0,0 +1,128 @@
+/*
+ * 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.servicemix.specs.activation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.activation.CommandMap;
+import javax.activation.DataContentHandler;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * A bundle activator for activation framework
+ */
+public class Activator extends org.apache.servicemix.specs.locator.Activator {
+
+    private Map<Long, MailCap> mailcaps = new ConcurrentHashMap<Long, MailCap>();
+
+    @Override
+    public void start(BundleContext bundleContext) throws Exception {
+        super.start(bundleContext);
+    }
+
+    @Override
+    public void stop(BundleContext bundleContext) throws Exception {
+        super.stop(bundleContext);
+        CommandMap.setDefaultCommandMap(null);
+    }
+
+    @Override
+    protected void register(Bundle bundle) {
+        debugPrintln("checking bundle " + bundle.getBundleId());
+        URL url = bundle.getResource("/META-INF/mailcap");
+        if (url != null) {
+            debugPrintln("found mailcap at " + url);
+
+            try {
+                final Class<?> clazz = bundle
+                        .loadClass("javax.activation.DataContentHandler");
+                if (!clazz.isAssignableFrom(DataContentHandler.class)) {
+                    debugPrintln("incompatible DataContentHandler class in bundle "
+                            + bundle.getBundleId());
+                    return;
+                }
+            } catch (ClassNotFoundException e) {
+                // ignored
+            }
+
+            try {
+                mailcaps.put(bundle.getBundleId(), new MailCap(bundle, url));
+            } catch (IOException ex) {
+                // ignored
+            }
+            rebuildCommandMap();
+        }
+    }
+
+    @Override
+    protected void unregister(long bundleId) {
+        MailCap mailcap = mailcaps.remove(bundleId);
+        if (mailcap != null ){
+            debugPrintln("removing mailcap for bundle " + mailcap.bundle.getBundleId());
+            rebuildCommandMap();
+        }
+    }
+
+    private void rebuildCommandMap() {
+        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+            OsgiMailcapCommandMap commandMap = new OsgiMailcapCommandMap();
+            for (MailCap mailcap : mailcaps.values()) {
+                for (String line : mailcap.lines) {
+                    commandMap.addMailcap(line, mailcap.bundle);
+                }
+            }
+            CommandMap.setDefaultCommandMap(commandMap);
+        } finally {
+            Thread.currentThread().setContextClassLoader(tccl);
+        }
+    }
+
+    private static class MailCap {
+        Bundle bundle;
+        List<String> lines;
+
+        private MailCap(Bundle bundle, URL url) throws IOException {
+            this.bundle = bundle;
+            this.lines = new ArrayList<String>();
+            InputStream is = url.openStream();
+            try {
+                BufferedReader br = new BufferedReader(new InputStreamReader(is));
+                String line;
+                while ((line = br.readLine()) != null) {
+                    lines.add(line);
+                }
+            } finally {
+                is.close();
+            }
+        }
+    }
+
+}
diff --git a/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/OsgiMailcapCommandMap.java b/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/OsgiMailcapCommandMap.java
new file mode 100644
index 0000000..a914247
--- /dev/null
+++ b/activation-api-2.0.1/src/main/java/org/apache/servicemix/specs/activation/OsgiMailcapCommandMap.java
@@ -0,0 +1,84 @@
+/*
+ * 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.servicemix.specs.activation;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.activation.MailcapCommandMap;
+import javax.activation.CommandInfo;
+import javax.activation.DataContentHandler;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * An OSGi enabled MailcapCommandMap
+ */
+public class OsgiMailcapCommandMap extends MailcapCommandMap {
+
+    private Bundle currentBundle;
+    private Map<CommandInfo, Bundle> bundles = new HashMap<CommandInfo, Bundle>();
+
+    public void addMailcap(String line, Bundle bundle) {
+        currentBundle = bundle;
+        addMailcap(line);
+    }
+
+    protected void addCommand(Map commandList, String mimeType, CommandInfo command) {
+        super.addCommand(commandList, mimeType, command);
+        if (currentBundle != null) {
+            bundles.put(command, currentBundle);
+        }
+    }
+
+    @Override
+    public DataContentHandler createDataContentHandler(String mimeType) {
+        CommandInfo info = getCommand(mimeType, "content-handler");
+        if (info == null) {
+            return null;
+        }
+
+        Bundle bundle = bundles.get(info);
+        if (bundle != null) {
+            try {
+                return (DataContentHandler) bundle.loadClass(info.getCommandClass()).newInstance();
+            } catch (ClassNotFoundException e) {
+                return null;
+            } catch (IllegalAccessException e) {
+                return null;
+            } catch (InstantiationException e) {
+                return null;
+            }
+        }
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = getClass().getClassLoader();
+        }
+        try {
+            return (DataContentHandler) cl.loadClass(info.getCommandClass()).newInstance();
+        } catch (ClassNotFoundException e) {
+            return null;
+        } catch (IllegalAccessException e) {
+            return null;
+        } catch (InstantiationException e) {
+            return null;
+        }
+    }
+}