Copybara import of the project:

  - a08bf530f67a36b3b746a940140e47ddc9ded512 Initial Contribution by Vinay Vishal <vinay.vishal@oracle.com>
  - d8fd8aa774ada0b41c9ecfeb8427ab2aac060de1 Remove unnecessary file from repository (#6) by Vinay Vishal <vinayvishal@users.noreply.github.com>
  - f91b943ea39644e3b69ea8b46084849cbd13918d Changes groupId to jakarta (master) (#8) by Dmitry Kornilov <maiden168@gmail.com>
  - 5bef63640cfaca5f1fe853dfc5f553bde9db20c7 Fix javadoc errors so "mvn deploy" will work. by Bill Shannon <bill.shannon@oracle.com>
  - 7b4a3aeb2d8e4c929a59de0bac4acaad9db5b2e5 Switch to new parent pom; include LICENSE.md and NOTICE.m... by Bill Shannon <bill.shannon@oracle.com>
  - 38c6aed6bc0092e45f991b08719973c723646f6a Remove incorrect trademark and crypo sections, update lic... by Bill Shannon <bill.shannon@oracle.com>
  - e9d4a8c283d6e4d67bd2179251e7b50fe41eb637 Add .gitignore file. by Bill Shannon <bill.shannon@oracle.com>
  - 471681a2fd534749decbb39977202980f20f173b Switch to jakarta coordinates. by Bill Shannon <bill.shannon@oracle.com>
  - 6b6c467a2687ae6f47ec37a37af07cc4b0279541 JAF 1.2.1 Final Release. by Bill Shannon <bill.shannon@oracle.com>
  - 919fd80179befb05ebc067dcd859d43851a4445d Update gpg version by Vinay Vishal <vinay.vishal@oracle.com>
  - e5623f7365f4d10b38a9d931e7f7fbd190924439 Add nexus-staging-maven-plugin configuration. by Bill Shannon <bill.shannon@oracle.com>
  - 82f0d49e14d8aed9d252a8e9277c26561de50e5c Update version to 1.2.2-SNAPSHOT. by Bill Shannon <bill.shannon@oracle.com>
  - e958beac1987078335b6256660be276f0d56d527 Update to 1.0.5 parent pom and remove unneeded configurat... by Bill Shannon <bill.shannon@oracle.com>
  - 4bb76a8c3d349c506d5fbc80ab515c7ad958bf23 Add pointer to JAF web site. by Bill Shannon <bill.shannon@oracle.com>
  - 70e71e6aab37cb0a9621fe19b7ce03190eff4f03 Exclude com.sun.* packages from API jar file OSGi manifes... by Bill Shannon <bill.shannon@oracle.com>
  - ee77e3830b5c234fc0cfb15666e1897cf46de664 Add spec/ submodule with boilerplate asciidoc (#25) by David Blevins <david.blevins@gmail.com>
  - 747f285f63d0c59b06613b30a4f498acd783abdd Fix parent pom reference; fix version; fix copyright line. by Bill Shannon <bill.shannon@oracle.com>
  - f1ee8512d9c4aa36404b0fafb69ff151855b754e Update min maven version (#27) by Piotrek Żygieło <pzygielo@users.noreply.github.com>
  - 6c636d2509aa155e518a5ac5524763069ea14989 Update project name to Jakarta Activation - fix #20. by Bill Shannon <bill.shannon@oracle.com>
  - b50200a8b9e3fd4182728398db40644fff1ee6a4 Change name to Jakarta Activation. by Bill Shannon <bill.shannon@oracle.com>
  - b915c7c9be3db8a6a1d28586b0e3b9193ca0c16e Update spec for final release. by Bill Shannon <bill.shannon@oracle.com>
  - 69497814b252bfa9b5b88020713489b32525774b Build (only) with JDK 9+; build a real module. by Bill Shannon <bill.shannon@oracle.com>
  - 8fe222817d846334b55d6d74ca44396d453bd694 Add spec license file. by Bill Shannon <bill.shannon@oracle.com>
  - 177daf703c7cdb61cb63aeaf9744821e8d6dd192 Fix build of API jar file and demos. by Bill Shannon <bill.shannon@oracle.com>
  - 02c28b24426c90820067a69420143825bf4474b4 Need to link to SE 9 docs or javadoc fails running in Ecl... by Bill Shannon <bill.shannon@oracle.com>
  - 204c56e75e6a59c27db3ee37a4b7d41504ed0497 Force non-module javadocs. by Bill Shannon <bill.shannon@oracle.com>
  - fe43eca037845c051ffd9894e66d285adf8b9067 Build all but module-info.java with -source 1.8. by Bill Shannon <bill.shannon@oracle.com>
  - 67e9b0525099a81818cf89302e1ba6f3c68ebba0 Fix javadoc build to include doc-files directory. by Bill Shannon <bill.shannon@oracle.com>
  - 595cc35e9b3e836193a780806e95dfbeef031b86 1.2.2 Final Release by Bill Shannon <bill.shannon@oracle.com>
  - 7f39afbf1049849a957c3bf4e68ab9c8627b9a70 Remove links to Java SE javadocs. by Bill Shannon <bill.shannon@oracle.com>
  - eea7f7c022c582af1d84deb21fb23cbde19fb074 Disable links to Java APIs. by Bill Shannon <bill.shannon@oracle.com>
  - 287696ee85a93b0d9062b5d7411a5bdc813c3d73 Make all APIs available to API jar file javadoc. by Bill Shannon <bill.shannon@oracle.com>
  - 0345740ecc36698e11a22bea7f86a3ec4c85e0a2 Define oss-release profile. by Bill Shannon <bill.shannon@oracle.com>
  - 6b9e077c085be3646d56a2fe538c784e21b177e8 Add module-info to API jar file. by Bill Shannon <bill.shannon@oracle.com>
  - a1c5ecb351574c973b5e8f17855a2ca201c9f201 Need all the source files for javadoc, but exclude them i... by Bill Shannon <bill.shannon@oracle.com>
  - 6ca0946a067ba1c2424d9800768957fa486a1ca0 Add issue templates. by Bill Shannon <bill.shannon@oracle.com>
  - 942500e691f95b2ae7935387ff9b58290d6d4aeb Update to new parent pom. by Bill Shannon <bill.shannon@oracle.com>
  - 9a459923860d8dfba4ef7d4ef4250bd1c663ff87 Initial version of the full specification document text. by Bill Shannon <bill.shannon@oracle.com>
  - e199f61f414fa3455734a407a6e56469b3ad97b4 Update for Jakarta EE; fix formatting. by Bill Shannon <bill.shannon@oracle.com>

GitOrigin-RevId: e199f61f414fa3455734a407a6e56469b3ad97b4
Change-Id: I472f7cc0f89f543c48d9b1aff8ce293a8cf0d7d7
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dd84ea7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/compatibility-certification-request.md b/.github/ISSUE_TEMPLATE/compatibility-certification-request.md
new file mode 100644
index 0000000..a6648c8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/compatibility-certification-request.md
@@ -0,0 +1,27 @@
+---
+name: Compatibility certification request
+about: Request certification of a compatible implementation of Jakarta Mail.
+title: Compatibility certification request for [product/project name]
+labels: certification
+assignees: ''
+
+---
+
+- [ ] Organization Name ("Organization") and, if applicable, URL\
+  // Add here
+- [ ] Product Name, Version and download URL (if applicable)\
+  // Add here
+- [ ] Specification Name, Version and download URL\
+   // Add here
+- [ ] TCK Version, digital SHA-256 fingerprint and download URL\
+  // Add here
+- [ ] Public URL of TCK Results Summary\
+  // Add here
+- [ ] Any Additional Specification Certification Requirements\
+  // Add here
+- [ ] Java runtime used to run the implementation\
+  // Add here
+- [ ] Summary of the information for the certification environment, operating system, cloud, ...\
+  // Add here
+- [ ] By checking this box I acknowledge that the Organization I represent accepts the terms of the [EFTL](https://www.eclipse.org/legal/tck.php).
+- [ ] By checking this box I attest that all TCK requirements have been met, including any compatibility rules.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7f8f2f1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+target/
+*/target/
+.m2/
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000..2a548dd
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1 @@
+dfaec4fe670da9f3554e3639e6907aeccb2bc1bc JAF-1_2_0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..46195fd
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing to Jakarta Activation
+
+Thanks for your interest in this project.
+
+## Project description
+
+Jakarta Activation lets you take advantage of standard services to:
+determine the type of an arbitrary piece of data; encapsulate access to
+discover the operations available on it; and instantiate the
+appropriate bean to perform the operation(s).
+
+* https://projects.eclipse.org/projects/ee4j.jaf
+
+## Developer resources
+
+Information regarding source code management, builds, coding standards, and
+more.
+
+* https://projects.eclipse.org/projects/ee4j.jaf/developer
+
+The project maintains the following source code repositories
+
+* https://github.com/eclipse-ee4j/jaf
+
+## Eclipse Contributor Agreement
+
+Before your contribution can be accepted by the project team contributors must
+electronically sign the Eclipse Contributor Agreement (ECA).
+
+* http://www.eclipse.org/legal/ECA.php
+
+Commits that are provided by non-committers must have a Signed-off-by field in
+the footer indicating that the author is aware of the terms by which the
+contribution has been provided to the project. The non-committer must
+additionally have an Eclipse Foundation account and must have a signed Eclipse
+Contributor Agreement (ECA) on file.
+
+For more information, please see the Eclipse Committer Handbook:
+https://www.eclipse.org/projects/handbook/#resources-commit
+
+## Contact
+
+Contact the project developers via the project's "dev" list.
+
+* https://accounts.eclipse.org/mailing-list/jaf-dev
+
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..e0358f9
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,29 @@
+
+    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+   
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+   
+      - Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+   
+      - Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+   
+      - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+   
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/NOTICE.md b/NOTICE.md
new file mode 100644
index 0000000..010e450
--- /dev/null
+++ b/NOTICE.md
@@ -0,0 +1,33 @@
+# Notices for Jakarta Activation
+
+This content is produced and maintained by Jakarta Activation project.
+
+* Project home: https://projects.eclipse.org/projects/ee4j.jaf
+
+## Copyright
+
+All content is the property of the respective authors or their employers. For
+more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Distribution License v. 1.0,
+which is available at http://www.eclipse.org/org/documents/edl-v10.php.
+
+SPDX-License-Identifier: BSD-3-Clause
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+* https://github.com/eclipse-ee4j/jaf
+
+## Third-party Content
+
+This project leverages the following third party content.
+
+JUnit (4.12)
+
+* License: Eclipse Public License
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..89be0a4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# Jakarta Activation
+
+Jakarta Activation lets you take advantage of standard services to:
+determine the type of an arbitrary piece of data; encapsulate access to
+it; discover the operations available on it; and instantiate the
+appropriate bean to perform the operation(s).
+
+See the
+[Jakarta Activation web site](https://eclipse-ee4j.github.io/jaf/).
diff --git a/activation/pom.xml b/activation/pom.xml
new file mode 100644
index 0000000..75b79db
--- /dev/null
+++ b/activation/pom.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+
+    Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<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">
+    <parent>
+	<groupId>com.sun.activation</groupId>
+	<artifactId>all</artifactId>
+	<version>1.2.2</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.activation</groupId>
+    <artifactId>jakarta.activation</artifactId>
+    <packaging>jar</packaging>
+    <name>Jakarta Activation</name>
+
+    <properties>
+	<activation.extensionName>
+	    jakarta.activation
+	</activation.extensionName>
+	<activation.moduleName>
+	    jakarta.activation
+	</activation.moduleName>
+	<activation.specificationTitle>
+	    Jakarta Activation Specification
+	</activation.specificationTitle>
+	<activation.implementationTitle>
+	    javax.activation
+	</activation.implementationTitle>
+	<activation.packages.export>
+	    javax.activation.*; version=${activation.spec.version},
+	    com.sun.activation.*; version=${activation.osgiversion}
+	</activation.packages.export>
+	<findbugs.skip>
+	    false
+	</findbugs.skip>
+	<findbugs.exclude>
+	    ${project.basedir}/exclude.xml
+	</findbugs.exclude>
+    </properties>
+
+    <build>
+	<resources>
+	    <resource>
+		<directory>src/main/resources</directory>
+		<filtering>true</filtering>
+	    </resource>
+	</resources>
+	<plugins>
+	    <!--
+		Configure compiler plugin to print lint warnings.
+	    -->
+	    <plugin>
+		<artifactId>maven-compiler-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>default-compile</id>
+			<configuration>
+			    <!--
+				ignore some of the errors that are
+				too hard to fix for now
+			    -->
+			    <!--
+			    <compilerArguments>
+				<Xlint:all/>
+				<Xlint:-rawtypes/>
+				<Xlint:-unchecked/>
+				<Xlint:-finally/>
+			    </compilerArguments>
+			    <showWarnings>true</showWarnings>
+			    -->
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Configure test plugin to find *TestSuite classes.
+	    -->
+	    <plugin>
+		<groupId>org.apache.maven.plugins</groupId>
+		<artifactId>maven-surefire-plugin</artifactId>
+		<configuration>
+		    <includes>
+			<include>**/*Test.java</include>
+			<include>**/*TestSuite.java</include>
+		    </includes>
+		</configuration>
+	    </plugin>
+
+	    <plugin>
+		<artifactId>maven-javadoc-plugin</artifactId>
+		<inherited>false</inherited>
+                <executions>
+		    <execution>
+			<phase>package</phase>
+			<goals>
+			    <goal>javadoc</goal>
+			</goals>
+			<configuration>
+			    <author>false</author>
+			    <description>
+				Jakarta Activation API documentation
+			    </description>
+			    <doctitle>
+				Jakarta Activation API documentation
+			    </doctitle>
+			    <windowtitle>
+				Jakarta Activation API documentation
+			    </windowtitle>
+			    <splitindex>true</splitindex>
+			    <use>true</use>
+			    <notimestamp>true</notimestamp>
+			    <serialwarn>true</serialwarn>
+			    <quiet>true</quiet>
+			    <bottom>
+<![CDATA[Copyright &#169; 2019 Eclipse Foundation.
+    Use is subject to
+    <a href="{@docRoot}/doc-files/speclicense.html" target="_top">license terms</a>.
+]]>
+			    </bottom>
+			    <groups>
+				<group>
+				    <title>Jakarta Activation API Packages</title>
+				    <packages>javax.*</packages>
+				</group>
+			    </groups>
+			    <!--
+			    <subpackages>javax.activation</subpackages>
+			    -->
+			    <!--
+				Force javadoc to produce non-module docs
+				since the module definition isn't part of
+				the API specification.
+			    -->
+			    <release>8</release>
+			    <sourceFileExcludes>
+				<sourceFileExclude>module-info.java</sourceFileExclude>
+				<sourceFileExclude>com/**</sourceFileExclude>
+			    </sourceFileExcludes>
+			    <!-- force the doc-files directory to be copied -->
+			    <docfilessubdirs>true</docfilessubdirs>
+			    <detectJavaApiLink>false</detectJavaApiLink>
+			</configuration>
+		    </execution>
+                </executions>
+	    </plugin>
+	</plugins>
+    </build>
+
+    <dependencies>
+	<dependency>
+	    <groupId>junit</groupId>
+	    <artifactId>junit</artifactId>
+	    <version>4.12</version>
+	    <scope>test</scope>
+	    <optional>true</optional>
+	</dependency>
+    </dependencies>
+</project>
diff --git a/activation/src/main/java/com/sun/activation/registries/LogSupport.java b/activation/src/main/java/com/sun/activation/registries/LogSupport.java
new file mode 100644
index 0000000..3228f3c
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/LogSupport.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.registries;
+
+import java.io.*;
+import java.util.logging.*;
+
+/**
+ * Logging related methods.
+ */
+public class LogSupport {
+    private static boolean debug = false;
+    private static Logger logger;
+    private static final Level level = Level.FINE;
+
+    static {
+	try {
+	    debug = Boolean.getBoolean("javax.activation.debug");
+	} catch (Throwable t) {
+	    // ignore any errors
+	}
+	logger = Logger.getLogger("javax.activation");
+    }
+
+    /**
+     * Constructor.
+     */
+    private LogSupport() {
+	// private constructor, can't create instances
+    }
+
+    public static void log(String msg) {
+	if (debug)
+	    System.out.println(msg);
+	logger.log(level, msg);
+    }
+
+    public static void log(String msg, Throwable t) {
+	if (debug)
+	    System.out.println(msg + "; Exception: " + t);
+	logger.log(level, msg, t);
+    }
+
+    public static boolean isLoggable() {
+	return debug || logger.isLoggable(level);
+    }
+}
diff --git a/activation/src/main/java/com/sun/activation/registries/MailcapFile.java b/activation/src/main/java/com/sun/activation/registries/MailcapFile.java
new file mode 100644
index 0000000..09deb1b
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/MailcapFile.java
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.registries;
+
+import java.io.*;
+import java.util.*;
+
+public class MailcapFile {
+
+    /**
+     * A Map indexed by MIME type (string) that references
+     * a Map of commands for each type.  The comand Map
+     * is indexed by the command name and references a List of
+     * class names (strings) for each command.
+     */
+    private Map type_hash = new HashMap();
+
+    /**
+     * Another Map like above, but for fallback entries.
+     */
+    private Map fallback_hash = new HashMap();
+
+    /**
+     * A Map indexed by MIME type (string) that references
+     * a List of native commands (string) corresponding to the type.
+     */
+    private Map native_commands = new HashMap();
+
+    private static boolean addReverse = false;
+
+    static {
+	try {
+	    addReverse = Boolean.getBoolean("javax.activation.addreverse");
+	} catch (Throwable t) {
+	    // ignore any errors
+	}
+    }
+
+    /**
+     * The constructor that takes a filename as an argument.
+     *
+     * @param new_fname The file name of the mailcap file.
+     * @throws	IOException	for I/O errors
+     */
+    public MailcapFile(String new_fname) throws IOException {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("new MailcapFile: file " + new_fname);
+	FileReader reader = null;
+	try {
+	    reader = new FileReader(new_fname);
+	    parse(new BufferedReader(reader));
+	} finally {
+	    if (reader != null) {
+		try {
+		    reader.close();
+		} catch (IOException ex) { }
+	    }
+	}
+    }
+
+    /**
+     * The constructor that takes an input stream as an argument.
+     *
+     * @param is	the input stream
+     * @throws	IOException	for I/O errors
+     */
+    public MailcapFile(InputStream is) throws IOException {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("new MailcapFile: InputStream");
+	parse(new BufferedReader(new InputStreamReader(is, "iso-8859-1")));
+    }
+
+    /**
+     * Mailcap file default constructor.
+     */
+    public MailcapFile() {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("new MailcapFile: default");
+    }
+
+    /**
+     * Get the Map of MailcapEntries based on the MIME type.
+     *
+     * <p>
+     * <strong>Semantics:</strong> First check for the literal mime type,
+     * if that fails looks for wildcard &lt;type&gt;/\* and return that.
+     * Return the list of all that hit.
+     *
+     * @param	mime_type	the MIME type
+     * @return	the map of MailcapEntries
+     */
+    public Map getMailcapList(String mime_type) {
+	Map search_result = null;
+	Map wildcard_result = null;
+
+	// first try the literal
+	search_result = (Map)type_hash.get(mime_type);
+
+	// ok, now try the wildcard
+	int separator = mime_type.indexOf('/');
+	String subtype = mime_type.substring(separator + 1);
+	if (!subtype.equals("*")) {
+	    String type = mime_type.substring(0, separator + 1) + "*";
+	    wildcard_result = (Map)type_hash.get(type);
+
+	    if (wildcard_result != null) { // damn, we have to merge!!!
+		if (search_result != null)
+		    search_result =
+			mergeResults(search_result, wildcard_result);
+		else
+		    search_result = wildcard_result;
+	    }
+	}
+	return search_result;
+    }
+
+    /**
+     * Get the Map of fallback MailcapEntries based on the MIME type.
+     *
+     * <p>
+     * <strong>Semantics:</strong> First check for the literal mime type,
+     * if that fails looks for wildcard &lt;type&gt;/\* and return that.
+     * Return the list of all that hit.
+     *
+     * @param	mime_type	the MIME type
+     * @return	the map of fallback MailcapEntries
+     */
+    public Map getMailcapFallbackList(String mime_type) {
+	Map search_result = null;
+	Map wildcard_result = null;
+
+	// first try the literal
+	search_result = (Map)fallback_hash.get(mime_type);
+
+	// ok, now try the wildcard
+	int separator = mime_type.indexOf('/');
+	String subtype = mime_type.substring(separator + 1);
+	if (!subtype.equals("*")) {
+	    String type = mime_type.substring(0, separator + 1) + "*";
+	    wildcard_result = (Map)fallback_hash.get(type);
+
+	    if (wildcard_result != null) { // damn, we have to merge!!!
+		if (search_result != null)
+		    search_result =
+			mergeResults(search_result, wildcard_result);
+		else
+		    search_result = wildcard_result;
+	    }
+	}
+	return search_result;
+    }
+
+    /**
+     * Return all the MIME types known to this mailcap file.
+     *
+     * @return	a String array of the MIME types
+     */
+    public String[] getMimeTypes() {
+	Set types = new HashSet(type_hash.keySet());
+	types.addAll(fallback_hash.keySet());
+	types.addAll(native_commands.keySet());
+	String[] mts = new String[types.size()];
+	mts = (String[])types.toArray(mts);
+	return mts;
+    }
+
+    /**
+     * Return all the native comands for the given MIME type.
+     *
+     * @param	mime_type	the MIME type
+     * @return	a String array of the commands
+     */
+    public String[] getNativeCommands(String mime_type) {
+	String[] cmds = null;
+	List v =
+	    (List)native_commands.get(mime_type.toLowerCase(Locale.ENGLISH));
+	if (v != null) {
+	    cmds = new String[v.size()];
+	    cmds = (String[])v.toArray(cmds);
+	}
+	return cmds;
+    }
+
+    /**
+     * Merge the first hash into the second.
+     * This merge will only effect the hashtable that is
+     * returned, we don't want to touch the one passed in since
+     * its integrity must be maintained.
+     */
+    private Map mergeResults(Map first, Map second) {
+	Iterator verb_enum = second.keySet().iterator();
+	Map clonedHash = new HashMap(first);
+
+	// iterate through the verbs in the second map
+	while (verb_enum.hasNext()) {
+	    String verb = (String)verb_enum.next();
+	    List cmdVector = (List)clonedHash.get(verb);
+	    if (cmdVector == null) {
+		clonedHash.put(verb, second.get(verb));
+	    } else {
+		// merge the two
+		List oldV = (List)second.get(verb);
+		cmdVector = new ArrayList(cmdVector);
+		cmdVector.addAll(oldV);
+		clonedHash.put(verb, cmdVector);
+	    }
+	}
+	return clonedHash;
+    }
+
+    /**
+     * appendToMailcap: Append to this Mailcap DB, use the mailcap
+     * format:
+     * Comment == "# <i>comment string</i>"
+     * Entry == "mimetype;        javabeanclass"
+     *
+     * Example:
+     * # this is a comment
+     * image/gif       jaf.viewers.ImageViewer
+     *
+     * @param	mail_cap	the mailcap string
+     */
+    public void appendToMailcap(String mail_cap) {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("appendToMailcap: " + mail_cap);
+	try {
+	    parse(new StringReader(mail_cap));
+	} catch (IOException ex) {
+	    // can't happen
+	}
+    }
+
+    /**
+     * parse file into a hash table of MC Type Entry Obj
+     */
+    private void parse(Reader reader) throws IOException {
+	BufferedReader buf_reader = new BufferedReader(reader);
+	String line = null;
+	String continued = null;
+
+	while ((line = buf_reader.readLine()) != null) {
+	    //    LogSupport.log("parsing line: " + line);
+
+	    line = line.trim();
+
+	    try {
+		if (line.charAt(0) == '#')
+		    continue;
+		if (line.charAt(line.length() - 1) == '\\') {
+		    if (continued != null)
+			continued += line.substring(0, line.length() - 1);
+		    else
+			continued = line.substring(0, line.length() - 1);
+		} else if (continued != null) {
+		    // handle the two strings
+		    continued = continued + line;
+		    //	LogSupport.log("parse: " + continued);
+		    try {
+			parseLine(continued);
+		    } catch (MailcapParseException e) {
+			//e.printStackTrace();
+		    }
+		    continued = null;
+		}
+		else {
+		    //	LogSupport.log("parse: " + line);
+		    try {
+			parseLine(line);
+			// LogSupport.log("hash.size = " + type_hash.size());
+		    } catch (MailcapParseException e) {
+			//e.printStackTrace();
+		    }
+		}
+	    } catch (StringIndexOutOfBoundsException e) {}
+	}
+    }
+
+    /**
+     *	A routine to parse individual entries in a Mailcap file.
+     *
+     *	Note that this routine does not handle line continuations.
+     *	They should have been handled prior to calling this routine.
+     *
+     * @param	mailcapEntry	the mailcap entry
+     * @throws	MailcapParseException	for parse errors
+     * @throws	IOException	for I/O errors
+     */
+    protected void parseLine(String mailcapEntry)
+				throws MailcapParseException, IOException {
+	MailcapTokenizer tokenizer = new MailcapTokenizer(mailcapEntry);
+	tokenizer.setIsAutoquoting(false);
+
+	if (LogSupport.isLoggable())
+	    LogSupport.log("parse: " + mailcapEntry);
+	//	parse the primary type
+	int currentToken = tokenizer.nextToken();
+	if (currentToken != MailcapTokenizer.STRING_TOKEN) {
+	    reportParseError(MailcapTokenizer.STRING_TOKEN, currentToken,
+					tokenizer.getCurrentTokenValue());
+	}
+	String primaryType =
+	    tokenizer.getCurrentTokenValue().toLowerCase(Locale.ENGLISH);
+	String subType = "*";
+
+	//	parse the '/' between primary and sub
+	//	if it's not present that's ok, we just don't have a subtype
+	currentToken = tokenizer.nextToken();
+	if ((currentToken != MailcapTokenizer.SLASH_TOKEN) &&
+			(currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
+	    reportParseError(MailcapTokenizer.SLASH_TOKEN,
+				MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
+				tokenizer.getCurrentTokenValue());
+	}
+
+	//	only need to look for a sub type if we got a '/'
+	if (currentToken == MailcapTokenizer.SLASH_TOKEN) {
+	    //	parse the sub type
+	    currentToken = tokenizer.nextToken();
+	    if (currentToken != MailcapTokenizer.STRING_TOKEN) {
+		reportParseError(MailcapTokenizer.STRING_TOKEN,
+			    currentToken, tokenizer.getCurrentTokenValue());
+	    }
+	    subType =
+		tokenizer.getCurrentTokenValue().toLowerCase(Locale.ENGLISH);
+
+	    //	get the next token to simplify the next step
+	    currentToken = tokenizer.nextToken();
+	}
+
+	String mimeType = primaryType + "/" + subType;
+
+	if (LogSupport.isLoggable())
+	    LogSupport.log("  Type: " + mimeType);
+
+	//	now setup the commands hashtable
+	Map commands = new LinkedHashMap();	// keep commands in order found
+
+	//	parse the ';' that separates the type from the parameters
+	if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
+	    reportParseError(MailcapTokenizer.SEMICOLON_TOKEN,
+			    currentToken, tokenizer.getCurrentTokenValue());
+	}
+	//	eat it
+
+	//	parse the required view command
+	tokenizer.setIsAutoquoting(true);
+	currentToken = tokenizer.nextToken();
+	tokenizer.setIsAutoquoting(false);
+	if ((currentToken != MailcapTokenizer.STRING_TOKEN) &&
+		    (currentToken != MailcapTokenizer.SEMICOLON_TOKEN)) {
+	    reportParseError(MailcapTokenizer.STRING_TOKEN,
+			    MailcapTokenizer.SEMICOLON_TOKEN, currentToken,
+			    tokenizer.getCurrentTokenValue());
+	}
+
+	if (currentToken == MailcapTokenizer.STRING_TOKEN) {
+	    // have a native comand, save the entire mailcap entry
+	    //String nativeCommand = tokenizer.getCurrentTokenValue();
+	    List v = (List)native_commands.get(mimeType);
+	    if (v == null) {
+		v = new ArrayList();
+		v.add(mailcapEntry);
+		native_commands.put(mimeType, v);
+	    } else {
+		// XXX - check for duplicates?
+		v.add(mailcapEntry);
+	    }
+	}
+
+	//	only have to get the next token if the current one isn't a ';'
+	if (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) {
+	    currentToken = tokenizer.nextToken();
+	}
+
+	// look for a ';' which will indicate whether
+	// a parameter list is present or not
+	if (currentToken == MailcapTokenizer.SEMICOLON_TOKEN) {
+	    boolean isFallback = false;
+	    do {
+		//	eat the ';'
+
+		//	parse the parameter name
+		currentToken = tokenizer.nextToken();
+		if (currentToken != MailcapTokenizer.STRING_TOKEN) {
+		    reportParseError(MailcapTokenizer.STRING_TOKEN,
+			    currentToken, tokenizer.getCurrentTokenValue());
+		}
+		String paramName = tokenizer.getCurrentTokenValue().
+						toLowerCase(Locale.ENGLISH);
+
+		//	parse the '=' which separates the name from the value
+		currentToken = tokenizer.nextToken();
+		if ((currentToken != MailcapTokenizer.EQUALS_TOKEN) &&
+		    (currentToken != MailcapTokenizer.SEMICOLON_TOKEN) &&
+		    (currentToken != MailcapTokenizer.EOI_TOKEN)) {
+		    reportParseError(MailcapTokenizer.EQUALS_TOKEN,
+			    MailcapTokenizer.SEMICOLON_TOKEN,
+			    MailcapTokenizer.EOI_TOKEN,
+			    currentToken, tokenizer.getCurrentTokenValue());
+		}
+
+		//	we only have a useful command if it is named
+		if (currentToken == MailcapTokenizer.EQUALS_TOKEN) {
+		    //	eat it
+
+		    //	parse the parameter value (which is autoquoted)
+		    tokenizer.setIsAutoquoting(true);
+		    currentToken = tokenizer.nextToken();
+		    tokenizer.setIsAutoquoting(false);
+		    if (currentToken != MailcapTokenizer.STRING_TOKEN) {
+			reportParseError(MailcapTokenizer.STRING_TOKEN,
+			currentToken, tokenizer.getCurrentTokenValue());
+		    }
+		    String paramValue =
+				tokenizer.getCurrentTokenValue();
+
+		    // add the class to the list iff it is one we care about
+		    if (paramName.startsWith("x-java-")) {
+			String commandName = paramName.substring(7);
+			//	7 == "x-java-".length
+
+			if (commandName.equals("fallback-entry") &&
+			    paramValue.equalsIgnoreCase("true")) {
+			    isFallback = true;
+			} else {
+
+			    //	setup the class entry list
+			    if (LogSupport.isLoggable())
+				LogSupport.log("    Command: " + commandName +
+						    ", Class: " + paramValue);
+			    List classes = (List)commands.get(commandName);
+			    if (classes == null) {
+				classes = new ArrayList();
+				commands.put(commandName, classes);
+			    }
+			    if (addReverse)
+				classes.add(0, paramValue);
+			    else
+				classes.add(paramValue);
+			}
+		    }
+
+		    //	set up the next iteration
+		    currentToken = tokenizer.nextToken();
+		}
+	    } while (currentToken == MailcapTokenizer.SEMICOLON_TOKEN);
+
+	    Map masterHash = isFallback ? fallback_hash : type_hash;
+	    Map curcommands =
+		(Map)masterHash.get(mimeType);
+	    if (curcommands == null) {
+		masterHash.put(mimeType, commands);
+	    } else {
+		if (LogSupport.isLoggable())
+		    LogSupport.log("Merging commands for type " + mimeType);
+		// have to merge current and new commands
+		// first, merge list of classes for commands already known
+		Iterator cn = curcommands.keySet().iterator();
+		while (cn.hasNext()) {
+		    String cmdName = (String)cn.next();
+		    List ccv = (List)curcommands.get(cmdName);
+		    List cv = (List)commands.get(cmdName);
+		    if (cv == null)
+			continue;
+		    // add everything in cv to ccv, if it's not already there
+		    Iterator cvn = cv.iterator();
+		    while (cvn.hasNext()) {
+			String clazz = (String)cvn.next();
+			if (!ccv.contains(clazz))
+			    if (addReverse)
+				ccv.add(0, clazz);
+			    else
+				ccv.add(clazz);
+		    }
+		}
+		// now, add commands not previously known
+		cn = commands.keySet().iterator();
+		while (cn.hasNext()) {
+		    String cmdName = (String)cn.next();
+		    if (curcommands.containsKey(cmdName))
+			continue;
+		    List cv = (List)commands.get(cmdName);
+		    curcommands.put(cmdName, cv);
+		}
+	    }
+	} else if (currentToken != MailcapTokenizer.EOI_TOKEN) {
+	    reportParseError(MailcapTokenizer.EOI_TOKEN,
+		MailcapTokenizer.SEMICOLON_TOKEN,
+		currentToken, tokenizer.getCurrentTokenValue());
+	}
+     }
+
+     protected static void reportParseError(int expectedToken, int actualToken,
+		String actualTokenValue) throws MailcapParseException {
+     	throw new MailcapParseException("Encountered a " +
+		MailcapTokenizer.nameForToken(actualToken) + " token (" +
+		actualTokenValue + ") while expecting a " +
+		MailcapTokenizer.nameForToken(expectedToken) + " token.");
+     }
+
+     protected static void reportParseError(int expectedToken,
+	int otherExpectedToken, int actualToken, String actualTokenValue)
+					throws MailcapParseException {
+     	throw new MailcapParseException("Encountered a " +
+		MailcapTokenizer.nameForToken(actualToken) + " token (" +
+		actualTokenValue + ") while expecting a " +
+		MailcapTokenizer.nameForToken(expectedToken) + " or a " +
+		MailcapTokenizer.nameForToken(otherExpectedToken) + " token.");
+     }
+
+     protected static void reportParseError(int expectedToken,
+	    int otherExpectedToken, int anotherExpectedToken, int actualToken,
+	    String actualTokenValue) throws MailcapParseException {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("PARSE ERROR: " + "Encountered a " +
+		MailcapTokenizer.nameForToken(actualToken) + " token (" +
+		actualTokenValue + ") while expecting a " +
+		MailcapTokenizer.nameForToken(expectedToken) + ", a " +
+		MailcapTokenizer.nameForToken(otherExpectedToken) + ", or a " +
+		MailcapTokenizer.nameForToken(anotherExpectedToken) + " token.");
+     	throw new MailcapParseException("Encountered a " +
+		MailcapTokenizer.nameForToken(actualToken) + " token (" +
+		actualTokenValue + ") while expecting a " +
+		MailcapTokenizer.nameForToken(expectedToken) + ", a " +
+		MailcapTokenizer.nameForToken(otherExpectedToken) + ", or a " +
+		MailcapTokenizer.nameForToken(anotherExpectedToken) + " token.");
+     }
+
+     /** for debugging
+     public static void	main(String[] args) throws Exception {
+     	Map masterHash = new HashMap();
+     	for (int i = 0; i < args.length; ++i) {
+	    System.out.println("Entry " + i + ": " + args[i]);
+	    parseLine(args[i], masterHash);
+     	}
+
+     	Enumeration types = masterHash.keys();
+     	while (types.hasMoreElements()) {
+	    String key = (String)types.nextElement();
+	    System.out.println("MIME Type: " + key);
+
+	    Map commandHash = (Map)masterHash.get(key);
+	    Enumeration commands = commandHash.keys();
+	    while (commands.hasMoreElements()) {
+		String command = (String)commands.nextElement();
+		System.out.println("    Command: " + command);
+
+		Vector classes = (Vector)commandHash.get(command);
+		for (int i = 0; i < classes.size(); ++i) {
+			System.out.println("        Class: " +
+					    (String)classes.elementAt(i));
+		}
+	    }
+
+	    System.out.println("");
+	}
+    }
+    */
+}
diff --git a/activation/src/main/java/com/sun/activation/registries/MailcapParseException.java b/activation/src/main/java/com/sun/activation/registries/MailcapParseException.java
new file mode 100644
index 0000000..754c405
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/MailcapParseException.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package	com.sun.activation.registries;
+
+/**
+ *	A class to encapsulate Mailcap parsing related exceptions
+ */
+public class MailcapParseException extends Exception {
+
+    public MailcapParseException() {
+	super();
+    }
+
+    public MailcapParseException(String inInfo) {
+	super(inInfo);
+    }
+}
diff --git a/activation/src/main/java/com/sun/activation/registries/MailcapTokenizer.java b/activation/src/main/java/com/sun/activation/registries/MailcapTokenizer.java
new file mode 100644
index 0000000..23728a5
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/MailcapTokenizer.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package	com.sun.activation.registries;
+
+/**
+ *	A tokenizer for strings in the form of "foo/bar; prop1=val1; ... ".
+ *	Useful for parsing MIME content types.
+ */
+public class MailcapTokenizer {
+
+    public static final int UNKNOWN_TOKEN = 0;
+    public static final int START_TOKEN = 1;
+    public static final int STRING_TOKEN = 2;
+    public static final int EOI_TOKEN = 5;
+    public static final int SLASH_TOKEN = '/';
+    public static final int SEMICOLON_TOKEN = ';';
+    public static final int EQUALS_TOKEN = '=';
+
+    /**
+     *  Constructor
+     *
+     *  @param  inputString the string to tokenize
+     */
+    public MailcapTokenizer(String inputString) {
+	data = inputString;
+	dataIndex = 0;
+	dataLength = inputString.length();
+
+	currentToken = START_TOKEN;
+	currentTokenValue = "";
+
+	isAutoquoting = false;
+	autoquoteChar = ';';
+    }
+
+    /**
+     *  Set whether auto-quoting is on or off.
+     *
+     *  Auto-quoting means that all characters after the first
+     *  non-whitespace, non-control character up to the auto-quote
+     *  terminator character or EOI (minus any whitespace immediatley
+     *  preceeding it) is considered a token.
+     *
+     *  This is required for handling command strings in a mailcap entry.
+     *
+     *  @param	value	on or off
+     */
+    public void setIsAutoquoting(boolean value) {
+	isAutoquoting = value;
+    }
+
+    /**
+     *  Retrieve current token.
+     *
+     *  @return    The current token value
+     */
+    public int getCurrentToken() {
+	return currentToken;
+    }
+
+    /*
+     *  Get a String that describes the given token.
+     */
+    public static String nameForToken(int token) {
+	String name = "really unknown";
+
+	switch(token) {
+	    case UNKNOWN_TOKEN:
+		name = "unknown";
+		break;
+	    case START_TOKEN:
+		name = "start";
+		break;
+	    case STRING_TOKEN:
+		name = "string";
+		break;
+	    case EOI_TOKEN:
+		name = "EOI";
+		break;
+	    case SLASH_TOKEN:
+		name = "'/'";
+		break;
+	    case SEMICOLON_TOKEN:
+		name = "';'";
+		break;
+	    case EQUALS_TOKEN:
+		name = "'='";
+		break;
+	}
+
+	return name;
+    }
+
+    /*
+     *  Retrieve current token value.
+     *
+     *  @returns    A String containing the current token value
+     */
+    public String getCurrentTokenValue() {
+	return currentTokenValue;
+    }
+
+    /*
+     *  Process the next token.
+     *
+     *  @returns    the next token
+     */
+    public int nextToken() {
+	if (dataIndex < dataLength) {
+	    //  skip white space
+	    while ((dataIndex < dataLength) &&
+		    (isWhiteSpaceChar(data.charAt(dataIndex)))) {
+		++dataIndex;
+	    }
+
+	    if (dataIndex < dataLength) {
+		//  examine the current character and see what kind of token we have
+		char c = data.charAt(dataIndex);
+		if (isAutoquoting) {
+		    if (c == ';' || c == '=') {
+			currentToken = c;
+			currentTokenValue = new Character(c).toString();
+			++dataIndex;
+		    } else {
+			processAutoquoteToken();
+		    }
+		} else {
+		    if (isStringTokenChar(c)) {
+			processStringToken();
+		    } else if ((c == '/') || (c == ';') || (c == '=')) {
+			currentToken = c;
+			currentTokenValue = new Character(c).toString();
+			++dataIndex;
+		    } else {
+			currentToken = UNKNOWN_TOKEN;
+			currentTokenValue = new Character(c).toString();
+			++dataIndex;
+		    }
+		}
+	    } else {
+		currentToken = EOI_TOKEN;
+		currentTokenValue = null;
+	    }
+	} else {
+	    currentToken = EOI_TOKEN;
+	    currentTokenValue = null;
+	}
+
+	return currentToken;
+    }
+
+    private void processStringToken() {
+	//  capture the initial index
+	int initialIndex = dataIndex;
+
+	//  skip to 1st non string token character
+	while ((dataIndex < dataLength) &&
+		isStringTokenChar(data.charAt(dataIndex))) {
+	    ++dataIndex;
+	}
+
+	currentToken = STRING_TOKEN;
+	currentTokenValue = data.substring(initialIndex, dataIndex);
+    }
+
+    private void processAutoquoteToken() {
+	//  capture the initial index
+	int initialIndex = dataIndex;
+
+	//  now skip to the 1st non-escaped autoquote termination character
+	//  XXX - doesn't actually consider escaping
+	boolean foundTerminator = false;
+	while ((dataIndex < dataLength) && !foundTerminator) {
+	    char c = data.charAt(dataIndex);
+	    if (c != autoquoteChar) {
+		++dataIndex;
+	    } else {
+		foundTerminator = true;
+	    }
+	}
+
+	currentToken = STRING_TOKEN;
+	currentTokenValue =
+	    fixEscapeSequences(data.substring(initialIndex, dataIndex));
+    }
+
+    private static boolean isSpecialChar(char c) {
+	boolean lAnswer = false;
+
+	switch(c) {
+	    case '(':
+	    case ')':
+	    case '<':
+	    case '>':
+	    case '@':
+	    case ',':
+	    case ';':
+	    case ':':
+	    case '\\':
+	    case '"':
+	    case '/':
+	    case '[':
+	    case ']':
+	    case '?':
+	    case '=':
+		lAnswer = true;
+		break;
+	}
+
+	return lAnswer;
+    }
+
+    private static boolean isControlChar(char c) {
+	return Character.isISOControl(c);
+    }
+
+    private static boolean isWhiteSpaceChar(char c) {
+	return Character.isWhitespace(c);
+    }
+
+    private static boolean isStringTokenChar(char c) {
+	return !isSpecialChar(c) && !isControlChar(c) && !isWhiteSpaceChar(c);
+    }
+
+    private static String fixEscapeSequences(String inputString) {
+	int inputLength = inputString.length();
+	StringBuffer buffer = new StringBuffer();
+	buffer.ensureCapacity(inputLength);
+
+	for (int i = 0; i < inputLength; ++i) {
+	    char currentChar = inputString.charAt(i);
+	    if (currentChar != '\\') {
+		buffer.append(currentChar);
+	    } else {
+		if (i < inputLength - 1) {
+		    char nextChar = inputString.charAt(i + 1);
+		    buffer.append(nextChar);
+
+		    //  force a skip over the next character too
+		    ++i;
+		} else {
+		    buffer.append(currentChar);
+		}
+	    }
+	}
+
+	return buffer.toString();
+    }
+
+    private String  data;
+    private int     dataIndex;
+    private int     dataLength;
+    private int     currentToken;
+    private String  currentTokenValue;
+    private boolean isAutoquoting;
+    private char    autoquoteChar;
+
+    /*
+    public static void main(String[] args) {
+	for (int i = 0; i < args.length; ++i) {
+	    MailcapTokenizer tokenizer = new MailcapTokenizer(args[i]);
+
+	    System.out.println("Original: |" + args[i] + "|");
+
+	    int currentToken = tokenizer.nextToken();
+	    while (currentToken != EOI_TOKEN) {
+		switch(currentToken) {
+		    case UNKNOWN_TOKEN:
+			System.out.println("  Unknown Token:           |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case START_TOKEN:
+			System.out.println("  Start Token:             |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case STRING_TOKEN:
+			System.out.println("  String Token:            |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case EOI_TOKEN:
+			System.out.println("  EOI Token:               |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case SLASH_TOKEN:
+			System.out.println("  Slash Token:             |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case SEMICOLON_TOKEN:
+			System.out.println("  Semicolon Token:         |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    case EQUALS_TOKEN:
+			System.out.println("  Equals Token:            |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		    default:
+			System.out.println("  Really Unknown Token:    |" + tokenizer.getCurrentTokenValue() + "|");
+			break;
+		}
+
+		currentToken = tokenizer.nextToken();
+	    }
+
+	    System.out.println("");
+	}
+    }
+    */
+}
diff --git a/activation/src/main/java/com/sun/activation/registries/MimeTypeEntry.java b/activation/src/main/java/com/sun/activation/registries/MimeTypeEntry.java
new file mode 100644
index 0000000..3582f77
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/MimeTypeEntry.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.registries;
+
+import java.lang.*;
+
+public class MimeTypeEntry {
+    private String type;
+    private String extension;
+
+    public MimeTypeEntry(String mime_type, String file_ext) {
+	type = mime_type;
+	extension = file_ext;
+    }
+
+    public String getMIMEType() {
+	return type;
+    }
+
+    public String getFileExtension() {
+	return extension;
+    }
+
+    public String toString() {
+	return "MIMETypeEntry: " + type + ", " + extension;
+    }
+}
diff --git a/activation/src/main/java/com/sun/activation/registries/MimeTypeFile.java b/activation/src/main/java/com/sun/activation/registries/MimeTypeFile.java
new file mode 100644
index 0000000..b2c89f0
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/registries/MimeTypeFile.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.registries;
+
+import java.io.*;
+import java.util.*;
+
+public class MimeTypeFile {
+    private String fname = null;
+    private Hashtable type_hash = new Hashtable();
+
+    /**
+     * The construtor that takes a filename as an argument.
+     *
+     * @param new_fname The file name of the mime types file.
+     * @throws	IOException	for I/O errors
+     */
+    public MimeTypeFile(String new_fname) throws IOException {
+	File mime_file = null;
+	FileReader fr = null;
+
+	fname = new_fname; // remember the file name
+
+	mime_file = new File(fname); // get a file object
+
+	fr = new FileReader(mime_file);
+
+	try {
+	    parse(new BufferedReader(fr));
+	} finally {
+	    try {
+		fr.close(); // close it
+	    } catch (IOException e) {
+		// ignore it
+	    }
+	}
+    }
+
+    public MimeTypeFile(InputStream is) throws IOException {
+	parse(new BufferedReader(new InputStreamReader(is, "iso-8859-1")));
+    }
+
+    /**
+     * Creates an empty DB.
+     */
+    public MimeTypeFile() {
+    }
+
+    /**
+     * get the MimeTypeEntry based on the file extension
+     *
+     * @param	file_ext	the file extension
+     * @return	the MimeTypeEntry
+     */
+    public MimeTypeEntry getMimeTypeEntry(String file_ext) {
+	return (MimeTypeEntry)type_hash.get((Object)file_ext);
+    }
+
+    /**
+     * Get the MIME type string corresponding to the file extension.
+     *
+     * @param	file_ext	the file extension
+     * @return	the MIME type string
+     */
+    public String getMIMETypeString(String file_ext) {
+	MimeTypeEntry entry = this.getMimeTypeEntry(file_ext);
+
+	if (entry != null)
+	    return entry.getMIMEType();
+	else
+	    return null;
+    }
+
+    /**
+     * Appends string of entries to the types registry, must be valid
+     * .mime.types format.
+     * A mime.types entry is one of two forms:
+     *
+     *	type/subtype	ext1 ext2 ...
+     * or
+     *	type=type/subtype desc="description of type" exts=ext1,ext2,...
+     *
+     * Example:
+     * # this is a test
+     * audio/basic            au
+     * text/plain             txt text
+     * type=application/postscript exts=ps,eps
+     *
+     * @param mime_types	the mime.types string
+     */
+    public void appendToRegistry(String mime_types) {
+	try {
+	    parse(new BufferedReader(new StringReader(mime_types)));
+	} catch (IOException ex) {
+	    // can't happen
+	}
+    }
+
+    /**
+     * Parse a stream of mime.types entries.
+     */
+    private void parse(BufferedReader buf_reader) throws IOException {
+	String line = null, prev = null;
+
+	while ((line = buf_reader.readLine()) != null) {
+	    if (prev == null)
+		prev = line;
+	    else
+		prev += line;
+	    int end = prev.length();
+	    if (prev.length() > 0 && prev.charAt(end - 1) == '\\') {
+		prev = prev.substring(0, end - 1);
+		continue;
+	    }
+	    this.parseEntry(prev);
+	    prev = null;
+	}
+	if (prev != null)
+	    this.parseEntry(prev);
+    }
+
+    /**
+     * Parse single mime.types entry.
+     */
+    private void parseEntry(String line) {
+	String mime_type = null;
+	String file_ext = null;
+	line = line.trim();
+
+	if (line.length() == 0) // empty line...
+	    return; // BAIL!
+
+	// check to see if this is a comment line?
+	if (line.charAt(0) == '#')
+	    return; // then we are done!
+
+	// is it a new format line or old format?
+	if (line.indexOf('=') > 0) {
+	    // new format
+	    LineTokenizer lt = new LineTokenizer(line);
+	    while (lt.hasMoreTokens()) {
+		String name = lt.nextToken();
+		String value = null;
+		if (lt.hasMoreTokens() && lt.nextToken().equals("=") &&
+							lt.hasMoreTokens())
+		    value = lt.nextToken();
+		if (value == null) {
+		    if (LogSupport.isLoggable())
+			LogSupport.log("Bad .mime.types entry: " + line);
+		    return;
+		}
+		if (name.equals("type"))
+		    mime_type = value;
+		else if (name.equals("exts")) {
+		    StringTokenizer st = new StringTokenizer(value, ",");
+		    while (st.hasMoreTokens()) {
+			file_ext = st.nextToken();
+			MimeTypeEntry entry =
+				new MimeTypeEntry(mime_type, file_ext);
+			type_hash.put(file_ext, entry);
+			if (LogSupport.isLoggable())
+			    LogSupport.log("Added: " + entry.toString());
+		    }
+		}
+	    }
+	} else {
+	    // old format
+	    // count the tokens
+	    StringTokenizer strtok = new StringTokenizer(line);
+	    int num_tok = strtok.countTokens();
+
+	    if (num_tok == 0) // empty line
+		return;
+
+	    mime_type = strtok.nextToken(); // get the MIME type
+
+	    while (strtok.hasMoreTokens()) {
+		MimeTypeEntry entry = null;
+
+		file_ext = strtok.nextToken();
+		entry = new MimeTypeEntry(mime_type, file_ext);
+		type_hash.put(file_ext, entry);
+		if (LogSupport.isLoggable())
+		    LogSupport.log("Added: " + entry.toString());
+	    }
+	}
+    }
+
+    // for debugging
+    /*
+    public static void main(String[] argv) throws Exception {
+	MimeTypeFile mf = new MimeTypeFile(argv[0]);
+	System.out.println("ext " + argv[1] + " type " +
+						mf.getMIMETypeString(argv[1]));
+	System.exit(0);
+    }
+    */
+}
+
+class LineTokenizer {
+    private int currentPosition;
+    private int maxPosition;
+    private String str;
+    private Vector stack = new Vector();
+    private static final String singles = "=";	// single character tokens
+
+    /**
+     * Constructs a tokenizer for the specified string.
+     * <p>
+     *
+     * @param   str            a string to be parsed.
+     */
+    public LineTokenizer(String str) {
+	currentPosition = 0;
+	this.str = str;
+	maxPosition = str.length();
+    }
+
+    /**
+     * Skips white space.
+     */
+    private void skipWhiteSpace() {
+	while ((currentPosition < maxPosition) &&
+	       Character.isWhitespace(str.charAt(currentPosition))) {
+	    currentPosition++;
+	}
+    }
+
+    /**
+     * Tests if there are more tokens available from this tokenizer's string.
+     *
+     * @return  <code>true</code> if there are more tokens available from this
+     *          tokenizer's string; <code>false</code> otherwise.
+     */
+    public boolean hasMoreTokens() {
+	if (stack.size() > 0)
+	    return true;
+	skipWhiteSpace();
+	return (currentPosition < maxPosition);
+    }
+
+    /**
+     * Returns the next token from this tokenizer.
+     *
+     * @return     the next token from this tokenizer.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     */
+    public String nextToken() {
+	int size = stack.size();
+	if (size > 0) {
+	    String t = (String)stack.elementAt(size - 1);
+	    stack.removeElementAt(size - 1);
+	    return t;
+	}
+	skipWhiteSpace();
+
+	if (currentPosition >= maxPosition) {
+	    throw new NoSuchElementException();
+	}
+
+	int start = currentPosition;
+	char c = str.charAt(start);
+	if (c == '"') {
+	    currentPosition++;
+	    boolean filter = false;
+	    while (currentPosition < maxPosition) {
+		c = str.charAt(currentPosition++);
+		if (c == '\\') {
+		    currentPosition++;
+		    filter = true;
+		} else if (c == '"') {
+		    String s;
+
+		    if (filter) {
+			StringBuffer sb = new StringBuffer();
+			for (int i = start + 1; i < currentPosition - 1; i++) {
+			    c = str.charAt(i);
+			    if (c != '\\')
+				sb.append(c);
+			}
+			s = sb.toString();
+		    } else
+			s = str.substring(start + 1, currentPosition - 1);
+		    return s;
+		}
+	    }
+	} else if (singles.indexOf(c) >= 0) {
+	    currentPosition++;
+	} else {
+	    while ((currentPosition < maxPosition) && 
+		   singles.indexOf(str.charAt(currentPosition)) < 0 &&
+		   !Character.isWhitespace(str.charAt(currentPosition))) {
+		currentPosition++;
+	    }
+	}
+	return str.substring(start, currentPosition);
+    }
+
+    public void pushToken(String token) {
+	stack.addElement(token);
+    }
+}
diff --git a/activation/src/main/java/com/sun/activation/viewers/ImageViewer.java b/activation/src/main/java/com/sun/activation/viewers/ImageViewer.java
new file mode 100644
index 0000000..b7b2294
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/viewers/ImageViewer.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.viewers;
+
+import java.awt.*;
+import java.io.*;
+import java.beans.*;
+import javax.activation.*;
+
+public class ImageViewer extends Panel implements CommandObject {
+    // UI Vars...
+    private ImageViewerCanvas canvas = null;
+    
+    // File Vars
+    //    private InputStream data_ins = null;
+    private Image image = null;
+    private DataHandler _dh = null;
+    
+    private boolean DEBUG = false;
+    /**
+     * Constructor
+     */
+    public ImageViewer(){
+	
+	// create the ImageViewerCanvas
+	canvas = new ImageViewerCanvas();
+	add(canvas);
+    }
+    /**
+     * Set the DataHandler for this CommandObject
+     * @param dh the DataHandler
+     */
+    public void setCommandContext(String verb, DataHandler dh)	throws IOException{
+	_dh = dh;
+	this.setInputStream( _dh.getInputStream() );
+    }
+    //--------------------------------------------------------------------
+    
+    /**
+     * Set the data stream, component to assume it is ready to
+     * be read.
+     */
+    private void setInputStream(InputStream ins) throws IOException {
+	MediaTracker mt = new MediaTracker(this);
+	int bytes_read = 0;
+	byte data[] = new byte[1024];
+	ByteArrayOutputStream baos = new ByteArrayOutputStream();
+	
+	while((bytes_read = ins.read(data)) >0)
+	    baos.write(data, 0, bytes_read);
+	ins.close();
+	
+	// convert the buffer into an image
+	image = getToolkit().createImage(baos.toByteArray());
+	
+	mt.addImage(image, 0);
+	
+	try {
+	    mt.waitForID(0);
+	    mt.waitForAll();
+	    if(mt.statusID(0, true ) != MediaTracker.COMPLETE){
+		System.out.println("Error occured in image loading = " +
+				   mt.getErrorsID(0));
+		
+	    }
+	    
+	}
+	catch(InterruptedException e) {
+	    throw new IOException("Error reading image data");
+	}
+	
+	canvas.setImage(image);
+	if(DEBUG)
+	    System.out.println("calling invalidate");
+	
+    }
+    //--------------------------------------------------------------------
+    public void addNotify(){
+	super.addNotify(); // call the real one first...
+	this.invalidate();
+	this.validate();
+	this.doLayout();
+    }
+    //--------------------------------------------------------------------
+    public Dimension getPreferredSize(){
+	return canvas.getPreferredSize();
+    }
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/activation/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java b/activation/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java
new file mode 100644
index 0000000..d85e9e2
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.viewers;
+
+import java.awt.*;
+
+public class ImageViewerCanvas extends Canvas
+{
+  private Image canvas_image = null;
+  
+  /**
+   * The constructor
+   */
+  public ImageViewerCanvas()
+    {
+	
+    }
+
+  /**
+   * set the image
+   * @param new_image the image
+   */
+  public void setImage(Image new_image)
+    {
+      canvas_image = new_image;
+      this.invalidate();
+      this.repaint();
+    }
+  
+  /**
+   * getPreferredSize
+   */
+  public Dimension getPreferredSize()
+    {
+      Dimension d = null;
+      
+      if(canvas_image == null)
+	{
+	  d = new Dimension(200, 200);
+	}
+      else
+	d = new Dimension(canvas_image.getWidth(this), 
+			  canvas_image.getHeight(this));
+
+      return d;
+    }
+  /**
+   * paint method
+   */
+  public void paint(Graphics g)
+    {
+
+      if(canvas_image != null)
+	g.drawImage(canvas_image, 0, 0, this);
+
+    }
+  
+}
diff --git a/activation/src/main/java/com/sun/activation/viewers/TextEditor.java b/activation/src/main/java/com/sun/activation/viewers/TextEditor.java
new file mode 100644
index 0000000..693461e
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/viewers/TextEditor.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.viewers;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.beans.*;
+import javax.activation.*;
+
+public class TextEditor extends Panel implements CommandObject,
+    ActionListener {
+	// UI Vars...
+    private TextArea text_area = null;
+    private GridBagLayout panel_gb = null;
+    private Panel button_panel = null;
+    private Button save_button = null;
+	// File Vars
+    private File text_file = null;
+    private String text_buffer = null;
+    private InputStream data_ins = null;
+    private FileInputStream fis = null;
+	
+    private DataHandler _dh = null;
+    private boolean DEBUG = false;
+	/**
+	 * Constructor
+	 */
+    public TextEditor() {
+	panel_gb = new GridBagLayout();
+	setLayout(panel_gb);
+	
+	button_panel = new Panel();
+	//	button_panel.setBackground(Color.white);
+	button_panel.setLayout( new FlowLayout() );
+	save_button = new Button("SAVE");
+	button_panel.add(save_button);
+	addGridComponent(this,
+			 button_panel,
+			 panel_gb,
+			 0,0,
+			 1,1,
+			 1,0);
+	
+	// create the text area
+	text_area = new TextArea("This is text",24, 80, 
+				 TextArea.SCROLLBARS_VERTICAL_ONLY );
+	//	text_area.setBackground(Color.lightGray);
+	text_area.setEditable( true );
+	
+	addGridComponent(this,
+			 text_area,
+			 panel_gb,
+			 0,1,
+			 1,2,
+			 1,1);
+	
+	// add listeners
+	save_button.addActionListener( this );
+	
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+	/**
+	 * adds a component to our gridbag layout
+	 */
+    private void addGridComponent(Container cont, 
+				  Component comp,
+				  GridBagLayout mygb,
+				  int gridx,
+				  int gridy, 
+				  int gridw,
+				  int gridh,
+				  int weightx,
+				  int weighty) { 
+	GridBagConstraints c = new GridBagConstraints(); 
+	c.gridx = gridx; 
+	c.gridy = gridy; 
+	c.gridwidth = gridw; 
+	c.gridheight = gridh; 
+	c.fill = GridBagConstraints.BOTH;
+	c.weighty = weighty;
+	c.weightx = weightx;
+	c.anchor =  GridBagConstraints.CENTER;
+	mygb.setConstraints(comp, c); 
+	cont.add(comp); 
+    }
+	
+  //--------------------------------------------------------------------
+    public void setCommandContext(String verb, DataHandler dh) throws IOException {
+	_dh = dh;
+	this.setInputStream( _dh.getInputStream() );
+
+    }
+  //--------------------------------------------------------------------
+
+  /**
+   * set the data stream, component to assume it is ready to
+   * be read.
+   *
+   * @param	ins	the data stream
+   * @throws	IOException	for I/O errors
+   */
+    public void setInputStream(InputStream ins) throws IOException {
+	
+	byte data[] = new byte[1024];
+	ByteArrayOutputStream baos = new ByteArrayOutputStream();
+	int bytes_read = 0;
+	// check that we can actually read
+	
+	while((bytes_read = ins.read(data)) >0)
+	    baos.write(data, 0, bytes_read);
+	ins.close();
+
+      
+	// convert the buffer into a string
+	// popuplate the buffer
+	text_buffer = baos.toString();
+
+	// place in the text area
+	text_area.setText(text_buffer);
+    }
+    ///////////////////////////////////////////////////////////////////////
+    private void performSaveOperation(){
+	OutputStream fos = null;
+	try {
+	    fos = _dh.getOutputStream();
+	} catch (Exception e) {}
+	
+	String buffer = text_area.getText();
+	
+	// make sure we got one
+	if(fos == null) {
+	    System.out.println("Invalid outputstream in TextEditor!");
+	    System.out.println("not saving!");
+	    return;
+	}
+	
+	try {
+	    fos.write( buffer.getBytes() );
+	    fos.flush(); // flush it!
+	    fos.close(); // close it!
+	} catch(IOException e)
+	    {
+		System.out.println("TextEditor Save Operation failed with: " + e);
+	    }
+	
+    }
+  //--------------------------------------------------------------------
+    public void addNotify() {
+	super.addNotify();
+	invalidate();
+    }
+  //--------------------------------------------------------------------
+    public Dimension getPreferredSize()	{
+	return text_area.getMinimumSize(24, 80);
+    }
+	/////////////////////////////////////////////////////////////////////
+	// for ActionListener
+    public void actionPerformed(ActionEvent evt){
+	if(evt.getSource() == save_button) { // save button pressed!
+	    
+	    // Save ourselves
+	    this.performSaveOperation();
+	}
+    }
+	
+}
diff --git a/activation/src/main/java/com/sun/activation/viewers/TextViewer.java b/activation/src/main/java/com/sun/activation/viewers/TextViewer.java
new file mode 100644
index 0000000..3093ff4
--- /dev/null
+++ b/activation/src/main/java/com/sun/activation/viewers/TextViewer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package com.sun.activation.viewers;
+
+import java.awt.*;
+import java.io.*;
+import java.beans.*;
+import javax.activation.*;
+
+public class TextViewer extends Panel implements CommandObject {
+    // UI Vars...
+    private TextArea text_area = null;
+    
+    // File Vars
+    private File text_file = null;
+    private String text_buffer = null;
+    
+    private DataHandler _dh = null;
+    private boolean DEBUG = false;
+    /**
+     * Constructor
+     */
+    public TextViewer() {
+	setLayout( new GridLayout(1,1));
+	// create the text area
+	text_area = new TextArea("", 24, 80, 
+				 TextArea.SCROLLBARS_VERTICAL_ONLY );
+	text_area.setEditable( false );
+	
+	add(text_area);
+    }
+    
+    //--------------------------------------------------------------------
+    public void setCommandContext(String verb, DataHandler dh) throws IOException {
+	_dh = dh;
+	this.setInputStream( _dh.getInputStream() );
+    }
+  //--------------------------------------------------------------------
+
+  /**
+   * set the data stream, component to assume it is ready to
+   * be read.
+   *
+   * @param	ins	the data stream
+   * @throws	IOException	for I/O errors
+   */
+  public void setInputStream(InputStream ins) throws IOException {
+      
+      int bytes_read = 0;
+      // check that we can actually read
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      byte data[] = new byte[1024];
+      
+      while((bytes_read = ins.read(data)) >0)
+	  baos.write(data, 0, bytes_read);
+      
+      ins.close();
+
+      // convert the buffer into a string
+      // popuplate the buffer
+      text_buffer = baos.toString();
+
+      // place in the text area
+      text_area.setText(text_buffer);
+
+    }
+  //--------------------------------------------------------------------
+    public void addNotify() {
+	super.addNotify();
+	invalidate();
+    }
+  //--------------------------------------------------------------------
+    public Dimension getPreferredSize()	{
+	return text_area.getMinimumSize(24, 80);
+    }
+
+}
+
+
+
+
+
+
diff --git a/activation/src/main/java/javax/activation/ActivationDataFlavor.java b/activation/src/main/java/javax/activation/ActivationDataFlavor.java
new file mode 100644
index 0000000..87f12a8
--- /dev/null
+++ b/activation/src/main/java/javax/activation/ActivationDataFlavor.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.awt.datatransfer.DataFlavor;
+import java.io.IOException;
+import javax.activation.MimeType;
+
+/**
+ * The ActivationDataFlavor class is a special subclass of
+ * <code>java.awt.datatransfer.DataFlavor</code>. It allows the JAF to
+ * set all three values stored by the DataFlavor class via a new
+ * constructor. It also contains improved MIME parsing in the <code>equals
+ * </code> method. Except for the improved parsing, its semantics are
+ * identical to that of the JDK's DataFlavor class.
+ */
+
+public class ActivationDataFlavor extends DataFlavor {
+
+    /*
+     * Raison d'etre:
+     *
+     * The DataFlavor class included in JDK 1.1 has several limitations
+     * including piss poor MIME type parsing, and the limitation of
+     * only supporting serialized objects and InputStreams as
+     * representation objects. This class 'fixes' that.
+     */
+
+    // I think for now I'll keep copies of all the variables and
+    // then later I may choose try to better coexist with the base
+    // class *sigh*
+    private String mimeType = null;
+    private MimeType mimeObject = null;
+    private String humanPresentableName = null;
+    private Class representationClass = null;
+
+    /**
+     * Construct a DataFlavor that represents an arbitrary
+     * Java object. This constructor is an extension of the
+     * JDK's DataFlavor in that it allows the explicit setting
+     * of all three DataFlavor attributes.
+     * <p>
+     * The returned DataFlavor will have the following characteristics:
+     * <p>
+     * representationClass = representationClass<br>
+     * mimeType            = mimeType<br>
+     * humanName           = humanName
+     * <p>
+     *
+     * @param representationClass the class used in this DataFlavor
+     * @param mimeType the MIME type of the data represented by this class
+     * @param humanPresentableName the human presentable name of the flavor
+     */
+    public ActivationDataFlavor(Class representationClass,
+		      String mimeType, String humanPresentableName) {
+	super(mimeType, humanPresentableName); // need to call super
+
+	// init private variables:
+	this.mimeType = mimeType;
+	this.humanPresentableName = humanPresentableName;
+	this.representationClass = representationClass;
+    }
+
+    /**
+     * Construct a DataFlavor that represents a MimeType.
+     * <p>
+     * The returned DataFlavor will have the following characteristics:
+     * <p>
+     * If the mimeType is "application/x-java-serialized-object;
+     * class=", the result is the same as calling new
+     * DataFlavor(Class.forName()) as above.
+     * <p>
+     * otherwise:
+     * <p>
+     * representationClass = InputStream<p>
+     * mimeType = mimeType<p>
+     *
+     * @param representationClass the class used in this DataFlavor
+     * @param humanPresentableName the human presentable name of the flavor
+     */
+    public ActivationDataFlavor(Class representationClass,
+				String humanPresentableName) {
+	super(representationClass, humanPresentableName);
+	this.mimeType = super.getMimeType();
+	this.representationClass = representationClass;
+      	this.humanPresentableName = humanPresentableName;
+    }
+
+    /**
+     * Construct a DataFlavor that represents a MimeType.
+     * <p>
+     * The returned DataFlavor will have the following characteristics:
+     * <p>
+     * If the mimeType is "application/x-java-serialized-object; class=",
+     * the result is the same as calling new DataFlavor(Class.forName()) as
+     * above, otherwise:
+     * <p>
+     * representationClass = InputStream<p>
+     * mimeType = mimeType
+     *
+     * @param mimeType the MIME type of the data represented by this class
+     * @param humanPresentableName the human presentable name of the flavor
+     */
+    public ActivationDataFlavor(String mimeType, String humanPresentableName) {
+	super(mimeType, humanPresentableName);
+	this.mimeType = mimeType;
+	try {
+	    this.representationClass = Class.forName("java.io.InputStream");
+	} catch (ClassNotFoundException ex) {
+	    // XXX - should never happen, ignore it
+	}
+      	this.humanPresentableName = humanPresentableName;
+    }
+
+    /**
+     * Return the MIME type for this DataFlavor.
+     *
+     * @return	the MIME type
+     */
+    public String getMimeType() {
+	return mimeType;
+    }
+
+    /**
+     * Return the representation class.
+     *
+     * @return	the representation class
+     */
+    public Class getRepresentationClass() {
+	return representationClass;
+    }
+
+    /**
+     * Return the Human Presentable name.
+     *
+     * @return	the human presentable name
+     */
+    public String getHumanPresentableName() {
+	return humanPresentableName;
+    }
+
+    /**
+     * Set the human presentable name.
+     *
+     * @param humanPresentableName	the name to set
+     */
+    public void setHumanPresentableName(String humanPresentableName) {
+	this.humanPresentableName = humanPresentableName;
+    }
+
+    /**
+     * Compares the DataFlavor passed in with this DataFlavor; calls
+     * the <code>isMimeTypeEqual</code> method.
+     *
+     * @param dataFlavor	the DataFlavor to compare with
+     * @return			true if the MIME type and representation class
+     *				are the same
+     */
+    public boolean equals(DataFlavor dataFlavor) {
+	return (isMimeTypeEqual(dataFlavor) &&
+	 	dataFlavor.getRepresentationClass() == representationClass);
+    }
+
+    /**
+     * Is the string representation of the MIME type passed in equivalent
+     * to the MIME type of this DataFlavor. <p>
+     *
+     * ActivationDataFlavor delegates the comparison of MIME types to
+     * the MimeType class included as part of Jakarta Activation.
+     * This provides a more robust comparison than is normally
+     * available in the DataFlavor class.
+     *
+     * @param mimeType	the MIME type
+     * @return		true if the same MIME type
+     */
+    public boolean isMimeTypeEqual(String mimeType) {
+	MimeType mt = null;
+	try {
+	    if (mimeObject == null)
+		mimeObject = new MimeType(this.mimeType);
+	    mt = new MimeType(mimeType);
+	} catch (MimeTypeParseException e) {
+	    // something didn't parse, do a crude comparison
+	    return this.mimeType.equalsIgnoreCase(mimeType);
+	}
+
+	return mimeObject.match(mt);
+    }
+
+    /**
+     * Called on DataFlavor for every MIME Type parameter to allow DataFlavor
+     * subclasses to handle special parameters like the text/plain charset
+     * parameters, whose values are case insensitive.  (MIME type parameter
+     * values are supposed to be case sensitive).
+     * <p>
+     * This method is called for each parameter name/value pair and should
+     * return the normalized representation of the parameterValue.
+     * This method is never invoked by this implementation.
+     *
+     * @param parameterName	the parameter name
+     * @param parameterValue	the parameter value
+     * @return			the normalized parameter value
+     * @deprecated
+     */
+    protected String normalizeMimeTypeParameter(String parameterName,
+						String parameterValue) {
+	return parameterValue;
+    }
+
+    /**
+     * Called for each MIME type string to give DataFlavor subtypes the
+     * opportunity to change how the normalization of MIME types is
+     * accomplished.
+     * One possible use would be to add default parameter/value pairs in cases
+     * where none are present in the MIME type string passed in.
+     * This method is never invoked by this implementation.
+     *
+     * @param mimeType	the MIME type
+     * @return		the normalized MIME type
+     * @deprecated
+     */
+    protected String normalizeMimeType(String mimeType) {
+	return mimeType;
+    }
+}
diff --git a/activation/src/main/java/javax/activation/CommandInfo.java b/activation/src/main/java/javax/activation/CommandInfo.java
new file mode 100644
index 0000000..792c582
--- /dev/null
+++ b/activation/src/main/java/javax/activation/CommandInfo.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The CommandInfo class is used by CommandMap implementations to
+ * describe the results of command requests. It provides the requestor
+ * with both the verb requested, as well as an instance of the
+ * bean. There is also a method that will return the name of the
+ * class that implements the command but <i>it is not guaranteed to
+ * return a valid value</i>. The reason for this is to allow CommandMap
+ * implmentations that subclass CommandInfo to provide special
+ * behavior. For example a CommandMap could dynamically generate
+ * JavaBeans. In this case, it might not be possible to create an
+ * object with all the correct state information solely from the class
+ * name.
+ */
+
+public class CommandInfo {
+    private String verb;
+    private String className;
+
+    /**
+     * The Constructor for CommandInfo.
+     * @param verb The command verb this CommandInfo decribes.
+     * @param className The command's fully qualified class name.
+     */
+    public CommandInfo(String verb, String className) {
+	this.verb = verb;
+	this.className = className;
+    }
+
+    /**
+     * Return the command verb.
+     *
+     * @return the command verb.
+     */
+    public String getCommandName() {
+	return verb;
+    }
+
+    /**
+     * Return the command's class name. <i>This method MAY return null in
+     * cases where a CommandMap subclassed CommandInfo for its
+     * own purposes.</i> In other words, it might not be possible to
+     * create the correct state in the command by merely knowing
+     * its class name. <b>DO NOT DEPEND ON THIS METHOD RETURNING
+     * A VALID VALUE!</b>
+     *
+     * @return The class name of the command, or <i>null</i>
+     */
+    public String getCommandClass() {
+	return className;
+    }
+
+    /**
+     * Return the instantiated JavaBean component.
+     * <p>
+     * If the current runtime environment supports
+     * {@link java.beans.Beans#instantiate Beans.instantiate},
+     * use it to instantiate the JavaBeans component.  Otherwise, use
+     * {@link java.lang.Class#forName Class.forName}.
+     * <p>
+     * The component class needs to be public.
+     * On Java SE 9 and newer, if the component class is in a named module,
+     * it needs to be in an exported package.
+     * <p>
+     * If the bean implements the <code>javax.activation.CommandObject</code>
+     * interface, call its <code>setCommandContext</code> method.
+     * <p>
+     * If the DataHandler parameter is null, then the bean is
+     * instantiated with no data. NOTE: this may be useful
+     * if for some reason the DataHandler that is passed in
+     * throws IOExceptions when this method attempts to
+     * access its InputStream. It will allow the caller to
+     * retrieve a reference to the bean if it can be
+     * instantiated.
+     * <p>
+     * If the bean does NOT implement the CommandObject interface,
+     * this method will check if it implements the
+     * java.io.Externalizable interface. If it does, the bean's
+     * readExternal method will be called if an InputStream
+     * can be acquired from the DataHandler.<p>
+     *
+     * @param dh	The DataHandler that describes the data to be
+     *			passed to the command.
+     * @param loader	The ClassLoader to be used to instantiate the bean.
+     * @return The bean
+     * @exception	IOException	for failures reading data
+     * @exception	ClassNotFoundException	if command object class can't
+     *						be found
+     * @see java.beans.Beans#instantiate
+     * @see javax.activation.CommandObject
+     */
+    public Object getCommandObject(DataHandler dh, ClassLoader loader)
+			throws IOException, ClassNotFoundException {
+	Object new_bean = null;
+
+	// try to instantiate the bean
+	new_bean = Beans.instantiate(loader, className);
+
+	// if we got one and it is a CommandObject
+	if (new_bean != null) {
+	    if (new_bean instanceof CommandObject) {
+		((CommandObject)new_bean).setCommandContext(verb, dh);
+	    } else if (new_bean instanceof Externalizable) {
+		if (dh != null) {
+		    InputStream is = dh.getInputStream();
+		    if (is != null) {
+			((Externalizable)new_bean).readExternal(
+					       new ObjectInputStream(is));
+		    }
+		}
+	    }
+	}
+
+	return new_bean;
+    }
+
+    /**
+     * Helper class to invoke Beans.instantiate reflectively or the equivalent
+     * with core reflection when module java.desktop is not readable.
+     */
+    private static final class Beans {
+        static final Method instantiateMethod;
+
+        static {
+            Method m;
+            try {
+                Class<?> c = Class.forName("java.beans.Beans");
+                m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class);
+            } catch (ClassNotFoundException e) {
+                m = null;
+            } catch (NoSuchMethodException e) {
+                m = null;
+            }
+            instantiateMethod = m;
+        }
+
+        /**
+         * Equivalent to invoking java.beans.Beans.instantiate(loader, cn)
+         */
+        static Object instantiate(ClassLoader loader, String cn)
+                throws IOException, ClassNotFoundException {
+
+            Exception exception;
+
+            if (instantiateMethod != null) {
+
+                // invoke Beans.instantiate
+                try {
+                    return instantiateMethod.invoke(null, loader, cn);
+                } catch (InvocationTargetException e) {
+                    exception = e;
+                } catch (IllegalAccessException e) {
+                    exception = e;
+                }
+
+            } else {
+
+		SecurityManager security = System.getSecurityManager();
+		if (security != null) {
+		    // if it's ok with the SecurityManager, it's ok with me.
+		    String cname = cn.replace('/', '.');
+		    if (cname.startsWith("[")) {
+			int b = cname.lastIndexOf('[') + 2;
+			if (b > 1 && b < cname.length()) {
+			    cname = cname.substring(b);
+			}
+		    }
+		    int i = cname.lastIndexOf('.');
+		    if (i != -1) {
+			security.checkPackageAccess(cname.substring(0, i));
+		    }
+		}
+
+                // Beans.instantiate specified to use SCL when loader is null
+                if (loader == null) {
+                    loader = (ClassLoader)
+		        AccessController.doPrivileged(new PrivilegedAction() {
+			    public Object run() {
+				ClassLoader cl = null;
+				try {
+				    cl = ClassLoader.getSystemClassLoader();
+				} catch (SecurityException ex) { }
+				return cl;
+			    }
+			});
+                }
+                Class<?> beanClass = Class.forName(cn, true, loader);
+                try {
+                    return beanClass.newInstance();
+                } catch (Exception ex) {
+                    throw new ClassNotFoundException(beanClass + ": " + ex, ex);
+                }
+
+            }
+            return null;
+        }
+    }
+}
diff --git a/activation/src/main/java/javax/activation/CommandMap.java b/activation/src/main/java/javax/activation/CommandMap.java
new file mode 100644
index 0000000..69f4910
--- /dev/null
+++ b/activation/src/main/java/javax/activation/CommandMap.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+
+/**
+ * The CommandMap class provides an interface to a registry of
+ * command objects available in the system.
+ * Developers are expected to either use the CommandMap
+ * implementation included with this package (MailcapCommandMap) or
+ * develop their own. Note that some of the methods in this class are
+ * abstract.
+ */
+public abstract class CommandMap {
+    private static CommandMap defaultCommandMap = null;
+    private static Map<ClassLoader,CommandMap> map =
+				new WeakHashMap<ClassLoader,CommandMap>();
+
+
+    /**
+     * Get the default CommandMap.
+     *
+     * <ul>
+     * <li> In cases where a CommandMap instance has been previously set
+     *      to some value (via <i>setDefaultCommandMap</i>)
+     *  return the CommandMap.
+     * <li>
+     *  In cases where no CommandMap has been set, the CommandMap
+     *       creates an instance of <code>MailcapCommandMap</code> and
+     *       set that to the default, returning its value.
+     *
+     * </ul>
+     *
+     * @return the CommandMap
+     */
+    public static synchronized CommandMap getDefaultCommandMap() {
+	if (defaultCommandMap != null)
+	    return defaultCommandMap;
+
+	// fetch per-thread-context-class-loader default
+	ClassLoader tccl = SecuritySupport.getContextClassLoader();
+	CommandMap def = map.get(tccl);
+	if (def == null) {
+	    def = new MailcapCommandMap();
+	    map.put(tccl, def);
+	}
+	return def;
+    }
+
+    /**
+     * Set the default CommandMap. Reset the CommandMap to the default by
+     * calling this method with <code>null</code>.
+     *
+     * @param commandMap The new default CommandMap.
+     * @exception SecurityException if the caller doesn't have permission
+     *					to change the default
+     */
+    public static synchronized void setDefaultCommandMap(CommandMap commandMap) {
+	SecurityManager security = System.getSecurityManager();
+	if (security != null) {
+	    try {
+		// if it's ok with the SecurityManager, it's ok with me...
+		security.checkSetFactory();
+	    } catch (SecurityException ex) {
+		// otherwise, we also allow it if this code and the
+		// factory come from the same (non-system) class loader (e.g.,
+		// the JAF classes were loaded with the applet classes).
+		ClassLoader cl = CommandMap.class.getClassLoader();
+		if (cl == null || cl.getParent() == null ||
+		    cl != commandMap.getClass().getClassLoader()) {
+		    throw ex;
+		}
+	    }
+	}
+	// remove any per-thread-context-class-loader CommandMap
+	map.remove(SecuritySupport.getContextClassLoader());
+	defaultCommandMap = commandMap;
+    }
+
+    /**
+     * Get the preferred command list from a MIME Type. The actual semantics
+     * are determined by the implementation of the CommandMap.
+     *
+     * @param mimeType	the MIME type
+     * @return the CommandInfo classes that represent the command Beans.
+     */
+    abstract public  CommandInfo[] getPreferredCommands(String mimeType);
+
+    /**
+     * Get the preferred command list from a MIME Type. The actual semantics
+     * are determined by the implementation of the CommandMap. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the list of commands that are returned.  The implementation
+     * in this class simply calls the <code>getPreferredCommands</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo classes that represent the command Beans.
+     * @since	JAF 1.1
+     */
+    public CommandInfo[] getPreferredCommands(String mimeType, DataSource ds) {
+	return getPreferredCommands(mimeType);
+    }
+
+    /**
+     * Get all the available commands for this type. This method
+     * should return all the possible commands for this MIME type.
+     *
+     * @param mimeType	the MIME type
+     * @return the CommandInfo objects representing all the commands.
+     */
+    abstract public CommandInfo[] getAllCommands(String mimeType);
+
+    /**
+     * Get all the available commands for this type. This method
+     * should return all the possible commands for this MIME type. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the list of commands that are returned.  The implementation
+     * in this class simply calls the <code>getAllCommands</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo objects representing all the commands.
+     * @since	JAF 1.1
+     */
+    public CommandInfo[] getAllCommands(String mimeType, DataSource ds) {
+	return getAllCommands(mimeType);
+    }
+
+    /**
+     * Get the default command corresponding to the MIME type.
+     *
+     * @param mimeType	the MIME type
+     * @param cmdName	the command name
+     * @return the CommandInfo corresponding to the command.
+     */
+    abstract public CommandInfo getCommand(String mimeType, String cmdName);
+
+    /**
+     * Get the default command corresponding to the MIME type. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the command that is chosen.  The implementation
+     * in this class simply calls the <code>getCommand</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param cmdName	the command name
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo corresponding to the command.
+     * @since	JAF 1.1
+     */
+    public CommandInfo getCommand(String mimeType, String cmdName,
+				DataSource ds) {
+	return getCommand(mimeType, cmdName);
+    }
+
+    /**
+     * Locate a DataContentHandler that corresponds to the MIME type.
+     * The mechanism and semantics for determining this are determined
+     * by the implementation of the particular CommandMap.
+     *
+     * @param mimeType	the MIME type
+     * @return		the DataContentHandler for the MIME type
+     */
+    abstract public DataContentHandler createDataContentHandler(String
+								mimeType);
+
+    /**
+     * Locate a DataContentHandler that corresponds to the MIME type.
+     * The mechanism and semantics for determining this are determined
+     * by the implementation of the particular CommandMap. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the choice of DataContentHandler.  The implementation
+     * in this class simply calls the <code>createDataContentHandler</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return		the DataContentHandler for the MIME type
+     * @since	JAF 1.1
+     */
+    public DataContentHandler createDataContentHandler(String mimeType,
+				DataSource ds) {
+	return createDataContentHandler(mimeType);
+    }
+
+    /**
+     * Get all the MIME types known to this command map.
+     * If the command map doesn't support this operation,
+     * null is returned.
+     *
+     * @return		array of MIME types as strings, or null if not supported
+     * @since	JAF 1.1
+     */
+    public String[] getMimeTypes() {
+	return null;
+    }
+}
diff --git a/activation/src/main/java/javax/activation/CommandObject.java b/activation/src/main/java/javax/activation/CommandObject.java
new file mode 100644
index 0000000..e44913b
--- /dev/null
+++ b/activation/src/main/java/javax/activation/CommandObject.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.IOException;
+
+/**
+ * JavaBeans components that are Jakarta Activation aware implement
+ * this interface to find out which command verb they're being asked
+ * to perform, and to obtain the DataHandler representing the
+ * data they should operate on.  JavaBeans that don't implement
+ * this interface may be used as well.  Such commands may obtain
+ * the data using the Externalizable interface, or using an
+ * application-specific method.
+ */
+public interface CommandObject {
+
+    /**
+     * Initialize the Command with the verb it is requested to handle
+     * and the DataHandler that describes the data it will
+     * operate on. <b>NOTE:</b> it is acceptable for the caller
+     * to pass <i>null</i> as the value for <code>DataHandler</code>.
+     *
+     * @param verb The Command Verb this object refers to.
+     * @param dh The DataHandler.
+     * @exception	IOException	for failures accessing data
+     */
+    public void setCommandContext(String verb, DataHandler dh)
+						throws IOException;
+}
diff --git a/activation/src/main/java/javax/activation/DataContentHandler.java b/activation/src/main/java/javax/activation/DataContentHandler.java
new file mode 100644
index 0000000..42e3148
--- /dev/null
+++ b/activation/src/main/java/javax/activation/DataContentHandler.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.activation.DataSource;
+
+/**
+ * The DataContentHandler interface is implemented by objects that can
+ * be used to extend the capabilities of the DataHandler's implementation
+ * of the Transferable interface. Through <code>DataContentHandlers</code>
+ * the framework can be extended to convert streams in to objects, and
+ * to write objects to streams. <p>
+ *
+ * Applications don't generally call the methods in DataContentHandlers
+ * directly. Instead, an application calls the equivalent methods in
+ * DataHandler. The DataHandler will attempt to find an appropriate
+ * DataContentHandler that corresponds to its MIME type using the
+ * current DataContentHandlerFactory. The DataHandler then calls
+ * through to the methods in the DataContentHandler.
+ */
+
+public interface DataContentHandler {
+    /**
+     * Returns an array of DataFlavor objects indicating the flavors the
+     * data can be provided in. The array should be ordered according to
+     * preference for providing the data (from most richly descriptive to
+     * least descriptive).
+     *
+     * @return The DataFlavors.
+     */
+    public DataFlavor[] getTransferDataFlavors();
+
+    /**
+     * Returns an object which represents the data to be transferred.
+     * The class of the object returned is defined by the representation class
+     * of the flavor.
+     *
+     * @param df The DataFlavor representing the requested type.
+     * @param ds The DataSource representing the data to be converted.
+     * @return The constructed Object.
+     * @exception UnsupportedFlavorException	if the handler doesn't
+     *						support the requested flavor
+     * @exception IOException	if the data can't be accessed
+     */
+    public Object getTransferData(DataFlavor df, DataSource ds)
+				throws UnsupportedFlavorException, IOException;
+
+    /**
+     * Return an object representing the data in its most preferred form.
+     * Generally this will be the form described by the first DataFlavor
+     * returned by the <code>getTransferDataFlavors</code> method.
+     *
+     * @param ds The DataSource representing the data to be converted.
+     * @return The constructed Object.
+     * @exception IOException	if the data can't be accessed
+     */
+    public Object getContent(DataSource ds) throws IOException;
+
+    /**
+     * Convert the object to a byte stream of the specified MIME type
+     * and write it to the output stream.
+     *
+     * @param obj	The object to be converted.
+     * @param mimeType	The requested MIME type of the resulting byte stream.
+     * @param os	The output stream into which to write the converted
+     *			byte stream.
+     * @exception IOException	errors writing to the stream
+     */
+    public void writeTo(Object obj, String mimeType, OutputStream os)
+	                                               throws IOException;
+}
diff --git a/activation/src/main/java/javax/activation/DataContentHandlerFactory.java b/activation/src/main/java/javax/activation/DataContentHandlerFactory.java
new file mode 100644
index 0000000..0cd0f5c
--- /dev/null
+++ b/activation/src/main/java/javax/activation/DataContentHandlerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+/**
+ * This interface defines a factory for <code>DataContentHandlers</code>. An
+ * implementation of this interface should map a MIME type into an
+ * instance of DataContentHandler. The design pattern for classes implementing
+ * this interface is the same as for the ContentHandler mechanism used in
+ * <code>java.net.URL</code>.
+ */
+
+public interface DataContentHandlerFactory {
+
+    /**
+     * Creates a new DataContentHandler object for the MIME type.
+     *
+     * @param mimeType the MIME type to create the DataContentHandler for.
+     * @return The new <code>DataContentHandler</code>, or <i>null</i>
+     * if none are found.
+     */
+    public DataContentHandler createDataContentHandler(String mimeType);
+}
diff --git a/activation/src/main/java/javax/activation/DataHandler.java b/activation/src/main/java/javax/activation/DataHandler.java
new file mode 100644
index 0000000..897fd95
--- /dev/null
+++ b/activation/src/main/java/javax/activation/DataHandler.java
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.UnsupportedFlavorException;
+
+/**
+ * The DataHandler class provides a consistent interface to data
+ * available in many different sources and formats.
+ * It manages simple stream to string conversions and related operations
+ * using DataContentHandlers.
+ * It provides access to commands that can operate on the data.
+ * The commands are found using a CommandMap. <p>
+ *
+ * <b>DataHandler and the Transferable Interface</b><p>
+ * DataHandler implements the Transferable interface so that data can
+ * be used in AWT data transfer operations, such as cut and paste and
+ * drag and drop. The implementation of the Transferable interface
+ * relies on the availability of an installed DataContentHandler
+ * object corresponding to the MIME type of the data represented in
+ * the specific instance of the DataHandler.<p>
+ *
+ * <b>DataHandler and CommandMaps</b><p>
+ * The DataHandler keeps track of the current CommandMap that it uses to
+ * service requests for commands (<code>getCommand</code>,
+ * <code>getAllCommands</code>, <code>getPreferredCommands</code>).
+ * Each instance of a DataHandler may have a CommandMap associated with
+ * it using the <code>setCommandMap</code> method.  If a CommandMap was
+ * not set, DataHandler calls the <code>getDefaultCommandMap</code>
+ * method in CommandMap and uses the value it returns. See
+ * <i>CommandMap</i> for more information. <p>
+ *
+ * <b>DataHandler and URLs</b><p>
+ * The current DataHandler implementation creates a private
+ * instance of URLDataSource when it is constructed with a URL.
+ *
+ * @see javax.activation.CommandMap
+ * @see javax.activation.DataContentHandler
+ * @see javax.activation.DataSource
+ * @see javax.activation.URLDataSource
+ */
+
+public class DataHandler implements Transferable {
+
+    // Use the datasource to indicate whether we were started via the
+    // DataSource constructor or the object constructor.
+    private DataSource dataSource = null;
+    private DataSource objDataSource = null;
+
+    // The Object and mimetype from the constructor (if passed in).
+    // object remains null if it was instantiated with a
+    // DataSource.
+    private Object object = null;
+    private String objectMimeType = null;
+
+    // Keep track of the CommandMap
+    private CommandMap currentCommandMap = null;
+
+    // our transfer flavors
+    private static final DataFlavor emptyFlavors[] = new DataFlavor[0];
+    private DataFlavor transferFlavors[] = emptyFlavors;
+
+    // our DataContentHandler
+    private DataContentHandler dataContentHandler = null;
+    private DataContentHandler factoryDCH = null;
+
+    // our DataContentHandlerFactory
+    private static DataContentHandlerFactory factory = null;
+    private DataContentHandlerFactory oldFactory = null;
+    // the short representation of the ContentType (sans params)
+    private String shortType = null;
+
+    /**
+     * Create a <code>DataHandler</code> instance referencing the
+     * specified DataSource.  The data exists in a byte stream form.
+     * The DataSource will provide an InputStream to access the data.
+     *
+     * @param ds	the DataSource
+     */
+    public DataHandler(DataSource ds) {
+	// save a reference to the incoming DS
+	dataSource = ds;
+	oldFactory = factory; // keep track of the factory
+    }
+
+    /**
+     * Create a <code>DataHandler</code> instance representing an object
+     * of this MIME type.  This constructor is
+     * used when the application already has an in-memory representation
+     * of the data in the form of a Java Object.
+     *
+     * @param obj	the Java Object
+     * @param mimeType	the MIME type of the object
+     */
+    public DataHandler(Object obj, String mimeType) {
+	object = obj;
+	objectMimeType = mimeType;
+	oldFactory = factory; // keep track of the factory
+    }
+
+    /**
+     * Create a <code>DataHandler</code> instance referencing a URL.
+     * The DataHandler internally creates a <code>URLDataSource</code>
+     * instance to represent the URL.
+     *
+     * @param url	a URL object
+     */
+    public DataHandler(URL url) {
+	dataSource = new URLDataSource(url);
+	oldFactory = factory; // keep track of the factory
+    }
+
+    /**
+     * Return the CommandMap for this instance of DataHandler.
+     */
+    private synchronized CommandMap getCommandMap() {
+	if (currentCommandMap != null)
+	    return currentCommandMap;
+	else
+	    return CommandMap.getDefaultCommandMap();
+    }
+
+    /**
+     * Return the DataSource associated with this instance
+     * of DataHandler.
+     * <p>
+     * For DataHandlers that have been instantiated with a DataSource,
+     * this method returns the DataSource that was used to create the
+     * DataHandler object. In other cases the DataHandler
+     * constructs a DataSource from the data used to construct
+     * the DataHandler. DataSources created for DataHandlers <b>not</b>
+     * instantiated with a DataSource are cached for performance
+     * reasons.
+     *
+     * @return	a valid DataSource object for this DataHandler
+     */
+    public DataSource getDataSource() {
+	if (dataSource == null) {
+	    // create one on the fly
+	    if (objDataSource == null)
+		objDataSource = new DataHandlerDataSource(this);
+	    return objDataSource;
+	}
+	return dataSource;
+    }
+
+    /**
+     * Return the name of the data object. If this DataHandler
+     * was created with a DataSource, this method calls through
+     * to the <code>DataSource.getName</code> method, otherwise it
+     * returns <i>null</i>.
+     *
+     * @return	the name of the object
+     */
+    public String getName() {
+	if (dataSource != null)
+	    return dataSource.getName();
+	else
+	    return null;
+    }
+
+    /**
+     * Return the MIME type of this object as retrieved from
+     * the source object. Note that this is the <i>full</i>
+     * type with parameters.
+     *
+     * @return	the MIME type
+     */
+    public String getContentType() {
+	if (dataSource != null) // data source case
+	    return dataSource.getContentType();
+	else
+	    return objectMimeType; // obj/type case
+    }
+
+    /**
+     * Get the InputStream for this object. <p>
+     *
+     * For DataHandlers instantiated with a DataSource, the DataHandler
+     * calls the <code>DataSource.getInputStream</code> method and
+     * returns the result to the caller.
+     * <p>
+     * For DataHandlers instantiated with an Object, the DataHandler
+     * first attempts to find a DataContentHandler for the Object. If
+     * the DataHandler can not find a DataContentHandler for this MIME
+     * type, it throws an UnsupportedDataTypeException.  If it is
+     * successful, it creates a pipe and a thread.  The thread uses the
+     * DataContentHandler's <code>writeTo</code> method to write the
+     * stream data into one end of the pipe.  The other end of the pipe
+     * is returned to the caller.  Because a thread is created to copy
+     * the data, IOExceptions that may occur during the copy can not be
+     * propagated back to the caller. The result is an empty stream.<p>
+     *
+     * @return	the InputStream representing this data
+     * @exception IOException	if an I/O error occurs
+     *
+     * @see javax.activation.DataContentHandler#writeTo
+     * @see javax.activation.UnsupportedDataTypeException
+     */
+    public InputStream getInputStream() throws IOException {
+	InputStream ins = null;
+
+	if (dataSource != null) {
+	    ins = dataSource.getInputStream();
+	} else {
+	    DataContentHandler dch = getDataContentHandler();
+	    // we won't even try if we can't get a dch
+	    if (dch == null)
+		throw new UnsupportedDataTypeException(
+				"no DCH for MIME type " + getBaseType());
+
+	    if (dch instanceof ObjectDataContentHandler) {
+		if (((ObjectDataContentHandler)dch).getDCH() == null)
+		    throw new UnsupportedDataTypeException(
+				"no object DCH for MIME type " + getBaseType());
+	    }
+	    // there is none but the default^^^^^^^^^^^^^^^^
+	    final DataContentHandler fdch = dch;
+
+	    // from bill s.
+	    // ce n'est pas une pipe!
+	    //
+	    // NOTE: This block of code needs to throw exceptions, but
+	    // can't because it is in another thread!!! ARG!
+	    //
+	    final PipedOutputStream pos = new PipedOutputStream();
+	    PipedInputStream pin = new PipedInputStream(pos);
+	    new Thread(
+		       new Runnable() {
+		public void run() {
+		    try {
+			fdch.writeTo(object, objectMimeType, pos);
+		    } catch (IOException e) {
+
+		    } finally {
+			try {
+			    pos.close();
+			} catch (IOException ie) { }
+		    }
+		}
+	    },
+		      "DataHandler.getInputStream").start();
+	    ins = pin;
+	}
+
+	return ins;
+    }
+
+    /**
+     * Write the data to an <code>OutputStream</code>.<p>
+     *
+     * If the DataHandler was created with a DataSource, writeTo
+     * retrieves the InputStream and copies the bytes from the
+     * InputStream to the OutputStream passed in.
+     * <p>
+     * If the DataHandler was created with an object, writeTo
+     * retrieves the DataContentHandler for the object's type.
+     * If the DataContentHandler was found, it calls the
+     * <code>writeTo</code> method on the <code>DataContentHandler</code>.
+     *
+     * @param os	the OutputStream to write to
+     * @exception IOException	if an I/O error occurs
+     */
+    public void writeTo(OutputStream os) throws IOException {
+	// for the DataSource case
+	if (dataSource != null) {
+	    InputStream is = null;
+	    byte data[] = new byte[8*1024];
+	    int bytes_read;
+
+	    is = dataSource.getInputStream();
+
+	    try {
+		while ((bytes_read = is.read(data)) > 0) {
+		    os.write(data, 0, bytes_read);
+		}
+	    } finally {
+		is.close();
+		is = null;
+	    }
+	} else { // for the Object case
+	    DataContentHandler dch = getDataContentHandler();
+	    dch.writeTo(object, objectMimeType, os);
+	}
+    }
+
+    /**
+     * Get an OutputStream for this DataHandler to allow overwriting
+     * the underlying data.
+     * If the DataHandler was created with a DataSource, the
+     * DataSource's <code>getOutputStream</code> method is called.
+     * Otherwise, <code>null</code> is returned.
+     *
+     * @return the OutputStream
+     * @exception	IOException	for failures creating the OutputStream
+     *
+     * @see javax.activation.DataSource#getOutputStream
+     * @see javax.activation.URLDataSource
+     */
+    public OutputStream getOutputStream() throws IOException {
+	if (dataSource != null)
+	    return dataSource.getOutputStream();
+	else
+	    return null;
+    }
+
+    /**
+     * Return the DataFlavors in which this data is available. <p>
+     *
+     * Returns an array of DataFlavor objects indicating the flavors
+     * the data can be provided in. The array is usually ordered
+     * according to preference for providing the data, from most
+     * richly descriptive to least richly descriptive.<p>
+     *
+     * The DataHandler attempts to find a DataContentHandler that
+     * corresponds to the MIME type of the data. If one is located,
+     * the DataHandler calls the DataContentHandler's
+     * <code>getTransferDataFlavors</code> method. <p>
+     *
+     * If a DataContentHandler can <i>not</i> be located, and if the
+     * DataHandler was created with a DataSource (or URL), one
+     * DataFlavor is returned that represents this object's MIME type
+     * and the <code>java.io.InputStream</code> class.  If the
+     * DataHandler was created with an object and a MIME type,
+     * getTransferDataFlavors returns one DataFlavor that represents
+     * this object's MIME type and the object's class.
+     *
+     * @return	an array of data flavors in which this data can be transferred
+     * @see javax.activation.DataContentHandler#getTransferDataFlavors
+     */
+    public synchronized DataFlavor[] getTransferDataFlavors() {
+	if (factory != oldFactory) // if the factory has changed, clear cache
+	    transferFlavors = emptyFlavors;
+
+	// if it's not set, set it...
+	if (transferFlavors == emptyFlavors)
+	    transferFlavors = getDataContentHandler().getTransferDataFlavors();
+	if (transferFlavors == emptyFlavors)
+	    return transferFlavors;	// no need to clone an empty array
+	else
+	    return transferFlavors.clone();
+    }
+
+    /**
+     * Returns whether the specified data flavor is supported
+     * for this object.<p>
+     *
+     * This method iterates through the DataFlavors returned from
+     * <code>getTransferDataFlavors</code>, comparing each with
+     * the specified flavor.
+     *
+     * @param flavor	the requested flavor for the data
+     * @return		true if the data flavor is supported
+     * @see javax.activation.DataHandler#getTransferDataFlavors
+     */
+    public boolean isDataFlavorSupported(DataFlavor flavor) {
+	DataFlavor[] lFlavors = getTransferDataFlavors();
+
+	for (int i = 0; i < lFlavors.length; i++) {
+	    if (lFlavors[i].equals(flavor))
+		return true;
+	}
+	return false;
+    }
+
+    /**
+     * Returns an object that represents the data to be
+     * transferred. The class of the object returned is defined by the
+     * representation class of the data flavor.<p>
+     *
+     * <b>For DataHandler's created with DataSources or URLs:</b><p>
+     *
+     * The DataHandler attempts to locate a DataContentHandler
+     * for this MIME type. If one is found, the passed in DataFlavor
+     * and the type of the data are passed to its <code>getTransferData</code>
+     * method. If the DataHandler fails to locate a DataContentHandler
+     * and the flavor specifies this object's MIME type and the
+     * <code>java.io.InputStream</code> class, this object's InputStream
+     * is returned.
+     * Otherwise it throws an UnsupportedFlavorException. <p>
+     *
+     * <b>For DataHandler's created with Objects:</b><p>
+     *
+     * The DataHandler attempts to locate a DataContentHandler
+     * for this MIME type. If one is found, the passed in DataFlavor
+     * and the type of the data are passed to its getTransferData
+     * method. If the DataHandler fails to locate a DataContentHandler
+     * and the flavor specifies this object's MIME type and its class,
+     * this DataHandler's referenced object is returned.  
+     * Otherwise it throws an UnsupportedFlavorException.
+     *
+     * @param flavor	the requested flavor for the data
+     * @return		the object
+     * @exception UnsupportedFlavorException	if the data could not be
+     *			converted to the requested flavor
+     * @exception IOException	if an I/O error occurs
+     * @see javax.activation.ActivationDataFlavor
+     */
+    public Object getTransferData(DataFlavor flavor)
+				throws UnsupportedFlavorException, IOException {
+	return getDataContentHandler().getTransferData(flavor, dataSource);
+    }
+
+    /**
+     * Set the CommandMap for use by this DataHandler.
+     * Setting it to <code>null</code> causes the CommandMap to revert
+     * to the CommandMap returned by the
+     * <code>CommandMap.getDefaultCommandMap</code> method.
+     * Changing the CommandMap, or setting it to <code>null</code>,
+     * clears out any data cached from the previous CommandMap.
+     *
+     * @param commandMap	the CommandMap to use in this DataHandler
+     *
+     * @see javax.activation.CommandMap#setDefaultCommandMap
+     */
+    public synchronized void setCommandMap(CommandMap commandMap) {
+	if (commandMap != currentCommandMap || commandMap == null) {
+	    // clear cached values...
+	    transferFlavors = emptyFlavors;
+	    dataContentHandler = null;
+
+	    currentCommandMap = commandMap;
+	}
+    }
+
+    /**
+     * Return the <i>preferred</i> commands for this type of data.
+     * This method calls the <code>getPreferredCommands</code> method
+     * in the CommandMap associated with this instance of DataHandler.
+     * This method returns an array that represents a subset of
+     * available commands. In cases where multiple commands for the
+     * MIME type represented by this DataHandler are present, the
+     * installed CommandMap chooses the appropriate commands.
+     *
+     * @return	the CommandInfo objects representing the preferred commands
+     *
+     * @see javax.activation.CommandMap#getPreferredCommands
+     */
+    public CommandInfo[] getPreferredCommands() {
+	if (dataSource != null)
+	    return getCommandMap().getPreferredCommands(getBaseType(),
+							dataSource);
+	else
+	    return getCommandMap().getPreferredCommands(getBaseType());
+    }
+
+    /**
+     * Return all the commands for this type of data.
+     * This method returns an array containing all commands
+     * for the type of data represented by this DataHandler. The
+     * MIME type for the underlying data represented by this DataHandler
+     * is used to call through to the <code>getAllCommands</code> method
+     * of the CommandMap associated with this DataHandler.
+     *
+     * @return	the CommandInfo objects representing all the commands
+     *
+     * @see javax.activation.CommandMap#getAllCommands
+     */
+    public CommandInfo[] getAllCommands() {
+	if (dataSource != null)
+	    return getCommandMap().getAllCommands(getBaseType(), dataSource);
+	else
+	    return getCommandMap().getAllCommands(getBaseType());
+    }
+
+    /**
+     * Get the command <i>cmdName</i>. Use the search semantics as
+     * defined by the CommandMap installed in this DataHandler. The
+     * MIME type for the underlying data represented by this DataHandler
+     * is used to call through to the <code>getCommand</code> method
+     * of the CommandMap associated with this DataHandler.
+     *
+     * @param cmdName	the command name
+     * @return	the CommandInfo corresponding to the command
+     *
+     * @see javax.activation.CommandMap#getCommand
+     */
+    public CommandInfo getCommand(String cmdName) {
+	if (dataSource != null)
+	    return getCommandMap().getCommand(getBaseType(), cmdName,
+								dataSource);
+	else
+	    return getCommandMap().getCommand(getBaseType(), cmdName);
+    }
+
+    /**
+     * Return the data in its preferred Object form. <p>
+     *
+     * If the DataHandler was instantiated with an object, return
+     * the object. <p>
+     *
+     * If the DataHandler was instantiated with a DataSource,
+     * this method uses a DataContentHandler to return the content
+     * object for the data represented by this DataHandler. If no
+     * <code>DataContentHandler</code> can be found for the
+     * the type of this data, the DataHandler returns an
+     * InputStream for the data.
+     *
+     * @return the content.
+     * @exception IOException if an IOException occurs during
+     *                              this operation.
+     */
+    public Object getContent() throws IOException {
+	if (object != null)
+	    return object;
+	else
+	    return getDataContentHandler().getContent(getDataSource());
+    }
+
+    /**
+     * A convenience method that takes a CommandInfo object
+     * and instantiates the corresponding command, usually
+     * a JavaBean component.
+     * <p>
+     * This method calls the CommandInfo's <code>getCommandObject</code>
+     * method with the <code>ClassLoader</code> used to load
+     * the <code>javax.activation.DataHandler</code> class itself.
+     *
+     * @param cmdinfo	the CommandInfo corresponding to a command
+     * @return	the instantiated command object
+     */
+    public Object getBean(CommandInfo cmdinfo) {
+	Object bean = null;
+
+	try {
+	    // make the bean
+	    ClassLoader cld = null;
+	    // First try the "application's" class loader.
+	    cld = SecuritySupport.getContextClassLoader();
+	    if (cld == null)
+		cld = this.getClass().getClassLoader();
+	    bean = cmdinfo.getCommandObject(this, cld);
+	} catch (IOException e) {
+	} catch (ClassNotFoundException e) { }
+
+	return bean;
+    }
+
+    /**
+     * Get the DataContentHandler for this DataHandler: <p>
+     *
+     * If a DataContentHandlerFactory is set, use it.
+     * Otherwise look for an object to serve DCH in the
+     * following order: <p>
+     *
+     * 1) if a factory is set, use it <p>
+     * 2) if a CommandMap is set, use it <p>
+     * 3) use the default CommandMap <p>
+     *
+     * In any case, wrap the real DataContentHandler with one of our own
+     * to handle any missing cases, fill in defaults, and to ensure that
+     * we always have a non-null DataContentHandler.
+     *
+     * @return	the requested DataContentHandler
+     */
+    private synchronized DataContentHandler getDataContentHandler() {
+
+	// make sure the factory didn't change
+	if (factory != oldFactory) {
+	    oldFactory = factory;
+	    factoryDCH = null;
+	    dataContentHandler = null;
+	    transferFlavors = emptyFlavors;
+	}
+
+ 	if (dataContentHandler != null)
+ 	    return dataContentHandler;
+
+	String simpleMT = getBaseType();
+
+	if (factoryDCH == null && factory != null)
+	    factoryDCH = factory.createDataContentHandler(simpleMT);
+
+ 	if (factoryDCH != null)
+ 	    dataContentHandler = factoryDCH;
+
+	if (dataContentHandler == null) {
+	    if (dataSource != null)
+		dataContentHandler = getCommandMap().
+				createDataContentHandler(simpleMT, dataSource);
+	    else
+		dataContentHandler = getCommandMap().
+				createDataContentHandler(simpleMT);
+	}
+
+	// getDataContentHandler always uses these 'wrapper' handlers
+	// to make sure it returns SOMETHING meaningful...
+	if (dataSource != null)
+	    dataContentHandler = new DataSourceDataContentHandler(
+						      dataContentHandler,
+						      dataSource);
+	else
+	    dataContentHandler = new ObjectDataContentHandler(
+						      dataContentHandler,
+						      object,
+						      objectMimeType);
+	return dataContentHandler;
+    }
+
+    /**
+     * Use the MimeType class to extract the MIME type/subtype,
+     * ignoring the parameters.  The type is cached.
+     */
+    private synchronized String getBaseType() {
+	if (shortType == null) {
+	    String ct = getContentType();
+	    try {
+		MimeType mt = new MimeType(ct);
+		shortType = mt.getBaseType();
+	    } catch (MimeTypeParseException e) {
+		shortType = ct;
+	    }
+	}
+	return shortType;
+    }
+
+    /**
+     * Sets the DataContentHandlerFactory.  The DataContentHandlerFactory
+     * is called first to find DataContentHandlers.
+     * The DataContentHandlerFactory can only be set once.
+     * <p>
+     * If the DataContentHandlerFactory has already been set,
+     * this method throws an Error.
+     *
+     * @param newFactory	the DataContentHandlerFactory
+     * @exception Error	if the factory has already been defined.
+     *
+     * @see javax.activation.DataContentHandlerFactory
+     */
+    public static synchronized void setDataContentHandlerFactory(
+					 DataContentHandlerFactory newFactory) {
+	if (factory != null)
+	    throw new Error("DataContentHandlerFactory already defined");
+
+	SecurityManager security = System.getSecurityManager();
+	if (security != null) {
+	    try {
+		// if it's ok with the SecurityManager, it's ok with me...
+		security.checkSetFactory();
+	    } catch (SecurityException ex) {
+		// otherwise, we also allow it if this code and the
+		// factory come from the same class loader (e.g.,
+		// the JAF classes were loaded with the applet classes).
+		if (DataHandler.class.getClassLoader() !=
+			newFactory.getClass().getClassLoader())
+		    throw ex;
+	    }
+	}
+	factory = newFactory;
+    }
+}
+
+/**
+ * The DataHanderDataSource class implements the
+ * DataSource interface when the DataHandler is constructed
+ * with an Object and a mimeType string.
+ */
+class DataHandlerDataSource implements DataSource {
+    DataHandler dataHandler = null;
+
+    /**
+     * The constructor.
+     */
+    public DataHandlerDataSource(DataHandler dh) {
+	this.dataHandler = dh;
+    }
+
+    /**
+     * Returns an <code>InputStream</code> representing this object.
+     * @return	the <code>InputStream</code>
+     */
+    public InputStream getInputStream() throws IOException {
+	return dataHandler.getInputStream();
+    }
+
+    /**
+     * Returns the <code>OutputStream</code> for this object.
+     * @return	the <code>OutputStream</code>
+     */
+    public OutputStream getOutputStream() throws IOException {
+	return dataHandler.getOutputStream();
+    }
+
+    /**
+     * Returns the MIME type of the data represented by this object.
+     * @return	the MIME type
+     */
+    public String getContentType() {
+	return dataHandler.getContentType();
+    }
+
+    /**
+     * Returns the name of this object.
+     * @return	the name of this object
+     */
+    public String getName() {
+	return dataHandler.getName(); // what else would it be?
+    }
+}
+
+/*
+ * DataSourceDataContentHandler
+ *
+ * This is a <i>private</i> DataContentHandler that wraps the real
+ * DataContentHandler in the case where the DataHandler was instantiated
+ * with a DataSource.
+ */
+class DataSourceDataContentHandler implements DataContentHandler {
+    private DataSource ds = null;
+    private DataFlavor transferFlavors[] = null;
+    private DataContentHandler dch = null;
+
+    /**
+     * The constructor.
+     */
+    public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
+	this.ds = ds;
+	this.dch = dch;
+    }
+
+    /**
+     * Return the DataFlavors for this <code>DataContentHandler</code>.
+     * @return	the DataFlavors
+     */
+    public DataFlavor[] getTransferDataFlavors() {
+
+	if (transferFlavors == null) {
+	    if (dch != null) { // is there a dch?
+		transferFlavors = dch.getTransferDataFlavors();
+	    } else {
+		transferFlavors = new DataFlavor[1];
+		transferFlavors[0] =
+		    new ActivationDataFlavor(ds.getContentType(),
+					     ds.getContentType());
+	    }
+	}
+	return transferFlavors;
+    }
+
+    /**
+     * Return the Transfer Data of type DataFlavor from InputStream.
+     * @param df	the DataFlavor
+     * @param ds	the DataSource
+     * @return		the constructed Object
+     */
+    public Object getTransferData(DataFlavor df, DataSource ds) throws
+				UnsupportedFlavorException, IOException {
+
+	if (dch != null)
+	    return dch.getTransferData(df, ds);
+	else if (df.equals(getTransferDataFlavors()[0])) // only have one now
+	    return ds.getInputStream();
+	else
+	    throw new UnsupportedFlavorException(df);
+    }
+
+    public Object getContent(DataSource ds) throws IOException {
+
+	if (dch != null)
+	    return dch.getContent(ds);
+	else
+	    return ds.getInputStream();
+    }
+
+    /**
+     * Write the object to the output stream.
+     */
+    public void writeTo(Object obj, String mimeType, OutputStream os)
+						throws IOException {
+	if (dch != null)
+	    dch.writeTo(obj, mimeType, os);
+	else
+	    throw new UnsupportedDataTypeException(
+			"no DCH for content type " + ds.getContentType());
+    }
+}
+
+/*
+ * ObjectDataContentHandler
+ *
+ * This is a <i>private</i> DataContentHandler that wraps the real
+ * DataContentHandler in the case where the DataHandler was instantiated
+ * with an object.
+ */
+class ObjectDataContentHandler implements DataContentHandler {
+    private DataFlavor transferFlavors[] = null;
+    private Object obj;
+    private String mimeType;
+    private DataContentHandler dch = null;
+
+    /**
+     * The constructor.
+     */
+    public ObjectDataContentHandler(DataContentHandler dch,
+				    Object obj, String mimeType) {
+	this.obj = obj;
+	this.mimeType = mimeType;
+	this.dch = dch;
+    }
+
+    /**
+     * Return the DataContentHandler for this object.
+     * Used only by the DataHandler class.
+     */
+    public DataContentHandler getDCH() {
+	return dch;
+    }
+
+    /**
+     * Return the DataFlavors for this <code>DataContentHandler</code>.
+     * @return	the DataFlavors
+     */
+    public synchronized DataFlavor[] getTransferDataFlavors() {
+	if (transferFlavors == null) {
+	    if (dch != null) {
+		transferFlavors = dch.getTransferDataFlavors();
+	    } else {
+		transferFlavors = new DataFlavor[1];
+		transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
+					     mimeType, mimeType);
+	    }
+	}
+	return transferFlavors;
+    }
+
+    /**
+     * Return the Transfer Data of type DataFlavor from InputStream.
+     * @param df	the DataFlavor
+     * @param ds	the DataSource
+     * @return		the constructed Object
+     */
+    public Object getTransferData(DataFlavor df, DataSource ds)
+				throws UnsupportedFlavorException, IOException {
+
+	if (dch != null)
+	    return dch.getTransferData(df, ds);
+	else if (df.equals(getTransferDataFlavors()[0])) // only have one now
+	    return obj;
+	else
+	    throw new UnsupportedFlavorException(df);
+
+    }
+
+    public Object getContent(DataSource ds) {
+	return obj;
+    }
+
+    /**
+     * Write the object to the output stream.
+     */
+    public void writeTo(Object obj, String mimeType, OutputStream os)
+						throws IOException {
+	if (dch != null)
+	    dch.writeTo(obj, mimeType, os);
+	else if (obj instanceof byte[])
+	    os.write((byte[])obj);
+	else if (obj instanceof String) {
+	    OutputStreamWriter osw = new OutputStreamWriter(os);
+	    osw.write((String)obj);
+	    osw.flush();
+	} else
+	    throw new UnsupportedDataTypeException(
+				"no object DCH for MIME type " + this.mimeType);
+    }
+}
diff --git a/activation/src/main/java/javax/activation/DataSource.java b/activation/src/main/java/javax/activation/DataSource.java
new file mode 100644
index 0000000..320d8ae
--- /dev/null
+++ b/activation/src/main/java/javax/activation/DataSource.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The DataSource interface provides Jakarta Activation
+ * with an abstraction of an arbitrary collection of data.  It
+ * provides a type for that data as well as access
+ * to it in the form of <code>InputStreams</code> and
+ * <code>OutputStreams</code> where appropriate.
+ */
+
+public interface DataSource {
+
+    /**
+     * This method returns an <code>InputStream</code> representing
+     * the data and throws the appropriate exception if it can
+     * not do so.  Note that a new <code>InputStream</code> object must be
+     * returned each time this method is called, and the stream must be
+     * positioned at the beginning of the data.
+     *
+     * @return an InputStream
+     * @exception	IOException	for failures creating the InputStream
+     */
+    public InputStream getInputStream() throws IOException;
+
+    /**
+     * This method returns an <code>OutputStream</code> where the
+     * data can be written and throws the appropriate exception if it can
+     * not do so.  Note that a new <code>OutputStream</code> object must
+     * be returned each time this method is called, and the stream must
+     * be positioned at the location the data is to be written.
+     *
+     * @return an OutputStream
+     * @exception	IOException	for failures creating the OutputStream
+     */
+    public OutputStream getOutputStream() throws IOException;
+
+    /**
+     * This method returns the MIME type of the data in the form of a
+     * string. It should always return a valid type. It is suggested
+     * that getContentType return "application/octet-stream" if the
+     * DataSource implementation can not determine the data type.
+     *
+     * @return the MIME Type
+     */
+    public String getContentType();
+
+    /**
+     * Return the <i>name</i> of this object where the name of the object
+     * is dependant on the nature of the underlying objects. DataSources
+     * encapsulating files may choose to return the filename of the object.
+     * (Typically this would be the last component of the filename, not an
+     * entire pathname.)
+     *
+     * @return the name of the object.
+     */
+    public String getName();
+}
diff --git a/activation/src/main/java/javax/activation/FileDataSource.java b/activation/src/main/java/javax/activation/FileDataSource.java
new file mode 100644
index 0000000..3048918
--- /dev/null
+++ b/activation/src/main/java/javax/activation/FileDataSource.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import com.sun.activation.registries.MimeTypeFile;
+
+/**
+ * The FileDataSource class implements a simple DataSource object
+ * that encapsulates a file. It provides data typing services via
+ * a FileTypeMap object. <p>
+ *
+ * <b>FileDataSource Typing Semantics</b><p>
+ *
+ * The FileDataSource class delegates data typing of files
+ * to an object subclassed from the FileTypeMap class.
+ * The <code>setFileTypeMap</code> method can be used to explicitly
+ * set the FileTypeMap for an instance of FileDataSource. If no
+ * FileTypeMap is set, the FileDataSource will call the FileTypeMap's
+ * getDefaultFileTypeMap method to get the System's default FileTypeMap.
+ *
+ * @see javax.activation.DataSource
+ * @see javax.activation.FileTypeMap
+ * @see javax.activation.MimetypesFileTypeMap
+ */
+public class FileDataSource implements DataSource {
+
+    // keep track of original 'ref' passed in, non-null
+    // one indicated which was passed in:
+    private File _file = null;
+    private FileTypeMap typeMap = null;
+
+    /**
+     * Creates a FileDataSource from a File object. <i>Note:
+     * The file will not actually be opened until a method is
+     * called that requires the file to be opened.</i>
+     *
+     * @param file the file
+     */
+    public FileDataSource(File file) {
+	_file = file;	// save the file Object...
+    }
+
+    /**
+     * Creates a FileDataSource from
+     * the specified path name. <i>Note:
+     * The file will not actually be opened until a method is
+     * called that requires the file to be opened.</i>
+     *
+     * @param name the system-dependent file name.
+     */
+    public FileDataSource(String name) {
+	this(new File(name));	// use the file constructor
+    }
+
+    /**
+     * This method will return an InputStream representing the
+     * the data and will throw an IOException if it can
+     * not do so. This method will return a new
+     * instance of InputStream with each invocation.
+     *
+     * @return an InputStream
+     */
+    public InputStream getInputStream() throws IOException {
+	return new FileInputStream(_file);
+    }
+
+    /**
+     * This method will return an OutputStream representing the
+     * the data and will throw an IOException if it can
+     * not do so. This method will return a new instance of
+     * OutputStream with each invocation.
+     *
+     * @return an OutputStream
+     */
+    public OutputStream getOutputStream() throws IOException {
+	return new FileOutputStream(_file);
+    }
+
+    /**
+     * This method returns the MIME type of the data in the form of a
+     * string. This method uses the currently installed FileTypeMap. If
+     * there is no FileTypeMap explictly set, the FileDataSource will
+     * call the <code>getDefaultFileTypeMap</code> method on
+     * FileTypeMap to acquire a default FileTypeMap. <i>Note: By
+     * default, the FileTypeMap used will be a MimetypesFileTypeMap.</i>
+     *
+     * @return the MIME Type
+     * @see javax.activation.FileTypeMap#getDefaultFileTypeMap
+     */
+    public String getContentType() {
+	// check to see if the type map is null?
+	if (typeMap == null)
+	    return FileTypeMap.getDefaultFileTypeMap().getContentType(_file);
+	else
+	    return typeMap.getContentType(_file);
+    }
+
+    /**
+     * Return the <i>name</i> of this object. The FileDataSource
+     * will return the file name of the object.
+     *
+     * @return the name of the object.
+     * @see javax.activation.DataSource
+     */
+    public String getName() {
+	return _file.getName();
+    }
+
+    /**
+     * Return the File object that corresponds to this FileDataSource.
+     * @return the File object for the file represented by this object.
+     */
+    public File getFile() {
+	return _file;
+    }
+
+    /**
+     * Set the FileTypeMap to use with this FileDataSource
+     *
+     * @param map The FileTypeMap for this object.
+     */
+    public void setFileTypeMap(FileTypeMap map) {
+	typeMap = map;
+    }
+}
diff --git a/activation/src/main/java/javax/activation/FileTypeMap.java b/activation/src/main/java/javax/activation/FileTypeMap.java
new file mode 100644
index 0000000..683f998
--- /dev/null
+++ b/activation/src/main/java/javax/activation/FileTypeMap.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.File;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * The FileTypeMap is an abstract class that provides a data typing
+ * interface for files. Implementations of this class will
+ * implement the getContentType methods which will derive a content
+ * type from a file name or a File object. FileTypeMaps could use any
+ * scheme to determine the data type, from examining the file extension
+ * of a file (like the MimetypesFileTypeMap) to opening the file and
+ * trying to derive its type from the contents of the file. The
+ * FileDataSource class uses the default FileTypeMap (a MimetypesFileTypeMap
+ * unless changed) to determine the content type of files.
+ *
+ * @see javax.activation.FileTypeMap
+ * @see javax.activation.FileDataSource
+ * @see javax.activation.MimetypesFileTypeMap
+ */
+
+public abstract class FileTypeMap {
+
+    private static FileTypeMap defaultMap = null;
+    private static Map<ClassLoader,FileTypeMap> map =
+				new WeakHashMap<ClassLoader,FileTypeMap>();
+
+    /**
+     * The default constructor.
+     */
+    public FileTypeMap() {
+	super();
+    }
+
+    /**
+     * Return the type of the file object. This method should
+     * always return a valid MIME type.
+     *
+     * @param file A file to be typed.
+     * @return The content type.
+     */
+    abstract public String getContentType(File file);
+
+    /**
+     * Return the type of the file passed in.  This method should
+     * always return a valid MIME type.
+     *
+     * @param filename the pathname of the file.
+     * @return The content type.
+     */
+    abstract public String getContentType(String filename);
+
+    /**
+     * Sets the default FileTypeMap for the system. This instance
+     * will be returned to callers of getDefaultFileTypeMap.
+     *
+     * @param fileTypeMap The FileTypeMap.
+     * @exception SecurityException if the caller doesn't have permission
+     *					to change the default
+     */
+    public static synchronized void setDefaultFileTypeMap(FileTypeMap fileTypeMap) {
+	SecurityManager security = System.getSecurityManager();
+	if (security != null) {
+	    try {
+		// if it's ok with the SecurityManager, it's ok with me...
+		security.checkSetFactory();
+	    } catch (SecurityException ex) {
+		// otherwise, we also allow it if this code and the
+		// factory come from the same (non-system) class loader (e.g.,
+		// the JAF classes were loaded with the applet classes).
+		ClassLoader cl = FileTypeMap.class.getClassLoader();
+		if (cl == null || cl.getParent() == null ||
+		    cl != fileTypeMap.getClass().getClassLoader())
+		    throw ex;
+	    }
+	}
+	// remove any per-thread-context-class-loader FileTypeMap
+	map.remove(SecuritySupport.getContextClassLoader());
+	defaultMap = fileTypeMap;	
+    }
+
+    /**
+     * Return the default FileTypeMap for the system.
+     * If setDefaultFileTypeMap was called, return
+     * that instance, otherwise return an instance of
+     * <code>MimetypesFileTypeMap</code>.
+     *
+     * @return The default FileTypeMap
+     * @see javax.activation.FileTypeMap#setDefaultFileTypeMap
+     */
+    public static synchronized FileTypeMap getDefaultFileTypeMap() {
+	if (defaultMap != null)
+	    return defaultMap;
+
+	// fetch per-thread-context-class-loader default
+	ClassLoader tccl = SecuritySupport.getContextClassLoader();
+	FileTypeMap def = map.get(tccl);
+	if (def == null) {
+	    def = new MimetypesFileTypeMap();
+	    map.put(tccl, def);
+	}
+	return def;
+    }
+}
diff --git a/activation/src/main/java/javax/activation/MailcapCommandMap.java b/activation/src/main/java/javax/activation/MailcapCommandMap.java
new file mode 100644
index 0000000..f5e0672
--- /dev/null
+++ b/activation/src/main/java/javax/activation/MailcapCommandMap.java
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import com.sun.activation.registries.MailcapFile;
+import com.sun.activation.registries.LogSupport;
+
+/**
+ * MailcapCommandMap extends the CommandMap
+ * abstract class. It implements a CommandMap whose configuration
+ * is based on mailcap files
+ * (<A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>).
+ * The MailcapCommandMap can be configured both programmatically
+ * and via configuration files.
+ * <p>
+ * <b>Mailcap file search order:</b><p>
+ * The MailcapCommandMap looks in various places in the user's
+ * system for mailcap file entries. When requests are made
+ * to search for commands in the MailcapCommandMap, it searches  
+ * mailcap files in the following order:
+ * <ol>
+ * <li> Programatically added entries to the MailcapCommandMap instance.
+ * <li> The file <code>.mailcap</code> in the user's home directory.
+ * <li> The file <code>mailcap</code> in the Java runtime.
+ * <li> The file or resources named <code>META-INF/mailcap</code>.
+ * <li> The file or resource named <code>META-INF/mailcap.default</code>
+ * (usually found only in the <code>activation.jar</code> file).
+ * </ol>
+ * <p>
+ * (The current implementation looks for the <code>mailcap</code> file
+ * in the Java runtime in the directory <code><i>java.home</i>/conf</code>
+ * if it exists, and otherwise in the directory
+ * <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
+ * of the "java.home" System property.  Note that the "conf" directory was
+ * introduced in JDK 9.)
+ * <p>
+ * <b>Mailcap file format:</b><p>
+ *
+ * Mailcap files must conform to the mailcap
+ * file specification (RFC 1524, <i>A User Agent Configuration Mechanism
+ * For Multimedia Mail Format Information</i>). 
+ * The file format consists of entries corresponding to
+ * particular MIME types. In general, the specification 
+ * specifies <i>applications</i> for clients to use when they
+ * themselves cannot operate on the specified MIME type. The 
+ * MailcapCommandMap extends this specification by using a parameter mechanism
+ * in mailcap files that allows JavaBeans(tm) components to be specified as
+ * corresponding to particular commands for a MIME type.<p>
+ *
+ * When a mailcap file is
+ * parsed, the MailcapCommandMap recognizes certain parameter signatures,
+ * specifically those parameter names that begin with <code>x-java-</code>.
+ * The MailcapCommandMap uses this signature to find
+ * command entries for inclusion into its registries.
+ * Parameter names with the form <code>x-java-&lt;name&gt;</code>
+ * are read by the MailcapCommandMap as identifying a command
+ * with the name <i>name</i>. When the <i>name</i> is <code>
+ * content-handler</code> the MailcapCommandMap recognizes the class
+ * signified by this parameter as a <i>DataContentHandler</i>.
+ * All other commands are handled generically regardless of command 
+ * name. The command implementation is specified by a fully qualified
+ * class name of a JavaBean(tm) component. For example; a command for viewing
+ * some data can be specified as: <code>x-java-view=com.foo.ViewBean</code>.<p>
+ *
+ * When the command name is <code>fallback-entry</code>, the value of
+ * the command may be <code>true</code> or <code>false</code>.  An
+ * entry for a MIME type that includes a parameter of
+ * <code>x-java-fallback-entry=true</code> defines fallback commands
+ * for that MIME type that will only be used if no non-fallback entry
+ * can be found.  For example, an entry of the form <code>text/*; ;
+ * x-java-fallback-entry=true; x-java-view=com.sun.TextViewer</code>
+ * specifies a view command to be used for any text MIME type.  This
+ * view command would only be used if a non-fallback view command for
+ * the MIME type could not be found.<p>
+ * 
+ * MailcapCommandMap aware mailcap files have the 
+ * following general form:<p>
+ * <code>
+ * # Comments begin with a '#' and continue to the end of the line.<br>
+ * &lt;mime type&gt;; ; &lt;parameter list&gt;<br>
+ * # Where a parameter list consists of one or more parameters,<br>
+ * # where parameters look like: x-java-view=com.sun.TextViewer<br>
+ * # and a parameter list looks like: <br>
+ * text/plain; ; x-java-view=com.sun.TextViewer; x-java-edit=com.sun.TextEdit
+ * <br>
+ * # Note that mailcap entries that do not contain 'x-java' parameters<br>
+ * # and comply to RFC 1524 are simply ignored:<br>
+ * image/gif; /usr/dt/bin/sdtimage %s<br>
+ *
+ * </code>
+ * <p>
+ *
+ * @author Bart Calder
+ * @author Bill Shannon
+ */
+
+public class MailcapCommandMap extends CommandMap {
+    /*
+     * We manage a collection of databases, searched in order.
+     */
+    private MailcapFile[] DB;
+    private static final int PROG = 0;	// programmatically added entries
+
+    private static final String confDir;
+
+    static {
+	String dir = null;
+	try {
+	    dir = (String)AccessController.doPrivileged(
+		new PrivilegedAction() {
+		    public Object run() {
+			String home = System.getProperty("java.home");
+			String newdir = home + File.separator + "conf";
+			File conf = new File(newdir);
+			if (conf.exists())
+			    return newdir + File.separator;
+			else
+			    return home + File.separator + "lib" + File.separator;
+		    }
+		});
+	} catch (Exception ex) {
+	    // ignore any exceptions
+	}
+	confDir = dir;
+    }
+
+    /**
+     * The default Constructor.
+     */
+    public MailcapCommandMap() {
+	super();
+	List dbv = new ArrayList(5);	// usually 5 or less databases
+	MailcapFile mf = null;
+	dbv.add(null);		// place holder for PROG entry
+
+	LogSupport.log("MailcapCommandMap: load HOME");
+	try {
+	    String user_home = System.getProperty("user.home");
+
+	    if (user_home != null) {
+		String path = user_home + File.separator + ".mailcap";
+		mf = loadFile(path);
+		if (mf != null)
+		    dbv.add(mf);
+	    }
+	} catch (SecurityException ex) {}
+
+	LogSupport.log("MailcapCommandMap: load SYS");
+	try {
+	    // check system's home
+	    if (confDir != null) {
+		mf = loadFile(confDir + "mailcap");
+		if (mf != null)
+		    dbv.add(mf);
+	    }
+	} catch (SecurityException ex) {}
+
+	LogSupport.log("MailcapCommandMap: load JAR");
+	// load from the app's jar file
+	loadAllResources(dbv, "META-INF/mailcap");
+
+	LogSupport.log("MailcapCommandMap: load DEF");
+	mf = loadResource("/META-INF/mailcap.default");
+
+	if (mf != null)
+	    dbv.add(mf);
+
+	DB = new MailcapFile[dbv.size()];
+	DB = (MailcapFile[])dbv.toArray(DB);
+    }
+
+    /**
+     * Load from the named resource.
+     */
+    private MailcapFile loadResource(String name) {
+	InputStream clis = null;
+	try {
+	    clis = SecuritySupport.getResourceAsStream(this.getClass(), name);
+	    if (clis != null) {
+		MailcapFile mf = new MailcapFile(clis);
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MailcapCommandMap: successfully loaded " +
+			"mailcap file: " + name);
+		return mf;
+	    } else {
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MailcapCommandMap: not loading " +
+			"mailcap file: " + name);
+	    }
+	} catch (IOException e) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MailcapCommandMap: can't load " + name, e);
+	} catch (SecurityException sex) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MailcapCommandMap: can't load " + name, sex);
+	} finally {
+	    try {
+		if (clis != null)
+		    clis.close();
+	    } catch (IOException ex) { }	// ignore it
+	}
+	return null;
+    }
+
+    /**
+     * Load all of the named resource.
+     */
+    private void loadAllResources(List v, String name) {
+	boolean anyLoaded = false;
+	try {
+	    URL[] urls;
+	    ClassLoader cld = null;
+	    // First try the "application's" class loader.
+	    cld = SecuritySupport.getContextClassLoader();
+	    if (cld == null)
+		cld = this.getClass().getClassLoader();
+	    if (cld != null)
+		urls = SecuritySupport.getResources(cld, name);
+	    else
+		urls = SecuritySupport.getSystemResources(name);
+	    if (urls != null) {
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MailcapCommandMap: getResources");
+		for (int i = 0; i < urls.length; i++) {
+		    URL url = urls[i];
+		    InputStream clis = null;
+		    if (LogSupport.isLoggable())
+			LogSupport.log("MailcapCommandMap: URL " + url);
+		    try {
+			clis = SecuritySupport.openStream(url);
+			if (clis != null) {
+			    v.add(new MailcapFile(clis));
+			    anyLoaded = true;
+			    if (LogSupport.isLoggable())
+				LogSupport.log("MailcapCommandMap: " +
+				    "successfully loaded " +
+				    "mailcap file from URL: " +
+				    url);
+			} else {
+			    if (LogSupport.isLoggable())
+				LogSupport.log("MailcapCommandMap: " +
+				    "not loading mailcap " +
+				    "file from URL: " + url);
+			}
+		    } catch (IOException ioex) {
+			if (LogSupport.isLoggable())
+			    LogSupport.log("MailcapCommandMap: can't load " +
+						url, ioex);
+		    } catch (SecurityException sex) {
+			if (LogSupport.isLoggable())
+			    LogSupport.log("MailcapCommandMap: can't load " +
+						url, sex);
+		    } finally {
+			try {
+			    if (clis != null)
+				clis.close();
+			} catch (IOException cex) { }
+		    }
+		}
+	    }
+	} catch (Exception ex) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MailcapCommandMap: can't load " + name, ex);
+	}
+
+	// if failed to load anything, fall back to old technique, just in case
+	if (!anyLoaded) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MailcapCommandMap: !anyLoaded");
+	    MailcapFile mf = loadResource("/" + name);
+	    if (mf != null)
+		v.add(mf);
+	}
+    }
+
+    /**
+     * Load from the named file.
+     */
+    private MailcapFile loadFile(String name) {
+	MailcapFile mtf = null;
+
+	try {
+	    mtf = new MailcapFile(name);
+	} catch (IOException e) {
+	    //	e.printStackTrace();
+	}
+	return mtf;
+    }
+
+    /**
+     * Constructor that allows the caller to specify the path
+     * of a <i>mailcap</i> file.
+     *
+     * @param fileName The name of the <i>mailcap</i> file to open
+     * @exception	IOException	if the file can't be accessed
+     */
+    public MailcapCommandMap(String fileName) throws IOException {
+	this();
+
+	if (LogSupport.isLoggable())
+	    LogSupport.log("MailcapCommandMap: load PROG from " + fileName);
+	if (DB[PROG] == null) {
+	    DB[PROG] = new MailcapFile(fileName);
+	}
+    }
+
+
+    /**
+     * Constructor that allows the caller to specify an <i>InputStream</i>
+     * containing a mailcap file.
+     *
+     * @param is	InputStream of the <i>mailcap</i> file to open
+     */
+    public MailcapCommandMap(InputStream is) {
+	this();
+
+	LogSupport.log("MailcapCommandMap: load PROG");
+	if (DB[PROG] == null) {
+	    try {
+		DB[PROG] = new MailcapFile(is);
+	    } catch (IOException ex) {
+		// XXX - should throw it
+	    }
+	}
+    }
+
+    /**
+     * Get the preferred command list for a MIME Type. The MailcapCommandMap
+     * searches the mailcap files as described above under
+     * <i>Mailcap file search order</i>.<p>
+     *
+     * The result of the search is a proper subset of available
+     * commands in all mailcap files known to this instance of 
+     * MailcapCommandMap.  The first entry for a particular command
+     * is considered the preferred command.
+     *
+     * @param mimeType	the MIME type
+     * @return the CommandInfo objects representing the preferred commands.
+     */
+    public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
+	List cmdList = new ArrayList();
+	if (mimeType != null)
+	    mimeType = mimeType.toLowerCase(Locale.ENGLISH);
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapList(mimeType);
+	    if (cmdMap != null)
+		appendPrefCmdsToList(cmdMap, cmdList);
+	}
+
+	// now add the fallback commands
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
+	    if (cmdMap != null)
+		appendPrefCmdsToList(cmdMap, cmdList);
+	}
+
+	CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
+	cmdInfos = (CommandInfo[])cmdList.toArray(cmdInfos);
+
+	return cmdInfos;
+    }
+
+    /**
+     * Put the commands that are in the hash table, into the list.
+     */
+    private void appendPrefCmdsToList(Map cmdHash, List cmdList) {
+	Iterator verb_enum = cmdHash.keySet().iterator();
+
+	while (verb_enum.hasNext()) {
+	    String verb = (String)verb_enum.next();
+	    if (!checkForVerb(cmdList, verb)) {
+		List cmdList2 = (List)cmdHash.get(verb); // get the list
+		String className = (String)cmdList2.get(0);
+		cmdList.add(new CommandInfo(verb, className));
+	    }
+	}
+    }
+
+    /**
+     * Check the cmdList to see if this command exists, return
+     * true if the verb is there.
+     */
+    private boolean checkForVerb(List cmdList, String verb) {
+	Iterator ee = cmdList.iterator();
+	while (ee.hasNext()) {
+	    String enum_verb =
+		(String)((CommandInfo)ee.next()).getCommandName();
+	    if (enum_verb.equals(verb))
+		return true;
+	}
+	return false;
+    }
+
+    /**
+     * Get all the available commands in all mailcap files known to
+     * this instance of MailcapCommandMap for this MIME type.
+     *
+     * @param mimeType	the MIME type
+     * @return the CommandInfo objects representing all the commands.
+     */
+    public synchronized CommandInfo[] getAllCommands(String mimeType) {
+	List cmdList = new ArrayList();
+	if (mimeType != null)
+	    mimeType = mimeType.toLowerCase(Locale.ENGLISH);
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapList(mimeType);
+	    if (cmdMap != null)
+		appendCmdsToList(cmdMap, cmdList);
+	}
+
+	// now add the fallback commands
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
+	    if (cmdMap != null)
+		appendCmdsToList(cmdMap, cmdList);
+	}
+
+	CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
+	cmdInfos = (CommandInfo[])cmdList.toArray(cmdInfos);
+
+	return cmdInfos;
+    }
+
+    /**
+     * Put the commands that are in the hash table, into the list.
+     */
+    private void appendCmdsToList(Map typeHash, List cmdList) {
+	Iterator verb_enum = typeHash.keySet().iterator();
+
+	while (verb_enum.hasNext()) {
+	    String verb = (String)verb_enum.next();
+	    List cmdList2 = (List)typeHash.get(verb);
+	    Iterator cmd_enum = ((List)cmdList2).iterator();
+
+	    while (cmd_enum.hasNext()) {
+		String cmd = (String)cmd_enum.next();
+		cmdList.add(new CommandInfo(verb, cmd));
+		// cmdList.add(0, new CommandInfo(verb, cmd));
+	    }
+	}
+    }
+
+    /**
+     * Get the command corresponding to <code>cmdName</code> for the MIME type.
+     *
+     * @param mimeType	the MIME type
+     * @param cmdName	the command name
+     * @return the CommandInfo object corresponding to the command.
+     */
+    public synchronized CommandInfo getCommand(String mimeType,
+							String cmdName) {
+	if (mimeType != null)
+	    mimeType = mimeType.toLowerCase(Locale.ENGLISH);
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapList(mimeType);
+	    if (cmdMap != null) {
+		// get the cmd list for the cmd
+		List v = (List)cmdMap.get(cmdName);
+		if (v != null) {
+		    String cmdClassName = (String)v.get(0);
+
+		    if (cmdClassName != null)
+			return new CommandInfo(cmdName, cmdClassName);
+		}
+	    }
+	}
+
+	// now try the fallback list
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
+	    if (cmdMap != null) {
+		// get the cmd list for the cmd
+		List v = (List)cmdMap.get(cmdName);
+		if (v != null) {
+		    String cmdClassName = (String)v.get(0);
+
+		    if (cmdClassName != null)
+			return new CommandInfo(cmdName, cmdClassName);
+		}
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * Add entries to the registry.  Programmatically 
+     * added entries are searched before other entries.<p>
+     *
+     * The string that is passed in should be in mailcap
+     * format.
+     *
+     * @param mail_cap a correctly formatted mailcap string
+     */
+    public synchronized void addMailcap(String mail_cap) {
+	// check to see if one exists
+	LogSupport.log("MailcapCommandMap: add to PROG");
+	if (DB[PROG] == null)
+	    DB[PROG] = new MailcapFile();
+
+	DB[PROG].appendToMailcap(mail_cap);
+    }
+
+    /**
+     * Return the DataContentHandler for the specified MIME type.
+     *
+     * @param mimeType	the MIME type
+     * @return		the DataContentHandler
+     */
+    public synchronized DataContentHandler createDataContentHandler(
+							String mimeType) {
+	if (LogSupport.isLoggable())
+	    LogSupport.log(
+		"MailcapCommandMap: createDataContentHandler for " + mimeType);
+	if (mimeType != null)
+	    mimeType = mimeType.toLowerCase(Locale.ENGLISH);
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    if (LogSupport.isLoggable())
+		LogSupport.log("  search DB #" + i);
+	    Map cmdMap = DB[i].getMailcapList(mimeType);
+	    if (cmdMap != null) {
+		List v = (List)cmdMap.get("content-handler");
+		if (v != null) {
+		    String name = (String)v.get(0);
+		    DataContentHandler dch = getDataContentHandler(name);
+		    if (dch != null)
+			return dch;
+		}
+	    }
+	}
+
+	// now try the fallback entries
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    if (LogSupport.isLoggable())
+		LogSupport.log("  search fallback DB #" + i);
+	    Map cmdMap = DB[i].getMailcapFallbackList(mimeType);
+	    if (cmdMap != null) {
+		List v = (List)cmdMap.get("content-handler");
+		if (v != null) {
+		    String name = (String)v.get(0);
+		    DataContentHandler dch = getDataContentHandler(name);
+		    if (dch != null)
+			return dch;
+		}
+	    }
+	}
+	return null;
+    }
+
+    private DataContentHandler getDataContentHandler(String name) {
+	if (LogSupport.isLoggable())
+	    LogSupport.log("    got content-handler");
+	if (LogSupport.isLoggable())
+	    LogSupport.log("      class " + name);
+	try {
+	    ClassLoader cld = null;
+	    // First try the "application's" class loader.
+	    cld = SecuritySupport.getContextClassLoader();
+	    if (cld == null)
+		cld = this.getClass().getClassLoader();
+	    Class cl = null;
+	    try {
+		cl = cld.loadClass(name);
+	    } catch (Exception ex) {
+		// if anything goes wrong, do it the old way
+		cl = Class.forName(name);
+	    }
+	    if (cl != null)		// XXX - always true?
+		return (DataContentHandler)cl.newInstance();
+	} catch (IllegalAccessException e) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("Can't load DCH " + name, e);
+	} catch (ClassNotFoundException e) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("Can't load DCH " + name, e);
+	} catch (InstantiationException e) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("Can't load DCH " + name, e);
+	}
+	return null;
+    }
+
+    /**
+     * Get all the MIME types known to this command map.
+     *
+     * @return		array of MIME types as strings
+     * @since	JAF 1.1
+     */
+    public synchronized String[] getMimeTypes() {
+	List mtList = new ArrayList();
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    String[] ts = DB[i].getMimeTypes();
+	    if (ts != null) {
+		for (int j = 0; j < ts.length; j++) {
+		    // eliminate duplicates
+		    if (!mtList.contains(ts[j]))
+			mtList.add(ts[j]);
+		}
+	    }
+	}
+
+	String[] mts = new String[mtList.size()];
+	mts = (String[])mtList.toArray(mts);
+
+	return mts;
+    }
+
+    /**
+     * Get the native commands for the given MIME type.
+     * Returns an array of strings where each string is
+     * an entire mailcap file entry.  The application
+     * will need to parse the entry to extract the actual
+     * command as well as any attributes it needs. See
+     * <A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>
+     * for details of the mailcap entry syntax.  Only mailcap
+     * entries that specify a view command for the specified
+     * MIME type are returned.
+     *
+     * @param	mimeType	the MIME type
+     * @return		array of native command entries
+     * @since	JAF 1.1
+     */
+    public synchronized String[] getNativeCommands(String mimeType) {
+	List cmdList = new ArrayList();
+	if (mimeType != null)
+	    mimeType = mimeType.toLowerCase(Locale.ENGLISH);
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    String[] cmds = DB[i].getNativeCommands(mimeType);
+	    if (cmds != null) {
+		for (int j = 0; j < cmds.length; j++) {
+		    // eliminate duplicates
+		    if (!cmdList.contains(cmds[j]))
+			cmdList.add(cmds[j]);
+		}
+	    }
+	}
+
+	String[] cmds = new String[cmdList.size()];
+	cmds = (String[])cmdList.toArray(cmds);
+
+	return cmds;
+    }
+
+    /**
+     * for debugging...
+     *
+    public static void main(String[] argv) throws Exception {
+	MailcapCommandMap map = new MailcapCommandMap();
+	CommandInfo[] cmdInfo;
+
+	cmdInfo = map.getPreferredCommands(argv[0]);
+	System.out.println("Preferred Commands:");
+	for (int i = 0; i < cmdInfo.length; i++)
+	    System.out.println("Command " + cmdInfo[i].getCommandName() + " [" +
+					    cmdInfo[i].getCommandClass() + "]");
+	cmdInfo = map.getAllCommands(argv[0]);
+	System.out.println();
+	System.out.println("All Commands:");
+	for (int i = 0; i < cmdInfo.length; i++)
+	    System.out.println("Command " + cmdInfo[i].getCommandName() + " [" +
+					    cmdInfo[i].getCommandClass() + "]");
+	DataContentHandler dch = map.createDataContentHandler(argv[0]);
+	if (dch != null)
+	    System.out.println("DataContentHandler " +
+						dch.getClass().toString());
+	System.exit(0);
+    }
+    */
+}
diff --git a/activation/src/main/java/javax/activation/MimeType.java b/activation/src/main/java/javax/activation/MimeType.java
new file mode 100644
index 0000000..49fe6e5
--- /dev/null
+++ b/activation/src/main/java/javax/activation/MimeType.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.*;
+import java.util.Locale;
+
+/**
+ * A Multipurpose Internet Mail Extension (MIME) type, as defined
+ * in RFC 2045 and 2046.
+ */
+public class MimeType implements Externalizable {
+
+    private String    primaryType;
+    private String    subType;
+    private MimeTypeParameterList parameters;
+
+    /**
+     * A string that holds all the special chars.
+     */
+    private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
+
+    /**
+     * Default constructor.
+     */
+    public MimeType() {
+        primaryType = "application";
+        subType = "*";
+        parameters = new MimeTypeParameterList();
+    }
+
+    /**
+     * Constructor that builds a MimeType from a String.
+     *
+     * @param rawdata	the MIME type string
+     * @exception	MimeTypeParseException	if the MIME type can't be parsed
+     */
+    public MimeType(String rawdata) throws MimeTypeParseException {
+        parse(rawdata);
+    }
+
+    /**
+     * Constructor that builds a MimeType with the given primary and sub type
+     * but has an empty parameter list.
+     *
+     * @param primary	the primary MIME type
+     * @param sub	the MIME sub-type
+     * @exception	MimeTypeParseException	if the primary type or subtype
+     *						is not a valid token
+     */
+    public MimeType(String primary, String sub) throws MimeTypeParseException {
+        //    check to see if primary is valid
+        if (isValidToken(primary)) {
+            primaryType = primary.toLowerCase(Locale.ENGLISH);
+        } else {
+            throw new MimeTypeParseException("Primary type is invalid.");
+        }
+
+        //    check to see if sub is valid
+        if (isValidToken(sub)) {
+            subType = sub.toLowerCase(Locale.ENGLISH);
+        } else {
+            throw new MimeTypeParseException("Sub type is invalid.");
+        }
+
+        parameters = new MimeTypeParameterList();
+    }
+
+    /**
+     * A routine for parsing the MIME type out of a String.
+     */
+    private void parse(String rawdata) throws MimeTypeParseException {
+        int slashIndex = rawdata.indexOf('/');
+        int semIndex = rawdata.indexOf(';');
+        if ((slashIndex < 0) && (semIndex < 0)) {
+            //    neither character is present, so treat it
+            //    as an error
+            throw new MimeTypeParseException("Unable to find a sub type.");
+        } else if ((slashIndex < 0) && (semIndex >= 0)) {
+            //    we have a ';' (and therefore a parameter list),
+            //    but no '/' indicating a sub type is present
+            throw new MimeTypeParseException("Unable to find a sub type.");
+        } else if ((slashIndex >= 0) && (semIndex < 0)) {
+            //    we have a primary and sub type but no parameter list
+            primaryType = rawdata.substring(0, slashIndex).trim().
+						toLowerCase(Locale.ENGLISH);
+            subType = rawdata.substring(slashIndex + 1).trim().
+						toLowerCase(Locale.ENGLISH);
+            parameters = new MimeTypeParameterList();
+        } else if (slashIndex < semIndex) {
+            //    we have all three items in the proper sequence
+            primaryType = rawdata.substring(0, slashIndex).trim().
+						toLowerCase(Locale.ENGLISH);
+            subType = rawdata.substring(slashIndex + 1, semIndex).trim().
+						toLowerCase(Locale.ENGLISH);
+            parameters = new MimeTypeParameterList(rawdata.substring(semIndex));
+        } else {
+            // we have a ';' lexically before a '/' which means we
+	    // have a primary type and a parameter list but no sub type
+            throw new MimeTypeParseException("Unable to find a sub type.");
+        }
+
+        //    now validate the primary and sub types
+
+        //    check to see if primary is valid
+        if (!isValidToken(primaryType))
+            throw new MimeTypeParseException("Primary type is invalid.");
+
+        //    check to see if sub is valid
+        if (!isValidToken(subType))
+            throw new MimeTypeParseException("Sub type is invalid.");
+    }
+
+    /**
+     * Retrieve the primary type of this object.
+     *
+     * @return	the primary MIME type
+     */
+    public String getPrimaryType() {
+        return primaryType;
+    }
+
+    /**
+     * Set the primary type for this object to the given String.
+     *
+     * @param primary	the primary MIME type
+     * @exception	MimeTypeParseException	if the primary type
+     *						is not a valid token
+     */
+    public void setPrimaryType(String primary) throws MimeTypeParseException {
+        //    check to see if primary is valid
+        if (!isValidToken(primaryType))
+            throw new MimeTypeParseException("Primary type is invalid.");
+        primaryType = primary.toLowerCase(Locale.ENGLISH);
+    }
+
+    /**
+     * Retrieve the subtype of this object.
+     *
+     * @return	the MIME subtype
+     */
+    public String getSubType() {
+        return subType;
+    }
+
+    /**
+     * Set the subtype for this object to the given String.
+     *
+     * @param sub	the MIME subtype
+     * @exception	MimeTypeParseException	if the subtype
+     *						is not a valid token
+     */
+    public void setSubType(String sub) throws MimeTypeParseException {
+        //    check to see if sub is valid
+        if (!isValidToken(subType))
+            throw new MimeTypeParseException("Sub type is invalid.");
+        subType = sub.toLowerCase(Locale.ENGLISH);
+    }
+
+    /**
+     * Retrieve this object's parameter list.
+     *
+     * @return	a MimeTypeParameterList object representing the parameters
+     */
+    public MimeTypeParameterList getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Retrieve the value associated with the given name, or null if there
+     * is no current association.
+     *
+     * @param name	the parameter name
+     * @return		the paramter's value
+     */
+    public String getParameter(String name) {
+        return parameters.get(name);
+    }
+
+    /**
+     * Set the value to be associated with the given name, replacing
+     * any previous association.
+     *
+     * @param name	the parameter name
+     * @param value	the paramter's value
+     */
+    public void setParameter(String name, String value) {
+        parameters.set(name, value);
+    }
+
+    /**
+     * Remove any value associated with the given name.
+     *
+     * @param name	the parameter name
+     */
+    public void removeParameter(String name) {
+        parameters.remove(name);
+    }
+
+    /**
+     * Return the String representation of this object.
+     */
+    public String toString() {
+        return getBaseType() + parameters.toString();
+    }
+
+    /**
+     * Return a String representation of this object
+     * without the parameter list.
+     *
+     * @return	the MIME type and sub-type
+     */
+    public String getBaseType() {
+        return primaryType + "/" + subType;
+    }
+
+    /**
+     * Determine if the primary and sub type of this object is
+     * the same as what is in the given type.
+     *
+     * @param type	the MimeType object to compare with
+     * @return		true if they match
+     */
+    public boolean match(MimeType type) {
+        return primaryType.equals(type.getPrimaryType())
+                    && (subType.equals("*")
+                            || type.getSubType().equals("*")
+                            || (subType.equals(type.getSubType())));
+    }
+
+    /**
+     * Determine if the primary and sub type of this object is
+     * the same as the content type described in rawdata.
+     *
+     * @param rawdata	the MIME type string to compare with
+     * @return		true if they match
+     * @exception	MimeTypeParseException	if the MIME type can't be parsed
+     */
+    public boolean match(String rawdata) throws MimeTypeParseException {
+        return match(new MimeType(rawdata));
+    }
+
+    /**
+     * The object implements the writeExternal method to save its contents
+     * by calling the methods of DataOutput for its primitive values or
+     * calling the writeObject method of ObjectOutput for objects, strings
+     * and arrays.
+     *
+     * @param out	the ObjectOutput object to write to
+     * @exception IOException Includes any I/O exceptions that may occur
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeUTF(toString());
+	out.flush();
+    }
+
+    /**
+     * The object implements the readExternal method to restore its
+     * contents by calling the methods of DataInput for primitive
+     * types and readObject for objects, strings and arrays.  The
+     * readExternal method must read the values in the same sequence
+     * and with the same types as were written by writeExternal.
+     *
+     * @param in	the ObjectInput object to read from
+     * @exception ClassNotFoundException If the class for an object being
+     *              restored cannot be found.
+     */
+    public void readExternal(ObjectInput in)
+				throws IOException, ClassNotFoundException {
+        try {
+            parse(in.readUTF());
+        } catch (MimeTypeParseException e) {
+            throw new IOException(e.toString());
+        }
+    }
+
+    //    below here be scary parsing related things
+
+    /**
+     * Determine whether or not a given character belongs to a legal token.
+     */
+    private static boolean isTokenChar(char c) {
+        return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
+    }
+
+    /**
+     * Determine whether or not a given string is a legal token.
+     */
+    private boolean isValidToken(String s) {
+        int len = s.length();
+        if (len > 0) {
+            for (int i = 0; i < len; ++i) {
+                char c = s.charAt(i);
+                if (!isTokenChar(c)) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * A simple parser test,
+     * for debugging...
+     *
+    public static void main(String[] args)
+				throws MimeTypeParseException, IOException {
+        for (int i = 0; i < args.length; ++i) {
+            System.out.println("Original: " + args[i]);
+
+            MimeType type = new MimeType(args[i]);
+
+            System.out.println("Short:    " + type.getBaseType());
+            System.out.println("Parsed:   " + type.toString());
+            System.out.println();
+        }
+    }
+    */
+}
diff --git a/activation/src/main/java/javax/activation/MimeTypeParameterList.java b/activation/src/main/java/javax/activation/MimeTypeParameterList.java
new file mode 100644
index 0000000..6298063
--- /dev/null
+++ b/activation/src/main/java/javax/activation/MimeTypeParameterList.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Locale;
+
+/**
+ * A parameter list of a MimeType
+ * as defined in RFC 2045 and 2046. The Primary type of the
+ * object must already be stripped off.
+ *
+ * @see javax.activation.MimeType
+ */
+public class MimeTypeParameterList {
+    private Hashtable parameters;
+
+    /**
+     * A string that holds all the special chars.
+     */
+    private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
+
+
+    /**
+     * Default constructor.
+     */
+    public MimeTypeParameterList() {
+        parameters = new Hashtable();
+    }
+
+    /**
+     * Constructs a new MimeTypeParameterList with the passed in data.
+     *
+     * @param parameterList an RFC 2045, 2046 compliant parameter list.
+     * @exception	MimeTypeParseException	if the MIME type can't be parsed
+     */
+    public MimeTypeParameterList(String parameterList)
+					throws MimeTypeParseException {
+        parameters = new Hashtable();
+
+        //    now parse rawdata
+        parse(parameterList);
+    }
+
+    /**
+     * A routine for parsing the parameter list out of a String.
+     *
+     * @param parameterList an RFC 2045, 2046 compliant parameter list.
+     * @exception	MimeTypeParseException	if the MIME type can't be parsed
+     */
+    protected void parse(String parameterList) throws MimeTypeParseException {
+	if (parameterList == null)
+	    return;
+
+        int length = parameterList.length();
+        if (length <= 0)
+	    return;
+
+	int i;
+	char c;
+	for (i = skipWhiteSpace(parameterList, 0);
+		i < length && (c = parameterList.charAt(i)) == ';';
+		i = skipWhiteSpace(parameterList, i)) {
+	    int lastIndex;
+	    String name;
+	    String value;
+
+	    //    eat the ';'
+	    i++;
+
+	    //    now parse the parameter name
+
+	    //    skip whitespace
+	    i = skipWhiteSpace(parameterList, i);
+
+	    // tolerate trailing semicolon, even though it violates the spec
+	    if (i >= length)
+		return;
+
+	    //    find the end of the token char run
+	    lastIndex = i;
+	    while ((i < length) && isTokenChar(parameterList.charAt(i)))
+		i++;
+
+	    name = parameterList.substring(lastIndex, i).
+						toLowerCase(Locale.ENGLISH);
+
+	    //    now parse the '=' that separates the name from the value
+	    i = skipWhiteSpace(parameterList, i);
+
+	    if (i >= length || parameterList.charAt(i) != '=')
+		throw new MimeTypeParseException(
+		    "Couldn't find the '=' that separates a " +
+		    "parameter name from its value.");
+
+	    //    eat it and parse the parameter value
+	    i++;
+	    i = skipWhiteSpace(parameterList, i);
+
+	    if (i >= length)
+		throw new MimeTypeParseException(
+			"Couldn't find a value for parameter named " + name);
+
+	    //    now find out whether or not we have a quoted value
+	    c = parameterList.charAt(i);
+	    if (c == '"') {
+		//    yup it's quoted so eat it and capture the quoted string
+		i++;
+		if (i >= length)
+		    throw new MimeTypeParseException(
+			    "Encountered unterminated quoted parameter value.");
+
+		lastIndex = i;
+
+		//    find the next unescaped quote
+		while (i < length) {
+		    c = parameterList.charAt(i);
+		    if (c == '"')
+			break;
+		    if (c == '\\') {
+			//    found an escape sequence
+			//    so skip this and the
+			//    next character
+			i++;
+		    }
+		    i++;
+		}
+		if (c != '"')
+		    throw new MimeTypeParseException(
+			"Encountered unterminated quoted parameter value.");
+
+		value = unquote(parameterList.substring(lastIndex, i));
+		//    eat the quote
+		i++;
+	    } else if (isTokenChar(c)) {
+		//    nope it's an ordinary token so it
+		//    ends with a non-token char
+		lastIndex = i;
+		while (i < length && isTokenChar(parameterList.charAt(i)))
+		    i++;
+		value = parameterList.substring(lastIndex, i);
+	    } else {
+		//    it ain't a value
+		throw new MimeTypeParseException(
+			"Unexpected character encountered at index " + i);
+	    }
+
+	    //    now put the data into the hashtable
+	    parameters.put(name, value);
+	}
+	if (i < length) {
+	    throw new MimeTypeParseException(
+		"More characters encountered in input than expected.");
+	}
+    }
+
+    /**
+     * Return the number of name-value pairs in this list.
+     *
+     * @return	the number of parameters
+     */
+    public int size() {
+        return parameters.size();
+    }
+
+    /**
+     * Determine whether or not this list is empty.
+     *
+     * @return	true if there are no parameters
+     */
+    public boolean isEmpty() {
+        return parameters.isEmpty();
+    }
+
+    /**
+     * Retrieve the value associated with the given name, or null if there
+     * is no current association.
+     *
+     * @param name	the parameter name
+     * @return		the parameter's value
+     */
+    public String get(String name) {
+        return (String)parameters.get(name.trim().toLowerCase(Locale.ENGLISH));
+    }
+
+    /**
+     * Set the value to be associated with the given name, replacing
+     * any previous association.
+     *
+     * @param name	the parameter name
+     * @param value	the parameter's value
+     */
+    public void set(String name, String value) {
+        parameters.put(name.trim().toLowerCase(Locale.ENGLISH), value);
+    }
+
+    /**
+     * Remove any value associated with the given name.
+     *
+     * @param name	the parameter name
+     */
+    public void remove(String name) {
+        parameters.remove(name.trim().toLowerCase(Locale.ENGLISH));
+    }
+
+    /**
+     * Retrieve an enumeration of all the names in this list.
+     *
+     * @return	an enumeration of all parameter names
+     */
+    public Enumeration getNames() {
+        return parameters.keys();
+    }
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.ensureCapacity(parameters.size() * 16);
+			//    heuristic: 8 characters per field
+
+        Enumeration keys = parameters.keys();
+        while (keys.hasMoreElements()) {
+            String key = (String)keys.nextElement();
+            buffer.append("; ");
+            buffer.append(key);
+            buffer.append('=');
+	    buffer.append(quote((String)parameters.get(key)));
+        }
+
+        return buffer.toString();
+    }
+
+    //    below here be scary parsing related things
+
+    /**
+     * Determine whether or not a given character belongs to a legal token.
+     */
+    private static boolean isTokenChar(char c) {
+        return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
+    }
+
+    /**
+     * return the index of the first non white space character in
+     * rawdata at or after index i.
+     */
+    private static int skipWhiteSpace(String rawdata, int i) {
+        int length = rawdata.length();
+	while ((i < length) && Character.isWhitespace(rawdata.charAt(i)))
+	    i++;
+        return i;
+    }
+
+    /**
+     * A routine that knows how and when to quote and escape the given value.
+     */
+    private static String quote(String value) {
+        boolean needsQuotes = false;
+
+        //    check to see if we actually have to quote this thing
+        int length = value.length();
+        for (int i = 0; (i < length) && !needsQuotes; i++) {
+            needsQuotes = !isTokenChar(value.charAt(i));
+        }
+
+        if (needsQuotes) {
+            StringBuffer buffer = new StringBuffer();
+            buffer.ensureCapacity((int)(length * 1.5));
+
+            //    add the initial quote
+            buffer.append('"');
+
+            //    add the properly escaped text
+            for (int i = 0; i < length; ++i) {
+                char c = value.charAt(i);
+                if ((c == '\\') || (c == '"'))
+                    buffer.append('\\');
+                buffer.append(c);
+            }
+
+            //    add the closing quote
+            buffer.append('"');
+
+            return buffer.toString();
+        } else {
+            return value;
+        }
+    }
+
+    /**
+     * A routine that knows how to strip the quotes and
+     * escape sequences from the given value.
+     */
+    private static String unquote(String value) {
+        int valueLength = value.length();
+        StringBuffer buffer = new StringBuffer();
+        buffer.ensureCapacity(valueLength);
+
+        boolean escaped = false;
+        for (int i = 0; i < valueLength; ++i) {
+            char currentChar = value.charAt(i);
+            if (!escaped && (currentChar != '\\')) {
+                buffer.append(currentChar);
+            } else if (escaped) {
+                buffer.append(currentChar);
+                escaped = false;
+            } else {
+                escaped = true;
+            }
+        }
+
+        return buffer.toString();
+    }
+}
diff --git a/activation/src/main/java/javax/activation/MimeTypeParseException.java b/activation/src/main/java/javax/activation/MimeTypeParseException.java
new file mode 100644
index 0000000..fd000e2
--- /dev/null
+++ b/activation/src/main/java/javax/activation/MimeTypeParseException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+/**
+ * A class to encapsulate MimeType parsing related exceptions.
+ */
+public class MimeTypeParseException extends Exception {
+
+    /**
+     * Constructs a MimeTypeParseException with no specified detail message. 
+     */
+    public MimeTypeParseException() {
+	super();
+    }
+
+    /**
+     * Constructs a MimeTypeParseException with the specified detail message. 
+     *
+     * @param   s   the detail message.
+     */
+    public MimeTypeParseException(String s) {
+	super(s);
+    }
+}
diff --git a/activation/src/main/java/javax/activation/MimetypesFileTypeMap.java b/activation/src/main/java/javax/activation/MimetypesFileTypeMap.java
new file mode 100644
index 0000000..e2dffb7
--- /dev/null
+++ b/activation/src/main/java/javax/activation/MimetypesFileTypeMap.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import com.sun.activation.registries.MimeTypeFile;
+import com.sun.activation.registries.LogSupport;
+
+/**
+ * This class extends FileTypeMap and provides data typing of files
+ * via their file extension. It uses the <code>.mime.types</code> format. <p>
+ *
+ * <b>MIME types file search order:</b><p>
+ * The MimetypesFileTypeMap looks in various places in the user's
+ * system for MIME types file entries. When requests are made
+ * to search for MIME types in the MimetypesFileTypeMap, it searches  
+ * MIME types files in the following order:
+ * <ol>
+ * <li> Programmatically added entries to the MimetypesFileTypeMap instance.
+ * <li> The file <code>.mime.types</code> in the user's home directory.
+ * <li> The file <code>mime.types</code> in the Java runtime.
+ * <li> The file or resources named <code>META-INF/mime.types</code>.
+ * <li> The file or resource named <code>META-INF/mimetypes.default</code>
+ * (usually found only in the <code>activation.jar</code> file).
+ * </ol>
+ * <p>
+ * (The current implementation looks for the <code>mime.types</code> file
+ * in the Java runtime in the directory <code><i>java.home</i>/conf</code>
+ * if it exists, and otherwise in the directory
+ * <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
+ * of the "java.home" System property.  Note that the "conf" directory was
+ * introduced in JDK 9.)
+ * <p>
+ * <b>MIME types file format:</b><p>
+ *
+ * <code>
+ * # comments begin with a '#'<br>
+ * # the format is &lt;mime type&gt; &lt;space separated file extensions&gt;<br>
+ * # for example:<br>
+ * text/plain    txt text TXT<br>
+ * # this would map file.txt, file.text, and file.TXT to<br>
+ * # the mime type "text/plain"<br>
+ * </code>
+ *
+ * @author Bart Calder
+ * @author Bill Shannon
+ */
+public class MimetypesFileTypeMap extends FileTypeMap {
+    /*
+     * We manage a collection of databases, searched in order.
+     */
+    private MimeTypeFile[] DB;
+    private static final int PROG = 0;	// programmatically added entries
+
+    private static final String defaultType = "application/octet-stream";
+
+    private static final String confDir;
+
+    static {
+	String dir = null;
+	try {
+	    dir = (String)AccessController.doPrivileged(
+		new PrivilegedAction() {
+		    public Object run() {
+			String home = System.getProperty("java.home");
+			String newdir = home + File.separator + "conf";
+			File conf = new File(newdir);
+			if (conf.exists())
+			    return newdir + File.separator;
+			else
+			    return home + File.separator + "lib" + File.separator;
+		    }
+		});
+	} catch (Exception ex) {
+	    // ignore any exceptions
+	}
+	confDir = dir;
+    }
+
+    /**
+     * The default constructor.
+     */
+    public MimetypesFileTypeMap() {
+	Vector dbv = new Vector(5);	// usually 5 or less databases
+	MimeTypeFile mf = null;
+	dbv.addElement(null);		// place holder for PROG entry
+
+	LogSupport.log("MimetypesFileTypeMap: load HOME");
+	try {
+	    String user_home = System.getProperty("user.home");
+
+	    if (user_home != null) {
+		String path = user_home + File.separator + ".mime.types";
+		mf = loadFile(path);
+		if (mf != null)
+		    dbv.addElement(mf);
+	    }
+	} catch (SecurityException ex) {}
+
+	LogSupport.log("MimetypesFileTypeMap: load SYS");
+	try {
+	    // check system's home
+	    if (confDir != null) {
+		mf = loadFile(confDir + "mime.types");
+		if (mf != null)
+		    dbv.addElement(mf);
+	    }
+	} catch (SecurityException ex) {}
+
+	LogSupport.log("MimetypesFileTypeMap: load JAR");
+	// load from the app's jar file
+	loadAllResources(dbv, "META-INF/mime.types");
+
+	LogSupport.log("MimetypesFileTypeMap: load DEF");
+	mf = loadResource("/META-INF/mimetypes.default");
+
+	if (mf != null)
+	    dbv.addElement(mf);
+
+	DB = new MimeTypeFile[dbv.size()];
+	dbv.copyInto(DB);
+    }
+
+    /**
+     * Load from the named resource.
+     */
+    private MimeTypeFile loadResource(String name) {
+	InputStream clis = null;
+	try {
+	    clis = SecuritySupport.getResourceAsStream(this.getClass(), name);
+	    if (clis != null) {
+		MimeTypeFile mf = new MimeTypeFile(clis);
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MimetypesFileTypeMap: successfully " +
+			"loaded mime types file: " + name);
+		return mf;
+	    } else {
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MimetypesFileTypeMap: not loading " +
+			"mime types file: " + name);
+	    }
+	} catch (IOException e) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MimetypesFileTypeMap: can't load " + name, e);
+	} catch (SecurityException sex) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MimetypesFileTypeMap: can't load " + name, sex);
+	} finally {
+	    try {
+		if (clis != null)
+		    clis.close();
+	    } catch (IOException ex) { }	// ignore it
+	}
+	return null;
+    }
+
+    /**
+     * Load all of the named resource.
+     */
+    private void loadAllResources(Vector v, String name) {
+	boolean anyLoaded = false;
+	try {
+	    URL[] urls;
+	    ClassLoader cld = null;
+	    // First try the "application's" class loader.
+	    cld = SecuritySupport.getContextClassLoader();
+	    if (cld == null)
+		cld = this.getClass().getClassLoader();
+	    if (cld != null)
+		urls = SecuritySupport.getResources(cld, name);
+	    else
+		urls = SecuritySupport.getSystemResources(name);
+	    if (urls != null) {
+		if (LogSupport.isLoggable())
+		    LogSupport.log("MimetypesFileTypeMap: getResources");
+		for (int i = 0; i < urls.length; i++) {
+		    URL url = urls[i];
+		    InputStream clis = null;
+		    if (LogSupport.isLoggable())
+			LogSupport.log("MimetypesFileTypeMap: URL " + url);
+		    try {
+			clis = SecuritySupport.openStream(url);
+			if (clis != null) {
+			    v.addElement(new MimeTypeFile(clis));
+			    anyLoaded = true;
+			    if (LogSupport.isLoggable())
+				LogSupport.log("MimetypesFileTypeMap: " +
+				    "successfully loaded " +
+				    "mime types from URL: " + url);
+			} else {
+			    if (LogSupport.isLoggable())
+				LogSupport.log("MimetypesFileTypeMap: " +
+				    "not loading " +
+				    "mime types from URL: " + url);
+			}
+		    } catch (IOException ioex) {
+			if (LogSupport.isLoggable())
+			    LogSupport.log("MimetypesFileTypeMap: can't load " +
+						url, ioex);
+		    } catch (SecurityException sex) {
+			if (LogSupport.isLoggable())
+			    LogSupport.log("MimetypesFileTypeMap: can't load " +
+						url, sex);
+		    } finally {
+			try {
+			    if (clis != null)
+				clis.close();
+			} catch (IOException cex) { }
+		    }
+		}
+	    }
+	} catch (Exception ex) {
+	    if (LogSupport.isLoggable())
+		LogSupport.log("MimetypesFileTypeMap: can't load " + name, ex);
+	}
+
+	// if failed to load anything, fall back to old technique, just in case
+	if (!anyLoaded) {
+	    LogSupport.log("MimetypesFileTypeMap: !anyLoaded");
+	    MimeTypeFile mf = loadResource("/" + name);
+	    if (mf != null)
+		v.addElement(mf);
+	}
+    }
+
+    /**
+     * Load the named file.
+     */
+    private MimeTypeFile loadFile(String name) {
+	MimeTypeFile mtf = null;
+
+	try {
+	    mtf = new MimeTypeFile(name);
+	} catch (IOException e) {
+	    //	e.printStackTrace();
+	}
+	return mtf;
+    }
+
+    /**
+     * Construct a MimetypesFileTypeMap with programmatic entries
+     * added from the named file.
+     *
+     * @param mimeTypeFileName	the file name
+     * @exception	IOException	for errors reading the file
+     */
+    public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException {
+	this();
+	DB[PROG] = new MimeTypeFile(mimeTypeFileName);
+    }
+
+    /**
+     * Construct a MimetypesFileTypeMap with programmatic entries
+     * added from the InputStream.
+     *
+     * @param is	the input stream to read from
+     */
+    public MimetypesFileTypeMap(InputStream is) {
+	this();
+	try {
+	    DB[PROG] = new MimeTypeFile(is);
+	} catch (IOException ex) {
+	    // XXX - really should throw it
+	}
+    }
+
+    /**
+     * Prepend the MIME type values to the registry.
+     *
+     * @param mime_types A .mime.types formatted string of entries.
+     */
+    public synchronized void addMimeTypes(String mime_types) {
+	// check to see if we have created the registry
+	if (DB[PROG] == null)
+	    DB[PROG] = new MimeTypeFile(); // make one
+
+	DB[PROG].appendToRegistry(mime_types);
+    }
+
+    /**
+     * Return the MIME type of the file object.
+     * The implementation in this class calls
+     * <code>getContentType(f.getName())</code>.
+     *
+     * @param f	the file
+     * @return	the file's MIME type
+     */
+    public String getContentType(File f) {
+	return this.getContentType(f.getName());
+    }
+
+    /**
+     * Return the MIME type based on the specified file name.
+     * The MIME type entries are searched as described above under
+     * <i>MIME types file search order</i>.
+     * If no entry is found, the type "application/octet-stream" is returned.
+     *
+     * @param filename	the file name
+     * @return		the file's MIME type
+     */
+    public synchronized String getContentType(String filename) {
+	int dot_pos = filename.lastIndexOf("."); // period index
+
+	if (dot_pos < 0)
+	    return defaultType;
+
+	String file_ext = filename.substring(dot_pos + 1);
+	if (file_ext.length() == 0)
+	    return defaultType;
+
+	for (int i = 0; i < DB.length; i++) {
+	    if (DB[i] == null)
+		continue;
+	    String result = DB[i].getMIMETypeString(file_ext);
+	    if (result != null)
+		return result;
+	}
+	return defaultType;
+    }
+
+    /**
+     * for debugging...
+     *
+    public static void main(String[] argv) throws Exception {
+	MimetypesFileTypeMap map = new MimetypesFileTypeMap();
+	System.out.println("File " + argv[0] + " has MIME type " +
+						map.getContentType(argv[0]));
+	System.exit(0);
+    }
+    */
+}
diff --git a/activation/src/main/java/javax/activation/SecuritySupport.java b/activation/src/main/java/javax/activation/SecuritySupport.java
new file mode 100644
index 0000000..c37174b
--- /dev/null
+++ b/activation/src/main/java/javax/activation/SecuritySupport.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.security.*;
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Security related methods that only work on J2SE 1.2 and newer.
+ */
+class SecuritySupport {
+
+    private SecuritySupport() {
+	// private constructor, can't create an instance
+    }
+
+    public static ClassLoader getContextClassLoader() {
+	return (ClassLoader)
+		AccessController.doPrivileged(new PrivilegedAction() {
+	    public Object run() {
+		ClassLoader cl = null;
+		try {
+		    cl = Thread.currentThread().getContextClassLoader();
+		} catch (SecurityException ex) { }
+		return cl;
+	    }
+	});
+    }
+
+    public static InputStream getResourceAsStream(final Class c,
+				final String name) throws IOException {
+	try {
+	    return (InputStream)
+		AccessController.doPrivileged(new PrivilegedExceptionAction() {
+		    public Object run() throws IOException {
+			return c.getResourceAsStream(name);
+		    }
+		});
+	} catch (PrivilegedActionException e) {
+	    throw (IOException)e.getException();
+	}
+    }
+
+    public static URL[] getResources(final ClassLoader cl, final String name) {
+	return (URL[])
+		AccessController.doPrivileged(new PrivilegedAction() {
+	    public Object run() {
+		URL[] ret = null;
+		try {
+		    List v = new ArrayList();
+		    Enumeration e = cl.getResources(name);
+		    while (e != null && e.hasMoreElements()) {
+			URL url = (URL)e.nextElement();
+			if (url != null)
+			    v.add(url);
+		    }
+		    if (v.size() > 0) {
+			ret = new URL[v.size()];
+			ret = (URL[])v.toArray(ret);
+		    }
+		} catch (IOException ioex) {
+		} catch (SecurityException ex) { }
+		return ret;
+	    }
+	});
+    }
+
+    public static URL[] getSystemResources(final String name) {
+	return (URL[])
+		AccessController.doPrivileged(new PrivilegedAction() {
+	    public Object run() {
+		URL[] ret = null;
+		try {
+		    List v = new ArrayList();
+		    Enumeration e = ClassLoader.getSystemResources(name);
+		    while (e != null && e.hasMoreElements()) {
+			URL url = (URL)e.nextElement();
+			if (url != null)
+			    v.add(url);
+		    }
+		    if (v.size() > 0) {
+			ret = new URL[v.size()];
+			ret = (URL[])v.toArray(ret);
+		    }
+		} catch (IOException ioex) {
+		} catch (SecurityException ex) { }
+		return ret;
+	    }
+	});
+    }
+
+    public static InputStream openStream(final URL url) throws IOException {
+	try {
+	    return (InputStream)
+		AccessController.doPrivileged(new PrivilegedExceptionAction() {
+		    public Object run() throws IOException {
+			return url.openStream();
+		    }
+		});
+	} catch (PrivilegedActionException e) {
+	    throw (IOException)e.getException();
+	}
+    }
+}
diff --git a/activation/src/main/java/javax/activation/URLDataSource.java b/activation/src/main/java/javax/activation/URLDataSource.java
new file mode 100644
index 0000000..c65805f
--- /dev/null
+++ b/activation/src/main/java/javax/activation/URLDataSource.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The URLDataSource class provides an object that wraps a <code>URL</code>
+ * object in a DataSource interface. URLDataSource simplifies the handling
+ * of data described by URLs within Jakarta Activation
+ * because this class can be used to create new DataHandlers. <i>NOTE: The
+ * DataHandler object creates a URLDataSource internally,
+ * when it is constructed with a URL.</i>
+ *
+ * @see javax.activation.DataSource
+ * @see javax.activation.DataHandler
+ */
+public class URLDataSource implements DataSource {
+    private URL url = null;
+    private URLConnection url_conn = null;
+
+    /**
+     * URLDataSource constructor. The URLDataSource class will
+     * not open a connection to the URL until a method requiring it
+     * to do so is called.
+     *
+     * @param url The URL to be encapsulated in this object.
+     */
+    public URLDataSource(URL url) {
+	this.url = url;
+    }
+
+    /**
+     * Returns the value of the URL content-type header field.
+     * It calls the URL's <code>URLConnection.getContentType</code> method
+     * after retrieving a URLConnection object.
+     * <i>Note: this method attempts to call the <code>openConnection</code>
+     * method on the URL. If this method fails, or if a content type is not
+     * returned from the URLConnection, getContentType returns
+     * "application/octet-stream" as the content type.</i>
+     *
+     * @return the content type.
+     */
+    public String getContentType() {
+	String type = null;
+
+	try {
+	    if (url_conn == null)
+		url_conn = url.openConnection();
+	} catch (IOException e) { }
+	
+	if (url_conn != null)
+	    type = url_conn.getContentType();
+
+	if (type == null)
+	    type = "application/octet-stream";
+	
+	return type;
+    }
+
+    /**
+     * Calls the <code>getFile</code> method on the URL used to
+     * instantiate the object.
+     *
+     * @return the result of calling the URL's getFile method.
+     */
+    public String getName() {
+	return url.getFile();
+    }
+
+    /**
+     * The getInputStream method from the URL. Calls the
+     * <code>openStream</code> method on the URL.
+     *
+     * @return the InputStream.
+     */
+    public InputStream getInputStream() throws IOException {
+	return url.openStream();
+    }
+
+    /**
+     * The getOutputStream method from the URL. First an attempt is
+     * made to get the URLConnection object for the URL. If that
+     * succeeds, the getOutputStream method on the URLConnection
+     * is returned.
+     *
+     * @return the OutputStream.
+     */
+    public OutputStream getOutputStream() throws IOException {
+	// get the url connection if it is available
+	url_conn = url.openConnection();
+	
+	if (url_conn != null) {
+	    url_conn.setDoOutput(true);
+	    return url_conn.getOutputStream();
+	} else
+	    return null;
+    }
+
+    /**
+     * Return the URL used to create this DataSource.
+     *
+     * @return The URL.
+     */
+    public URL getURL() {
+	return url;
+    }
+}
diff --git a/activation/src/main/java/javax/activation/UnsupportedDataTypeException.java b/activation/src/main/java/javax/activation/UnsupportedDataTypeException.java
new file mode 100644
index 0000000..b24a788
--- /dev/null
+++ b/activation/src/main/java/javax/activation/UnsupportedDataTypeException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package javax.activation;
+
+import java.io.IOException;
+
+/**
+ * Signals that the requested operation does not support the
+ * requested data type.
+ *
+ * @see javax.activation.DataHandler
+ */
+
+public class UnsupportedDataTypeException extends IOException {
+    /**
+     * Constructs an UnsupportedDataTypeException with no detail
+     * message.
+     */
+    public UnsupportedDataTypeException() {
+	super();
+    }
+
+    /**
+     * Constructs an UnsupportedDataTypeException with the specified 
+     * message.
+     * 
+     * @param s The detail message.
+     */
+    public UnsupportedDataTypeException(String s) {
+	super(s);
+    }
+}
diff --git a/activation/src/main/java/javax/activation/package.html b/activation/src/main/java/javax/activation/package.html
new file mode 100644
index 0000000..6cc89ab
--- /dev/null
+++ b/activation/src/main/java/javax/activation/package.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<!--
+
+    Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+Jakarta Activation is used by Jakarta Mail to manage MIME data.
+
+</BODY>
+</HTML>
diff --git a/activation/src/main/java/module-info.java b/activation/src/main/java/module-info.java
new file mode 100644
index 0000000..b18cd91
--- /dev/null
+++ b/activation/src/main/java/module-info.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+module jakarta.activation {
+    exports javax.activation;
+    requires java.logging;
+    requires java.desktop;	// for image/jpeg handler
+}
diff --git a/activation/src/main/javadoc/doc-files/speclicense.html b/activation/src/main/javadoc/doc-files/speclicense.html
new file mode 100644
index 0000000..ba29e5e
--- /dev/null
+++ b/activation/src/main/javadoc/doc-files/speclicense.html
@@ -0,0 +1,72 @@
+<html>
+<head>
+<title>Eclipse Foundation Specification License - v1.0</title>
+</head>
+<body>
+<h1>Eclipse Foundation Specification License - v1.0</h1>
+<p>By using and/or copying this document, or the Eclipse Foundation
+  document from which this statement is linked, you (the licensee) agree
+  that you have read, understood, and will comply with the following
+  terms and conditions:</p>
+
+<p>Permission to copy, and distribute the contents of this document, or
+  the Eclipse Foundation document from which this statement is linked, in
+  any medium for any purpose and without fee or royalty is hereby
+  granted, provided that you include the following on ALL copies of the
+  document, or portions thereof, that you use:</p>
+
+<ul>
+  <li> link or URL to the original Eclipse Foundation document.</li>
+  <li>All existing copyright notices, or if one does not exist, a notice
+      (hypertext is preferred, but a textual representation is permitted)
+      of the form: &quot;Copyright &copy; [$date-of-document]
+      &ldquo;Eclipse Foundation, Inc. &lt;&lt;url to this license&gt;&gt;
+      &quot;
+  </li>
+</ul>
+
+<p>Inclusion of the full text of this NOTICE must be provided. We
+  request that authorship attribution be provided in any software,
+  documents, or other items or products that you create pursuant to the
+  implementation of the contents of this document, or any portion
+  thereof.</p>
+
+<p>No right to create modifications or derivatives of Eclipse Foundation
+  documents is granted pursuant to this license, except anyone may
+  prepare and distribute derivative works and portions of this document
+  in software that implements the specification, in supporting materials
+  accompanying such software, and in documentation of such software,
+  PROVIDED that all such works include the notice below. HOWEVER, the
+  publication of derivative works of this document for use as a technical
+  specification is expressly prohibited.</p>
+
+<p>The notice is:</p>
+
+<p>&quot;Copyright &copy; 2018 Eclipse Foundation. This software or
+  document includes material copied from or derived from [title and URI
+  of the Eclipse Foundation specification document].&quot;</p>
+
+<h2>Disclaimers</h2>
+
+<p>THIS DOCUMENT IS PROVIDED &quot;AS IS,&quot; AND THE COPYRIGHT
+  HOLDERS AND THE ECLIPSE FOUNDATION MAKE NO REPRESENTATIONS OR
+  WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+  NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE
+  SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS
+  WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR
+  OTHER RIGHTS.</p>
+
+<p>THE COPYRIGHT HOLDERS AND THE ECLIPSE FOUNDATION WILL NOT BE LIABLE
+  FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT
+  OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE
+  CONTENTS THEREOF.</p>
+
+<p>The name and trademarks of the copyright holders or the Eclipse
+  Foundation may NOT be used in advertising or publicity pertaining to
+  this document or its contents without specific, written prior
+  permission. Title to copyright in this document will at all times
+  remain with copyright holders.</p>
+
+</body>
+</html>
diff --git a/activation/src/main/resources/META-INF/LICENSE.md b/activation/src/main/resources/META-INF/LICENSE.md
new file mode 100644
index 0000000..e0358f9
--- /dev/null
+++ b/activation/src/main/resources/META-INF/LICENSE.md
@@ -0,0 +1,29 @@
+
+    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+   
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+   
+      - Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+   
+      - Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+   
+      - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+   
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/activation/src/main/resources/META-INF/mailcap.default b/activation/src/main/resources/META-INF/mailcap.default
new file mode 100644
index 0000000..542de7d
--- /dev/null
+++ b/activation/src/main/resources/META-INF/mailcap.default
@@ -0,0 +1,7 @@
+#
+# This is a very simple 'mailcap' file
+#
+image/gif;;		x-java-view=com.sun.activation.viewers.ImageViewer
+image/jpeg;;		x-java-view=com.sun.activation.viewers.ImageViewer
+text/*;;		x-java-view=com.sun.activation.viewers.TextViewer
+text/*;;		x-java-edit=com.sun.activation.viewers.TextEditor
diff --git a/activation/src/main/resources/META-INF/mimetypes.default b/activation/src/main/resources/META-INF/mimetypes.default
new file mode 100644
index 0000000..1b4056b
--- /dev/null
+++ b/activation/src/main/resources/META-INF/mimetypes.default
@@ -0,0 +1,25 @@
+#
+# A simple, old format, mime.types file
+#
+text/html		html htm HTML HTM
+text/plain		txt text TXT TEXT
+image/gif		gif GIF
+image/ief		ief
+image/jpeg		jpeg jpg jpe JPG
+image/tiff		tiff tif
+image/png		png PNG
+image/x-xwindowdump	xwd
+application/postscript	ai eps ps
+application/rtf		rtf
+application/x-tex	tex
+application/x-texinfo	texinfo texi
+application/x-troff	t tr roff
+audio/basic		au
+audio/midi		midi mid
+audio/x-aifc		aifc
+audio/x-aiff            aif aiff
+audio/x-mpeg		mpeg mpg
+audio/x-wav             wav
+video/mpeg		mpeg mpg mpe
+video/quicktime		qt mov
+video/x-msvideo		avi
diff --git a/activationapi/pom.xml b/activationapi/pom.xml
new file mode 100644
index 0000000..2650521
--- /dev/null
+++ b/activationapi/pom.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+
+    Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+<!--
+    This project builds the Activation API jar file, which contains only
+    the javax.activation.* API definitions and is *only* intended to be used
+    for programs to compile against.  Note that it includes none of the
+    implementation-specific classes that the javax.activation.* classes rely on.
+-->
+<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">
+    <parent>
+        <groupId>com.sun.activation</groupId>
+        <artifactId>all</artifactId>
+        <version>1.2.2</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>jakarta.activation</groupId>
+    <artifactId>jakarta.activation-api</artifactId>
+    <packaging>jar</packaging>
+    <name>Jakarta Activation API jar</name>
+    <properties>
+        <activation.extensionName>
+            jakarta.activation
+        </activation.extensionName>
+        <activation.moduleName>
+            jakarta.activation
+        </activation.moduleName>
+        <activation.packages.export>
+            javax.activation.*; version=${activation.spec.version},
+	    !com.sun.*
+        </activation.packages.export>
+        <activation.packages.import>
+	    !com.sun.*
+        </activation.packages.import>
+        <activation.bundle.symbolicName>
+            jakarta.activation-api
+        </activation.bundle.symbolicName>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <!-- download the binaries -->
+                        <id>get-binaries</id>
+                        <phase>process-sources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <!-- download the sources -->
+                        <id>get-sources</id>
+                        <phase>process-sources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>com.sun.activation</groupId>
+                                    <artifactId>jakarta.activation</artifactId>
+                                    <version>${project.version}</version>
+                                    <classifier>sources</classifier>
+                                    <outputDirectory>
+                                        ${project.build.directory}/sources
+                                    </outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+                <configuration>
+                    <artifactItems>
+                        <artifactItem>
+                            <groupId>com.sun.activation</groupId>
+                            <artifactId>jakarta.activation</artifactId>
+                            <version>${project.version}</version>
+                        </artifactItem>
+                    </artifactItems>
+                    <outputDirectory>
+                        ${project.build.outputDirectory}
+                    </outputDirectory>
+		    <!--
+			Include all the implementation source files so that
+			javadoc run as part of "deploy" will find all the
+			required classes.
+
+			Don't include the metadata files from the original
+			jar file.
+		    -->
+		    <excludes>
+			META-INF/**
+		    </excludes>
+                </configuration>
+            </plugin>
+
+	    <!--
+		 Skip compiling since the dependency plugin pulled in
+		 the sources and class files.
+	    -->
+	    <plugin>
+		<artifactId>maven-compiler-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>default-compile</id>
+			<configuration>
+			    <skipMain>true</skipMain>
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Don't include the implementation classes in the jar files.
+	    -->
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <finalName>${project.artifactId}</finalName>
+		    <excludes>
+			<exclude>com/**</exclude>
+		    </excludes>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-source-plugin</artifactId>
+                <configuration>
+		    <excludes>
+			<exclude>com/**</exclude>
+		    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/copyright-exclude b/copyright-exclude
new file mode 100644
index 0000000..1f0ceed
--- /dev/null
+++ b/copyright-exclude
@@ -0,0 +1,8 @@
+copyright-exclude
+LICENSE
+CONTRIBUTING.md
+README
+/META-INF/
+/speclicense.html
+doc/release/
+doc/spec/
diff --git a/demo/pom.xml b/demo/pom.xml
new file mode 100644
index 0000000..b800c51
--- /dev/null
+++ b/demo/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+
+    Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<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">
+    <parent>
+	<groupId>com.sun.activation</groupId>
+	<artifactId>all</artifactId>
+	<version>1.2.2</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.activation</groupId>
+    <artifactId>demo</artifactId>
+    <packaging>jar</packaging>
+    <name>Jakarta Activation demos</name>
+
+    <build>
+        <plugins>
+	    <!--
+		Need to disable the maven-bundle-plugin because the
+		new version doesn't like classes in the default package.
+	    -->
+	    <plugin>
+		<groupId>org.apache.felix</groupId>
+		<artifactId>maven-bundle-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>osgi-manifest</id>
+			<phase>none</phase>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Because the maven-jar-plugin depends on the manifest file
+		created by the maven-bundle-plugin, we need to disable it too.
+	    -->
+	    <plugin>
+		<artifactId>maven-jar-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>default-jar</id>
+			<phase>none</phase>
+		    </execution>
+		</executions>
+	    </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.sun.activation</groupId>
+            <artifactId>jakarta.activation</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/demo/src/main/java/CompViewer.java b/demo/src/main/java/CompViewer.java
new file mode 100644
index 0000000..3b4a831
--- /dev/null
+++ b/demo/src/main/java/CompViewer.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.awt.*;
+import java.beans.*;
+import java.lang.reflect.Method;
+import java.io.*;
+import java.awt.event.*;
+
+/**
+ * Class <code>CompViewer</code> creates a 'viewer' component
+ * that implements the CommandObject interface.
+ *
+ */
+public class CompViewer extends Frame implements WindowListener {
+
+    /**
+     * Our constructor...
+     */
+    public CompViewer(){
+	super("Component");
+	this.initCompViewer(null);
+    }
+
+    public CompViewer(String name){
+	super(name);
+	this.initCompViewer(name);
+    }
+
+    public void initCompViewer(String name){
+	if (name != null)
+	    setTitle(name);
+	setSize(400,400);
+	setLayout(new BorderLayout());
+	this.addWindowListener(this);
+    }
+    
+    ////////////////////////////////////////////////////////////////////////
+    // we got our bean as a component display it!
+    void setBean(Component new_bean)
+	{
+	    Dimension start_dim = null;
+	    add((Component)new_bean, "Center");
+	    start_dim =  ((Component)new_bean).getPreferredSize();
+	    
+	    if(start_dim.width != 0 && start_dim.height != 0) {
+		// this is what we do under normal conditions
+		start_dim.height += 40;
+		start_dim.width += 15;
+		this.setSize( start_dim );
+		((Component)new_bean).invalidate(); 
+		((Component)new_bean).validate();
+		((Component)new_bean).doLayout();
+		show();           
+	    }
+	    else {
+		// we get here if for some reason our child's
+		// getPref size needs to have it's peer created
+		// first...
+		show();           
+		start_dim =  ((Component)new_bean).getPreferredSize();
+		start_dim.height += 40;
+		start_dim.width += 15;
+		this.setSize( start_dim );
+		((Component)new_bean).validate();
+	    }
+	    this.setSize(this.getSize());
+	    validate();
+	}
+
+
+    /**
+     * Make the bean based on it's class loader and name
+     */
+    private Object makeBean(ClassLoader cls, String beanName) {
+	Object new_bean = null;
+
+	try {
+	    try {
+		new_bean = java.beans.Beans.instantiate(cls, beanName);
+	    }
+	    catch(IOException e) {
+		System.out.println("CompViewer:Beans.instantiate:IOException " + beanName + ".");
+		System.out.println(e);
+		System.exit(1);
+	    }
+	}
+	catch (ClassNotFoundException e) {
+	    System.out.println("CompViewer:Beans.instantiate:ClassNotFoundException " + beanName + "."); 
+	    System.out.println(e);
+	    System.exit(1);
+	}
+      
+	if( !(new_bean instanceof Component) ) {
+	    System.out.println("CompViewer: " + beanName + " not instance of awt.Component exiting");
+	    System.exit(1);
+	}
+	return new_bean;
+    }
+
+    public void windowOpened(WindowEvent e) {}
+    public void windowClosing(WindowEvent e) {
+	this.setVisible(false);
+    }
+    public void windowClosed(WindowEvent e) {}
+    public void windowIconified(WindowEvent e) {}
+    public void windowDeiconified(WindowEvent e) {}
+    public void windowActivated(WindowEvent e) {}
+    public void windowDeactivated(WindowEvent e) {}
+
+}
+
+
+
diff --git a/demo/src/main/java/DCHTest.java b/demo/src/main/java/DCHTest.java
new file mode 100644
index 0000000..929aa0d
--- /dev/null
+++ b/demo/src/main/java/DCHTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import javax.activation.*;
+import java.awt.datatransfer.*;
+
+public class DCHTest {
+    private FileDataSource fds = null;
+    private DataHandler dh = null;
+    private DataContentHandlerFactory dchf = null;
+    /**
+     * main function
+     */
+    public static void main(String args[]) {
+	DCHTest test = new DCHTest();
+	
+	if(args.length == 0) {
+	    System.out.println("usage: DCHTest file.txt");
+	    System.exit(1);
+	}
+	
+	// first let's get a DataSource
+
+	test.setFile(args[0]);
+	
+	test.doit();
+    }
+
+    private void doit() {
+	DataFlavor xfer_flavors[];
+	Object content = null;
+
+	// now let's create a DataHandler
+	dh = new DataHandler(fds);
+	System.out.println("DCHTest: DataHandler created");
+
+	// now lets set a DataContentHandlerFactory
+	dchf = new SimpleDCF("text/plain:PlainDCH\n");
+	System.out.println("DCHTest: Simple dchf created");
+	
+	// now let's set the dchf in the dh
+	dh.setDataContentHandlerFactory(dchf);
+	System.out.println("DCHTest: DataContentHandlerFactory set in DataHandler");
+	
+	// get the dataflavors
+	xfer_flavors = dh.getTransferDataFlavors();
+	System.out.println("DCHTest: dh.getTransferDF returned " +
+			   xfer_flavors.length + " data flavors.");
+
+	// get the content:
+        try {
+	   content = dh.getContent();
+        } catch (Exception e) { e.printStackTrace(); }
+
+	if(content == null)
+	    System.out.println("DCHTest: no content to be had!!!");
+	else
+	    System.out.println("DCHTest: got content of the following type: " +
+			       content.getClass().getName());
+	
+    }
+
+    /**
+     * set the file
+     */
+    public void setFile(String filename) {
+	fds = new FileDataSource(filename);
+	System.out.println("DCHTest: FileDataSource created");
+	if(!fds.getContentType().equals("text/plain")) {
+	    System.out.println("Type must be text/plain");
+	    System.exit(1);
+	}
+    }
+	    
+}
+
+
diff --git a/demo/src/main/java/DCHTest2.java b/demo/src/main/java/DCHTest2.java
new file mode 100644
index 0000000..155ee06
--- /dev/null
+++ b/demo/src/main/java/DCHTest2.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import javax.activation.*;
+import java.awt.datatransfer.*;
+
+public class DCHTest2 {
+    private FileDataSource fds = null;
+    private MailcapCommandMap cmdMap = null;
+    private DataHandler dh = null;
+    private DataContentHandlerFactory dchf = null;
+    /**
+     * main function
+     */
+    public static void main(String args[]) {
+	DCHTest2 test = new DCHTest2();
+	
+	if(args.length < 2) {
+	    System.out.println("usage: DCHTest2 file.txt mailcap");
+	    System.exit(1);
+	}
+	
+	// first let's get a DataSource
+
+	test.setFile(args[0]);
+	
+	test.setMailcap(args[1]);
+	test.doit();
+    }
+
+    private void doit() {
+	DataFlavor xfer_flavors[];
+	Object content = null;
+
+	// now let's create a DataHandler
+	dh = new DataHandler(fds);
+        dh.setCommandMap(cmdMap);
+	System.out.println("DCHTest2: DataHandler created");
+
+	// get the dataflavors
+	xfer_flavors = dh.getTransferDataFlavors();
+	System.out.println("DCHTest2: dh.getTransferDF returned " +
+			   xfer_flavors.length + " data flavors.");
+
+	// get the content:
+	try {
+	    content = dh.getContent();
+        } catch (Exception e) { e.printStackTrace(); }
+	if(content == null)
+	    System.out.println("DCHTest2: no content to be had!!!");
+	else
+	    System.out.println("DCHTest2: got content of the following type: " +
+			       content.getClass().getName());
+	
+    }
+
+    /**
+     * set the file
+     */
+    public void setFile(String filename) {
+	fds = new FileDataSource(filename);
+	System.out.println("DCHTest2: FileDataSource created");
+	if(!fds.getContentType().equals("text/plain")) {
+	    System.out.println("Type must be text/plain");
+	    System.exit(1);
+	}
+    }
+
+   /**
+    * set the mailcap file in the CMD Map
+    */
+   public void setMailcap(String mailcap) {
+
+       try {
+	   cmdMap = new MailcapCommandMap(mailcap);
+       } catch(Exception e){
+	   e.printStackTrace();
+	   System.exit(1);
+       }
+   }
+
+	    
+}
+
+
diff --git a/demo/src/main/java/DHURL.java b/demo/src/main/java/DHURL.java
new file mode 100644
index 0000000..b79a05e
--- /dev/null
+++ b/demo/src/main/java/DHURL.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.net.*;
+import java.io.*;
+import javax.activation.*;
+
+public class DHURL {
+    URL url = null;
+    DataHandler dh = null;
+    
+    public static void main(String args[]){
+        DHURL test = new DHURL();
+
+        if(args.length == 0) {
+            System.out.println("usage: DHURL url");
+            System.exit(1);
+        }
+
+        test.setURL(args[0]);
+
+        test.doit();
+
+    }
+
+    public void setURL(String url) {
+	
+	try {
+	    this.url = new URL(url);
+	} catch(MalformedURLException e) {
+	    e.printStackTrace();
+	    System.out.println("malformed URL!!!");
+	    System.exit(1);
+	}
+
+    }
+    
+    public void doit() {
+	System.out.print("Creating DataHandler...");
+	dh = new DataHandler(url);
+	System.out.println("...done.");
+
+	System.out.println("The MimeType of the DH : " +
+			   dh.getContentType());
+	try {
+	InputStream is = dh.getInputStream();
+	if(is != null)
+	    System.out.println("got an inputstream");
+	} catch(Exception e) {
+	    e.printStackTrace();
+	}
+
+	
+    }
+	
+    
+}
diff --git a/demo/src/main/java/FileView.java b/demo/src/main/java/FileView.java
new file mode 100644
index 0000000..6aae7f7
--- /dev/null
+++ b/demo/src/main/java/FileView.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.awt.*;
+import java.beans.*;
+import java.net.*;
+import javax.activation.*;
+
+public class FileView {
+    private Frame frame;
+
+    public static void main(String args[]) throws Exception {
+        FileView fv = new FileView();
+        if (args.length == 0) {
+            System.out.println("usage: FileView  file.txt");
+            System.exit(1);
+        }
+        fv.view(args[0]);
+    }
+
+    private void view(String filename) throws Exception {
+  	FileDataSource fds = new FileDataSource(filename); 
+  	DataHandler dh = new DataHandler(fds); 
+	// comment out previous two lines, and uncomment next
+	// line and pass in a URL on the command line.
+	// DataHandler dh = new DataHandler(new URL(filename));
+
+	CommandInfo bi = dh.getCommand("view");
+	
+	if (bi == null) {
+	    System.out.println("no viewer found, exiting");
+	    System.exit(1);
+	}
+
+	frame = new Frame("Viewer");
+	frame.add((Component)dh.getBean(bi));
+	frame.setSize(new Dimension(400,300));
+	frame.show();
+    }
+}
diff --git a/demo/src/main/java/JAFApp.java b/demo/src/main/java/JAFApp.java
new file mode 100644
index 0000000..6531f49
--- /dev/null
+++ b/demo/src/main/java/JAFApp.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.io.*;
+import javax.activation.*;
+
+public class JAFApp extends Frame implements WindowListener, ItemListener, ActionListener {
+
+    // UI stuff...
+    private GridBagLayout gridbag = null;
+    private GridBagLayout panel_gb = null;
+    private List file_list = null;
+    private Panel results_panel = null;
+    private Label f_title = null;
+    private Label f_name_label = null;
+    private Label type_label = null;
+    private Label type_title = null;
+    private Button launch_button = null;
+    private Choice verb_choice = null;
+    // File stuff...
+    private File _file = null;
+    // private FileDataSource fds[] = null;
+    private DataHandler dh[] = null;
+
+    private boolean debug = false;
+    //    private 
+    ///////////////////////////////////////////////////////////////////////
+    // ctor
+    public JAFApp(String title)
+	{
+	   super(title);
+	   initMe();
+	}
+
+    public JAFApp()
+	{
+	    super();
+	    initMe();
+	}
+    
+    ///////////////////////////////////////////////////////////////////////
+    // initME -- init the UI
+    private void initMe()
+	{
+	    Font label_font = new Font("Default", Font.PLAIN, 12);
+	    Font title_font = new Font("Default", Font.BOLD, 12);
+
+	    gridbag = new GridBagLayout();
+	    setLayout(gridbag);
+	    
+	    this.setBackground(Color.white);
+
+	    // results panel create
+	    results_panel = new Panel();
+	    panel_gb = new GridBagLayout();
+	    results_panel.setLayout(panel_gb);
+	    results_panel.setBackground(Color.lightGray);
+	    addGridComponent(this,
+			     results_panel,
+			     gridbag,
+			     0,0,
+			     1,1,
+			     1,0 );
+
+	    // file name label
+	    f_title = new Label("File Name:");
+	    f_title.setBackground(Color.lightGray);
+	    f_title.setAlignment(Label.RIGHT);
+	    f_title.setFont(title_font);	    
+	    addGridComponent(results_panel,
+			     f_title,
+			     panel_gb,
+			     0, 0,
+			     1, 1,
+			     5, 100);
+
+	    // file name label
+	    f_name_label = new Label("<none selected>");
+	    f_name_label.setBackground(Color.lightGray);
+	    f_name_label.setAlignment(Label.LEFT);
+	    f_name_label.setFont(label_font);
+	    addGridComponent(results_panel,
+			     f_name_label,
+			     panel_gb,
+			     1, 0,
+			     1, 1,
+			     15, 100);
+	    
+	    	    // file name label
+	    f_title = new Label("MIME Type:");
+	    f_title.setBackground(Color.lightGray);
+	    f_title.setAlignment(Label.RIGHT);
+	    f_title.setFont(title_font);	    
+	    addGridComponent(results_panel,
+			     f_title,
+			     panel_gb,
+			     2, 0,
+			     1, 1,
+			     5, 100);
+
+	    // type_label
+	    type_label = new Label("<no type>");
+	    type_label.setBackground(Color.lightGray);
+	    type_label.setAlignment(Label.LEFT);
+	    type_label.setFont(label_font);
+	    addGridComponent(results_panel,
+			     type_label,
+			     panel_gb,
+			     3,0,
+			     1,1,
+			     10, 100);
+
+	    // launch button
+	    launch_button = new Button("Launch!");
+	    launch_button.setEnabled( false );
+	    launch_button.setBackground(Color.red);
+	    launch_button.setFont(title_font);
+	    addGridComponent(results_panel,
+			     launch_button,
+			     panel_gb,
+			     4,0,
+			     1,1,
+			     5, 100);
+	    
+	    // verb popup
+	    verb_choice = new Choice();
+	    verb_choice.setEnabled( false );
+	    verb_choice.setFont(label_font);
+	    verb_choice.add("<empty>");
+	    addGridComponent(results_panel,
+			     verb_choice,
+			     panel_gb,
+			     5,0,
+			     1,1,
+			     10, 100);
+
+	    // file list
+	    file_list = new List();
+	    file_list.setBackground(Color.white);
+	    file_list.setFont(label_font);
+	    addGridComponent(this,
+			     file_list,
+			     gridbag,
+			     0,1,
+			     1, 2,
+			     1,1);
+
+	    this.invalidate();
+
+	    // set up events
+	    this.addWindowListener(this);
+	    file_list.addItemListener(this);
+	    launch_button.addActionListener(this);
+
+	}
+
+    ////////////////////////////////////////////////////////////////////////
+    /**
+     * adds a component to our gridbag layout
+     */
+    private void addGridComponent(Container cont, 
+				  Component comp,
+				  GridBagLayout mygb,
+				  int gridx,
+				  int gridy, 
+				  int gridw,
+				  int gridh,
+				  int weightx,
+				  int weighty)
+	{ 
+	    GridBagConstraints c = new GridBagConstraints(); 
+	    c.gridx = gridx; 
+	    c.gridy = gridy; 
+	    c.gridwidth = gridw; 
+	    c.gridheight = gridh; 
+	    c.fill = GridBagConstraints.BOTH;
+	    c.weighty = weighty;
+	    c.weightx = weightx;
+	    c.anchor =  GridBagConstraints.CENTER;
+	    mygb.setConstraints(comp, c); 
+	    cont.add(comp); 
+	}
+
+    ///////////////////////////////////////////////////////////////////////
+    // setFile - sets the file/directory for this frame at startup usually
+    //
+    public void setFile( File file )
+	{
+	    _file = file;
+	    int i;
+	    MailcapCommandMap cmdmap = 
+		(MailcapCommandMap)CommandMap.getDefaultCommandMap();
+	    cmdmap.addMailcap("application/x-int;      jaf.viewers.IntViewer");
+
+	    if(_file.isFile())
+		{
+		    dh = new DataHandler[1];
+		    dh[0] = new DataHandler(new FileDataSource( _file ));
+
+		    file_list.add( dh[0].getName() );
+		}
+	    else if( _file.isDirectory() )
+		{
+		    String files[] = _file.list();
+		    MimetypesFileTypeMap map = new MimetypesFileTypeMap();
+		    map.addMimeTypes("text/java java\n");
+		    FileTypeMap.setDefaultFileTypeMap(map);
+		    dh = new DataHandler[ files.length ];
+		    // iterate through the list and make fds
+		    for( i = 0; i < files.length; i++)
+			{
+
+
+			    if(debug)
+				System.out.println(files[i]);
+
+			    dh[i] = new  DataHandler(
+					   new FileDataSource( _file.getAbsolutePath() +
+							       _file.separator +  
+							       files[i] )
+					   );
+			    dh[i].setCommandMap(cmdmap);
+
+// 			    try {
+// 				((FileDataSource)dh[i].getDataSource()).addMimeTypes("text/plain java\n");
+// 			    } catch(IOException e){ System.out.println(e); }
+			    file_list.add(dh[i].getName());
+			}
+		    System.out.println("number of files: " + files.length +
+				       " read : " + i);
+
+		}
+
+	}
+    /////////////////***ACTION LISTENER***///////////////////////
+    // is called when a monkey (user) presses the launch button
+    public void actionPerformed(ActionEvent evt)
+	{
+	    Object source = evt.getSource();
+	    int index = file_list.getSelectedIndex();
+	    
+	    // make sure it's the launch button and that
+	    // a list item is selected...
+	    if(source == launch_button && index > -1){
+		CommandInfo cmds[] = null;
+		String mimeType = dh[index].getContentType();
+		
+		if(debug)
+		    System.out.println("Finding...");
+		
+		// get the available commands for this type
+		cmds = dh[index].getPreferredCommands();
+		
+		// if we actually got some back...
+		if(cmds.length > 0){ 
+		    CompViewer cont = null;
+		    Object my_bean = null;
+		    // take the first one
+		    if(debug)
+			System.out.println("Launching...");
+		    
+		    // get the first one
+		    my_bean = dh[index].getBean( cmds[verb_choice.getSelectedIndex()] );
+		    
+			    // if it isn't a CommandObject we still
+			    // have to give it it's data...
+// 			    if(!(my_bean instanceof javax.activation.CommandObject))
+// 				{
+// 				    System.out.println("WHOOOAAA!");
+// 				    if(my_bean instanceof 
+// 				       java.io.Externalizable)
+		
+// 					{
+// 					    try
+// 						{
+//                 	     ((Externalizable)my_bean).readExternal(
+// 						new ObjectInputStream( 
+// 						   dh[index].getInputStream() 
+// 						   )
+// 						);
+// 						} catch(Exception e)
+// 						    {
+// 				  System.out.println("There was a problem reading the Externalized Data in the viewer bean : " + e);
+// 						    }
+// 					}
+// 				}
+		    if(debug)
+			System.out.println("GOTTA BEAN!: " + 
+					   my_bean.getClass().getName() );
+			    // create a new bean container
+		    cont = new CompViewer( "JAF Component" );
+		    cont.setBean( (Component) my_bean);
+		    cont.show();
+		}
+	    }
+	}
+    /////////////////***ITEM LISTENER***/////////////////////////
+    public void itemStateChanged(ItemEvent evt)
+	{
+	    Integer id = (Integer)evt.getItem();
+
+	    if(evt.getStateChange() == ItemEvent.SELECTED)
+		{
+		    // get the content type from the data handler...
+		    String mime_type = dh[id.intValue()].getContentType();
+		    // set the state in the info dlog:
+		    f_name_label.setText(dh[id.intValue()].getName());
+		    
+		    // set the field in the UI and enable launch button
+		    if(mime_type != null)
+			{
+			    CommandInfo cmds[] = null;
+			    // set the text label
+			    type_label.setText(mime_type);
+
+			    // check to see if any commands are available
+			    cmds = dh[id.intValue()].getPreferredCommands();
+			    if(cmds != null && cmds.length > 0) // we got a command!
+				{
+				    launch_button.setEnabled( true );
+				    verb_choice.setEnabled( true );
+				    launch_button.setBackground( Color.green );
+
+				    verb_choice.removeAll();
+				    for(int i = 0; i < cmds.length; i++)
+					{
+					    //		    verb_choice.addItem(cmds[i].getBeanDescriptor().getName());
+					    verb_choice.addItem(cmds[i].getCommandName());
+					}
+				}
+			    else
+				{
+				    launch_button.setEnabled( false );
+				    verb_choice.setEnabled( false );
+				    launch_button.setBackground( Color.red );
+				}
+			    
+			}
+		    else
+			{
+			    // set label to be unknown and launch button off!
+			    type_label.setText("<unknown>");
+			    launch_button.setEnabled( false );
+			    launch_button.setBackground( Color.red );
+			}
+		    
+		}
+	}
+    /////////////////***WINDOW LISTENER***////////////////////////
+    public void windowOpened(WindowEvent e){}
+    public void windowClosing(WindowEvent e)
+	{
+	    System.exit(0); // quit
+	}
+    public void windowClosed(WindowEvent e){}
+    public void windowIconified(WindowEvent e){}
+    public void windowDeiconified(WindowEvent e){}
+    public void windowActivated(WindowEvent e){}
+    public void windowDeactivated(WindowEvent e){}
+	    
+    ///////////////////////////////////////////////////////////////////////
+    // main
+    public static void main(String args[])
+	{
+	    JAFApp appFrame = new JAFApp("JAF Testing Application");
+	    appFrame.setSize(600, 400);
+	    appFrame.show();
+
+	    // set the directory
+	    if(args.length == 0)
+		{
+		    appFrame.setFile( new File("."));
+		}
+	    else
+		{
+		    appFrame.setFile( new File(args[0]) );
+		}
+	}
+
+	    
+}
diff --git a/demo/src/main/java/MCDump.java b/demo/src/main/java/MCDump.java
new file mode 100644
index 0000000..eab6d9a
--- /dev/null
+++ b/demo/src/main/java/MCDump.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import java.beans.*;
+import com.sun.activation.registries.*;
+import javax.activation.*;
+
+/**
+ * Dump out everything we know about a MailcapCommandMap.
+ */
+public class MCDump {
+    static MailcapCommandMap mcf = null;
+
+    public static void main(String args[]) {
+	
+	try {
+	    if (args.length == 0)
+		mcf = new MailcapCommandMap();
+	    else
+		mcf = new MailcapCommandMap(args[0]);
+	} catch (Exception e){ 
+	    e.printStackTrace();
+	    System.exit(1);
+	}
+
+	String[] types = mcf.getMimeTypes();
+	if (types == null) {
+	    System.out.println("No known MIME types");
+	    System.exit(0);
+	} else {
+	    System.out.println("Known MIME types:");
+	    for (int i = 0; i < types.length; i++)
+		System.out.println("\t" + types[i]);
+	}
+
+	System.out.println();
+	System.out.println("All commands for each MIME type:");
+	for (int i = 0; i < types.length; i++) {
+	    System.out.println("    " + types[i]);
+	    CommandInfo[] cmdinfo = mcf.getAllCommands(types[i]);
+	    if (cmdinfo == null) {
+		System.out.println("\tNONE");
+	    } else {
+		for (int k = 0; k < cmdinfo.length; k++)
+		    System.out.println("\t" + cmdinfo[k].getCommandName() +
+			": " + cmdinfo[k].getCommandClass());
+	    }
+	}
+
+	System.out.println();
+	System.out.println("Preferred commands for each MIME type:");
+	for (int i = 0; i < types.length; i++) {
+	    System.out.println("    " + types[i]);
+	    CommandInfo[] cmdinfo = mcf.getPreferredCommands(types[i]);
+	    if (cmdinfo == null) {
+		System.out.println("\tNONE");
+	    } else {
+		for (int k = 0; k < cmdinfo.length; k++)
+		    System.out.println("\t" + cmdinfo[k].getCommandName() +
+			": " + cmdinfo[k].getCommandClass());
+	    }
+	}
+
+	System.out.println();
+	System.out.println("Native commands for each MIME type:");
+	for (int i = 0; i < types.length; i++) {
+	    System.out.println("    " + types[i]);
+	    String[] cmds = mcf.getNativeCommands(types[i]);
+	    if (cmds.length == 0) {
+		System.out.println("\tNONE");
+	    } else {
+		for (int k = 0; k < cmds.length; k++)
+		    System.out.println("\t" + cmds[k]);
+	    }
+	}
+    }
+}
diff --git a/demo/src/main/java/MCTest.java b/demo/src/main/java/MCTest.java
new file mode 100644
index 0000000..b34ffac
--- /dev/null
+++ b/demo/src/main/java/MCTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import java.beans.*;
+import com.sun.activation.registries.*;
+import javax.activation.*;
+
+public class MCTest {
+    static MailcapCommandMap mcf = null;
+
+    public static void main(String args[]) {
+	
+	try {
+	    if (args.length == 0)
+		mcf = new MailcapCommandMap();
+	    else
+		mcf = new MailcapCommandMap(args[0]);
+	} catch (Exception e){ 
+	    e.printStackTrace();
+	    System.exit(1);
+	}
+
+	CommandInfo cmdinfo[] = mcf.getAllCommands("text/plain");
+        System.out.print("Are there any commands for text/plain?");
+
+	if (cmdinfo != null) {
+	    System.out.println("number of cmds = " + cmdinfo.length);
+	    System.out.println("now try an individual cmd");
+	    CommandInfo info = mcf.getCommand("text/plain", "view");
+	    if (info != null) {
+		System.out.println("Got command...");
+	    } else {
+		System.out.println("no cmds");
+	    }
+
+	    mcf.addMailcap("text/plain;; x-java-flobotz=com.sun.activation.flobotz\n");	
+	    //	    System.out.println("...dome");
+	    if (cmdinfo != null) {
+		cmdinfo = mcf.getAllCommands("text/plain");
+		System.out.println("now we have cmds = " + cmdinfo.length);
+		
+	    }	
+
+        } else {
+	    System.out.println("NO CMDS AT ALL!");
+	}
+    }
+}
diff --git a/demo/src/main/java/ODCHTest.java b/demo/src/main/java/ODCHTest.java
new file mode 100644
index 0000000..a4c1183
--- /dev/null
+++ b/demo/src/main/java/ODCHTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import javax.activation.*;
+import java.awt.datatransfer.*;
+
+public class ODCHTest {
+    private FileDataSource fds = null;
+    private DataHandler dh = null;
+    private DataContentHandlerFactory dchf = null;
+    private String str;
+    /**
+     * main function
+     */
+    public static void main(String args[]) {
+	ODCHTest test = new ODCHTest();
+	
+	if(args.length != 0) {
+	    System.out.println("usage: ODCHTest");
+	    System.exit(1);
+	}
+	
+	// first let's get a DataSource
+
+	
+	test.doit();
+    }
+
+    private void doit() {
+	DataFlavor xfer_flavors[];
+	Object content = null;
+
+	str = new String("This is a test");
+
+	// now let's create a DataHandler
+	dh = new DataHandler(str, "text/plain");
+	System.out.println("ODCHTest: DataHandler created with str & text/plain");
+
+	// now lets set a DataContentHandlerFactory
+	dchf = new SimpleDCF("text/plain:PlainDCH\n");
+	System.out.println("ODCHTest: Simple dchf created");
+	
+	// now let's set the dchf in the dh
+	dh.setDataContentHandlerFactory(dchf);
+	System.out.println("ODCHTest: DataContentHandlerFactory set in DataHandler");
+	
+	// get the dataflavors
+	xfer_flavors = dh.getTransferDataFlavors();
+	System.out.println("ODCHTest: dh.getTransferDF returned " +
+			   xfer_flavors.length + " data flavors.");
+
+	// get the content:
+        try {
+	   content = dh.getContent();
+        } catch (Exception e) { e.printStackTrace(); }
+
+	if(content == null)
+	    System.out.println("ODCHTest: no content to be had!!!");
+	else {
+	    System.out.println("ODCHTest: got content of the following type: " +
+			       content.getClass().getName());
+	    if(content == str)
+		System.out.println("get content works");
+	    
+	}
+    }
+	    
+}
diff --git a/demo/src/main/java/PlainDCH.java b/demo/src/main/java/PlainDCH.java
new file mode 100644
index 0000000..447937b
--- /dev/null
+++ b/demo/src/main/java/PlainDCH.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import java.awt.datatransfer.DataFlavor;
+import javax.activation.*;
+
+
+public class PlainDCH implements DataContentHandler {
+    /**
+     * return the DataFlavors for this <code>DataContentHandler</code>
+     * @return The DataFlavors.
+     */
+    public DataFlavor[] getTransferDataFlavors() { // throws Exception;
+	DataFlavor flavors[] = new DataFlavor[2];
+	
+
+	try {
+	    flavors[0] = new ActivationDataFlavor(Class.forName("java.lang.String"),
+					   "text/plain",
+					   "text string");
+	} catch(Exception e)
+	    { System.out.println(e); }
+
+	flavors[1] = new DataFlavor("text/plain", "Plain Text");
+	return flavors;
+    }
+    /**
+     * return the Transfer Data of type DataFlavor from InputStream
+     * @param df The DataFlavor.
+     * @param ins The InputStream corresponding to the data.
+     * @return The constructed Object.
+     */
+    public Object getTransferData(DataFlavor df, DataSource ds) {
+	
+	// this is sort of hacky, but will work for the
+	// sake of testing...
+	if(df.getMimeType().equals("text/plain")) {
+	    if(df.getRepresentationClass().getName().equals(
+					       "java.lang.String")) {
+		// spit out String
+		StringBuffer buf = new StringBuffer();
+		char data[] = new char[1024];
+		// InputStream is = null;
+		InputStreamReader isr = null;
+		int bytes_read = 0;
+		int total_bytes = 0;
+
+		try {
+		    isr = new InputStreamReader(ds.getInputStream());
+		    
+// 		    while(is.read(data) > 0)
+// 			buf.append(data);
+
+		    while(true){
+			bytes_read = isr.read(data);
+			if(bytes_read > 0)
+			    buf.append(data, total_bytes, bytes_read);
+			else
+			    break;
+			total_bytes += bytes_read;
+		    } 
+		} catch(Exception e) {}
+
+		return buf.toString();
+		
+	    }
+	    else if(df.getRepresentationClass().getName().equals(
+					     "java.io.InputStream")){
+		// spit out InputStream
+		try {
+		    return ds.getInputStream();
+		} catch (Exception e) {}
+	    }
+		
+	} 
+
+	    return null;
+    }
+    
+    /**
+     *
+     */
+    public Object getContent(DataSource ds) { // throws Exception;
+	StringBuffer buf = new StringBuffer();
+	char data[] = new char[1024];
+	// InputStream is = null;
+	InputStreamReader isr = null;
+	int bytes_read = 0;
+	int total_bytes = 0;
+	
+	try {
+	    isr = new InputStreamReader(ds.getInputStream());
+	    
+	    // 		    while(is.read(data) > 0)
+	    // 			buf.append(data);
+	    
+	    while(true){
+		bytes_read = isr.read(data);
+		if(bytes_read > 0)
+		    buf.append(data, total_bytes, bytes_read);
+		else
+		    break;
+		total_bytes += bytes_read;
+	    } 
+	} catch(Exception e) {}
+	
+	return buf.toString();
+    }
+    /**
+     * construct an object from a byte stream
+     * (similar semantically to previous method, we are deciding
+     *  which one to support)
+     */
+    public void writeTo(Object obj, String mimeTye, OutputStream os) 
+	throws IOException {
+	// throws Exception;
+    }
+    
+}
diff --git a/demo/src/main/java/PrefTest.java b/demo/src/main/java/PrefTest.java
new file mode 100644
index 0000000..b165fda
--- /dev/null
+++ b/demo/src/main/java/PrefTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.io.*;
+import java.beans.*;
+import javax.activation.*;
+
+public class PrefTest {
+
+    public static void main(String args[]) {
+	MailcapCommandMap mcf = null;
+
+	if (args.length > 0) {
+	    try {
+		mcf = new MailcapCommandMap(args[0]);
+	    } catch (Exception e) {
+		e.printStackTrace();
+		System.exit(1);
+	    }
+	} else
+	    mcf = new MailcapCommandMap();
+
+	CommandInfo cmdinfo[] = mcf.getAllCommands("text/plain");
+	
+	if (cmdinfo != null) {
+	    System.out.println("ALL Commands for text/plain:");
+	    for (int i = 0; i < cmdinfo.length; i++) {
+		System.out.println("Verb: " + cmdinfo[i].getCommandName() +
+				  " Class: " + cmdinfo[i].getCommandClass());
+	    }
+	    System.out.println("done");
+	} else {
+	    System.out.println("no commands");
+	}
+	System.out.println();
+
+	cmdinfo = mcf.getPreferredCommands("text/plain");
+	if (cmdinfo != null) {
+	    System.out.println("PREFERRED Commands for text/plain:");
+	    for (int i = 0; i < cmdinfo.length; i++) {
+		System.out.println("Verb: " + cmdinfo[i].getCommandName() +
+				  " Class: " + cmdinfo[i].getCommandClass());
+	    }
+	    System.out.println("done");
+	} else {
+	    System.out.println("no commands");
+	}
+	System.out.println();
+    }
+}
diff --git a/demo/src/main/java/SimpleDCF.java b/demo/src/main/java/SimpleDCF.java
new file mode 100644
index 0000000..c7997dc
--- /dev/null
+++ b/demo/src/main/java/SimpleDCF.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import javax.activation.*;
+import java.util.StringTokenizer;
+import java.util.Hashtable;
+
+public class SimpleDCF implements DataContentHandlerFactory {
+    Hashtable entry_hash = new Hashtable();
+    /**
+     * the constructor, takes a list of classes as an argument in the
+     * form:
+     * <mimetype>:<class name>\n
+     *
+     * For Example:
+     *
+     * application/x-wombat:com.womco.WombatDCH
+     * text/plain:com.textco.TextDCH
+     *
+     */
+    public SimpleDCF(String entries) {
+	StringTokenizer tok = new StringTokenizer(entries);
+
+	String entry;
+	System.out.println("SimpleDCH: new SimpleDCF being created");
+
+	// parse the string
+	while(tok.hasMoreTokens()) {
+	    int colon;
+
+	    entry = tok.nextToken();
+	    System.out.println("full entry = " + entry);
+
+	    // parse out the fields
+	    colon = entry.indexOf(':');
+	    VectorEntry ve = new VectorEntry(entry.substring(0,colon),
+					     entry.substring(colon + 1, 
+							     entry.length()));
+	    System.out.println("adding element = " + ve);
+	    entry_hash.put(ve.getMimeType(),ve);
+	}
+    }
+
+    /**
+     * implement the factor interface
+     */
+    public DataContentHandler createDataContentHandler(String mimeType){
+	DataContentHandler dch = null;
+
+	System.out.print("SimpleDCF: trying to create a DCH");
+
+	VectorEntry ve = (VectorEntry)entry_hash.get(mimeType);
+	if(ve != null) {
+	    System.out.print("...found token");
+	    try { 
+		
+		dch = (DataContentHandler)Class.forName(
+					ve.getClassName()).newInstance();
+		if(dch == null)
+		    System.out.println("...FAILED!!!");
+		else
+		    System.out.println("...SUCCESS!!!");
+
+	    } catch(Exception e) {
+		System.out.println(e);
+	    }
+	}
+	return dch;
+    }
+}
+
+class VectorEntry {
+    private String mimeType;
+    private String className;
+
+    public VectorEntry(String mimeType, String className) {
+	this.mimeType = mimeType;
+	this.className = className;
+    }
+    
+    public String getMimeType() { return mimeType; }
+    public String getClassName() { return className; }
+    public String toString() { 
+	return new String("type: " + mimeType + " class name: " + className);
+    }
+
+}
diff --git a/demo/src/main/java/TextInternalizer.java b/demo/src/main/java/TextInternalizer.java
new file mode 100644
index 0000000..a7ed047
--- /dev/null
+++ b/demo/src/main/java/TextInternalizer.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0, which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import java.awt.*;
+import java.io.*;
+import java.beans.*;
+import javax.activation.*;
+
+public class TextInternalizer extends Panel implements Externalizable {
+    // UI Vars...
+    private TextArea text_area = null;
+    
+    // File Vars
+    private File text_file = null;
+    private String text_buffer = null;
+    
+    private DataHandler _dh = null;
+    private boolean DEBUG = false;
+    /**
+     * Constructor
+     */
+    public TextInternalizer() {
+	System.out.println("TextInternalizer!!!!!");
+
+	setLayout( new GridLayout(1,1));
+	// create the text area
+	text_area = new TextArea("", 24, 80, 
+				 TextArea.SCROLLBARS_VERTICAL_ONLY );
+	text_area.setEditable( false );
+	
+	add(text_area);
+    }
+    
+    public void writeExternal(ObjectOutput out) throws IOException{
+
+    }
+
+    public void readExternal(ObjectInput in) throws IOException, 
+	ClassNotFoundException {
+
+	
+	this.setObjectInput(in);
+    }
+
+
+
+    //--------------------------------------------------------------------
+//     public void setCommandContext(String verb, DataHandler dh) throws IOException {
+// 	_dh = dh;
+// 	this.setInputStream( _dh.getInputStream() );
+//     }
+  //--------------------------------------------------------------------
+
+  /**
+   * set the data stream, component to assume it is ready to
+   * be read.
+   */
+  public void setObjectInput(ObjectInput ins) throws IOException {
+      try {
+
+      text_buffer = (String)ins.readObject();
+      } catch(Exception e){ e.printStackTrace(); }
+      // place in the text area
+      text_area.setText(text_buffer);
+
+    }
+  //--------------------------------------------------------------------
+    public void addNotify() {
+	super.addNotify();
+	invalidate();
+    }
+  //--------------------------------------------------------------------
+    public Dimension getPreferredSize()	{
+	return text_area.getMinimumSize(24, 80);
+    }
+
+}
+
+
+
+
+
+
diff --git a/doc/release/LICENSE.md b/doc/release/LICENSE.md
new file mode 100644
index 0000000..e0358f9
--- /dev/null
+++ b/doc/release/LICENSE.md
@@ -0,0 +1,29 @@
+
+    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+   
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+   
+      - Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+   
+      - Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+   
+      - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+   
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/doc/release/README.txt b/doc/release/README.txt
new file mode 100644
index 0000000..25eecb3
--- /dev/null
+++ b/doc/release/README.txt
@@ -0,0 +1,21 @@
+	  **JAVABEANS(tm) ACTIVATION FRAMEWORK 1.2 RELEASE**
+
+Thank you for downloading the release of the JavaBeans(tm) Activation
+Framework!  We hope you find it useful.  Included in this release are
+the following files and directories:
+
+README.txt     : This file!
+
+RELNOTES.txt   : The release notes for this release including,
+                 installation instructions, system requirements, 
+                 known bugs, and open issues.
+
+LICENSE.txt    : The license covering this software.
+
+javax.activation.jar : This JAR file contains the classes that
+                 make up JavaBeans(tm) Activation Framework.
+
+demo           : This directory contains some simple *unsupported*
+                 demos that make use of some of the JAF's features.
+
+doc            : This directory contains the JAF specification.
diff --git a/doc/release/RELNOTES.txt b/doc/release/RELNOTES.txt
new file mode 100644
index 0000000..a07f374
--- /dev/null
+++ b/doc/release/RELNOTES.txt
@@ -0,0 +1,62 @@
+	 JavaBeans(tm) Activation Framework 1.2 Release Notes
+
+Welcome to the JavaBeans(tm) Activation Framework!
+
+System Requirements:
+--------------------
+
+The JavaBeans(tm) Activation Framework (JAF) was developed and tested
+against JDK 1.5.  JAF is written in Java (with no native code).  It
+will run on any JDK 1.5 (or newer) compatible virtual machine.
+
+Note that JAF is included in Java SE 6 and later releases.
+
+Installation:
+-------------
+
+There is effectively *no* installation of the JAF. The classes that
+make up the JAF are contained in the included Java(tm) Archive (JAR) file,
+"javax.activation.jar". This file can be placed anywhere accessible to the
+Java virtual machine running on your system. The only requirement is
+that the javax.activation.jar be included in your system's class path so
+Java can find the JAF classes.
+
+Related Web Sites:
+------------------
+
+There are a number of web sites you might find useful if you haven't
+already run across them:
+
+https://github.com/eclipse-ee4j/javamail -- The JavaMail(tm) API provides a set
+                             of abstract classes that model a mail system.
+                             Its implementation is dependent on the JAF.
+
+
+Bugs fixed in the 1.2 Release:
+------------------------------
+
+JDK-8047773 Remove JAF's API dependency on java.beans.Beans.instantiate
+JDK-8049379 JDK 1.9 moves config files to <java.home>/conf
+
+
+Bugs fixed in the 1.1.1 Release:
+--------------------------------
+
+6456395	DataHandler.writeTo should have built-in support for byte arrays
+	and Strings
+6538484	JAF fails in Turkish locale
+
+
+Bugs fixed in the 1.1 Release:
+------------------------------
+
+<no id>	use context class loader to load data content handlers
+<no id>	guard against possible NPE when parsing mailcap file
+<no id>	really make sure input stream gets closed in DataHandler.writeTo
+4134676	need way to find all known MIME types
+4786035	API doc: some bugs in javax/activation/MimeType.cmnt
+4848096	MailcapCommandMap should store *ALL* mailcap entries
+5090200	CommandMap needs file name to choose proper command on Windows
+6245613	fix ActivationDataFlavor normalize methods to match DataFlavor
+6252930	MailcapCommandMap needs support for "fallback" entries in mailcap file
+6357487	DataHandler.getBean should load class using application's class loader
diff --git a/doc/spec/JAF-1.1-changes.txt b/doc/spec/JAF-1.1-changes.txt
new file mode 100644
index 0000000..531c7a3
--- /dev/null
+++ b/doc/spec/JAF-1.1-changes.txt
@@ -0,0 +1,197 @@
+
+		JavaBeans Activation Framework 1.1
+		==================================
+
+Please send comments and feedback to activation-comments@sun.com.
+
+The JavaBeans Activation Framework (JAF) 1.0 has been in use for eight
+years.  In that time it has served its original purpose quite well,
+with only a few enhancements being requested.
+
+JAF 1.1 proposes a few minor changes to the JAF APIs to address the
+most commonly requested enhancements.  Following is a description of
+the new APIs that are being introduced in JAF 1.1.  The numbers in
+parentheses are bug numbers; you can find more information about the
+bug reports at:
+
+    http://bugs.sun.com
+
+The JAF 1.1 RI will require J2SE 1.4 or later.  (The JAF 1.0.2 RI
+requires only JDK 1.1.6.)  JAF 1.1 will be included in J2EE 5.0
+and J2SE 6.0.
+
+The JAF 1.1 RI and TCK will be available under the same terms as the
+JAF 1.0 RI and TCK.
+
+
+===================================================================
+
+1.  Need way to find all known MIME types (4134676)
+---------------------------------------------------
+
+To support this we add a new method to CommandMap:
+
+    /**
+     * Get all the MIME types known to this command map.
+     * If the command map doesn't support this operation,
+     * null is returned.
+     *
+     * @return		array of MIME types as strings, or null if not supported
+     * @since	JAF 1.1
+     */
+    public String[] getMimeTypes()
+
+The default implementation of this method returns null for
+compatibility with applications that have provided a CommandMap
+implementation based on JAF 1.0.  The JAF 1.1 implementation of
+MailcapCommandMap will return all the MIME types known to the
+command map.
+
+
+===================================================================
+
+2.  CommandMap needs file name to choose proper command on Windows (5090200)
+----------------------------------------------------------------------------
+
+This RFE requests additional CommandMap methods that allow
+the CommandMap implementation to determine the file name, to
+better support systems such as Windows that use the file name
+extension to choose between the commands available to support
+a given MIME type.  We add the following methods to CommandMap:
+
+    /**
+     * Get the preferred command list from a MIME Type. The actual semantics
+     * are determined by the implementation of the CommandMap. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the list of commands that are returned.  The implementation
+     * in this class simply calls the <code>getPreferredCommands</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo classes that represent the command Beans.
+     * @since	JAF 1.1
+     */
+    public CommandInfo[] getPreferredCommands(String mimeType, DataSource ds)
+
+    /**
+     * Get all the available commands for this type. This method
+     * should return all the possible commands for this MIME type. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the list of commands that are returned.  The implementation
+     * in this class simply calls the <code>getAllCommands</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo objects representing all the commands.
+     * @since	JAF 1.1
+     */
+    public CommandInfo[] getAllCommands(String mimeType, DataSource ds)
+
+    /**
+     * Get the default command corresponding to the MIME type. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the command that is chosen.  The implementation
+     * in this class simply calls the <code>getCommand</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param cmdName	the command name
+     * @param ds	a DataSource for the data
+     * @return the CommandInfo corresponding to the command.
+     * @since	JAF 1.1
+     */
+    public CommandInfo getCommand(String mimeType, String cmdName,
+				DataSource ds)
+
+    /**
+     * Locate a DataContentHandler that corresponds to the MIME type.
+     * The mechanism and semantics for determining this are determined
+     * by the implementation of the particular CommandMap. <p>
+     *
+     * The <code>DataSource</code> provides extra information, such as
+     * the file name, that a CommandMap implementation may use to further
+     * refine the choice of DataContentHandler.  The implementation
+     * in this class simply calls the <code>createDataContentHandler</code>
+     * method that ignores this argument.
+     *
+     * @param mimeType	the MIME type
+     * @param ds	a DataSource for the data
+     * @return		the DataContentHandler for the MIME type
+     * @since	JAF 1.1
+     */
+    public DataContentHandler createDataContentHandler(String mimeType,
+				DataSource ds)
+
+
+As described, the default implementations of these methods simply
+call the existing CommandMap methods that don't require a
+DataSource object.  The DataHandler implementation is changed to
+call these new methods if created with a DataSource.
+
+The JAF 1.1 Reference Implementation would not provide a CommandMap
+implementation that uses these new methods.
+
+
+===================================================================
+
+3.  MailcapCommandMap needs support for "fallback" entries (6252930)
+--------------------------------------------------------------------
+
+This RFE describes a problem with wildcard matching and providing
+fallbacks for JAF commands, in particular DataContentHandlers used
+by JavaMail.  To support the scenario described in that bug report,
+we add a special "command" entry that can be added to a mailcap
+entry to indicate that the mailcap entry defines fallback commands
+that should only be used if no regular entry is available.  An
+attribute of the form
+
+	x-java-fallback-entry=true
+
+in the mailcap entry indicates a fallback entry.  For example:
+
+	text/*;; x-java-fallback-entry=true; x-java-view=com.sun.TextViewer
+
+The MailcapCommandMap implementation supports this attribute.
+Methods that return an array of commands will include commands
+from fallback entries after commands from regular entries.
+Methods that use or return only a single command will search
+fallback entries after regular entries.  This two level hierarchy,
+in combination with the existing search rules for mailcap files,
+is sufficient to handle the common use cases.
+
+
+===================================================================
+
+4.  MailcapCommandMap should store *ALL* mailcap entries (4848096)
+------------------------------------------------------------------
+
+This RFE requests the ability to retrieve the native command
+line associated with a mailcap entry.  To support this we add
+a method to MailcapCommandMap:
+
+    /**
+     * Get the native commands for the given MIME type.
+     * Returns an array of strings where each string is
+     * an entire mailcap file entry.  The application
+     * will need to parse the entry to extract the actual
+     * command as well as any attributes it needs. See
+     * <A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>
+     * for details of the mailcap entry syntax.  Only mailcap
+     * entries that specify a view command for the specified
+     * MIME type are returned.
+     *
+     * @return	array of native command entries
+     * @since	JAF 1.1
+     */
+    public String[] getNativeCommands(String mimeType)
+
+An application can choose to use these native "view" commands
+using (e.g.) the Runtime.exec method.
diff --git a/doc/spec/JAF-1.2-changes.txt b/doc/spec/JAF-1.2-changes.txt
new file mode 100644
index 0000000..bfd349b
--- /dev/null
+++ b/doc/spec/JAF-1.2-changes.txt
@@ -0,0 +1,94 @@
+
+		JavaBeans Activation Framework 1.2
+		==================================
+
+JAF 1.2 proposes a few minor changes to the JAF specification to
+align with other changes in JDK 9.  Following is a description of
+the changes that are being introduced in JAF 1.2.  The numbers in
+parentheses are bug numbers; you can find more information about the
+bug reports at:
+
+    http://bugs.openjdk.java.net
+
+The JAF 1.2 RI will require Java SE 7 or later.  JAF 1.2 will be
+included in Java SE 9.
+
+The JAF 1.2 RI and TCK will be available under the same terms as the
+JAF 1.1 RI and TCK.
+
+
+===================================================================
+
+1.  JDK 9 moves config files to <java.home>/conf (JDK-8049379)
+----------------------------------------------------------------
+
+The specification for MailcapCommandMap is changed as follows:
+
+     * <b>Mailcap file search order:</b><p>
+     * The MailcapCommandMap looks in various places in the user's
+     * system for mailcap file entries. When requests are made
+     * to search for commands in the MailcapCommandMap, it searches
+     * mailcap files in the following order:
+     * <p>
+     * <ol>
+     * <li> Programatically added entries to the MailcapCommandMap instance.
+     * <li> The file <code>.mailcap</code> in the user's home directory.
+     * <li> The file <code>mailcap</code> in the Java runtime.
+     * <li> The file or resources named <code>META-INF/mailcap</code>.
+     * <li> The file or resource named <code>META-INF/mailcap.default</code>
+     * (usually found only in the <code>activation.jar</code> file).
+     * </ol>
+     * <p>
+     * (The current implementation looks for the <code>mailcap</code> file
+     * in the Java runtime in the directory <code><i>java.home</i>/conf</code>
+     * if it exists, and otherwise in the directory
+     * <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
+     * of the "java.home" System property.  Note that the "conf" directory was
+     * introduced in JDK 9.)
+
+
+The specification for MimetypesFileTypeMap is changed as follows:
+
+     * <b>MIME types file search order:</b><p>
+     * The MimetypesFileTypeMap looks in various places in the user's
+     * system for MIME types file entries. When requests are made
+     * to search for MIME types in the MimetypesFileTypeMap, it searches  
+     * MIME types files in the following order:
+     * <ol>
+     * <li> Programmatically added entries to the MimetypesFileTypeMap instance.
+     * <li> The file <code>.mime.types</code> in the user's home directory.
+     * <li> The file <code>mime.types</code> in the Java runtime.
+     * <li> The file or resources named <code>META-INF/mime.types</code>.
+     * <li> The file or resource named <code>META-INF/mimetypes.default</code>
+     * (usually found only in the <code>activation.jar</code> file).
+     * </ol>
+     * <p>
+     * (The current implementation looks for the <code>mime.types</code> file
+     * in the Java runtime in the directory <code><i>java.home</i>/conf</code>
+     * if it exists, and otherwise in the directory
+     * <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
+     * of the "java.home" System property.  Note that the "conf" directory was
+     * introduced in JDK 9.)
+
+
+===================================================================
+
+2.  Remove JAF's API dependency on java.beans.Beans.instantiate (JDK-804773)
+----------------------------------------------------------------------------
+
+To allow custom runtimes to be created without the java.desktop module,
+the getCommandObject method of CommandInfo is changed to make the use
+of java.beans.Beans.instantiate conditional:
+
+    /**
+     * Return the instantiated JavaBean component.
+     * <p>
+     * If the current runtime environment supports
+     * {@link java.beans.Beans#instantiate Beans.instantiate},
+     * use it to instantiate the JavaBeans component.  Otherwise, use
+     * {@link java.lang.Class#forName Class.forName}.
+     * <p>
+     * The component class needs to be public.
+     * On Java SE 9 and newer, if the component class is in a named module,
+     * it needs to be in an exported package.
+    ...
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1053cae
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,552 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+
+    Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Distribution License v. 1.0, which is available at
+    http://www.eclipse.org/org/documents/edl-v10.php.
+
+    SPDX-License-Identifier: BSD-3-Clause
+
+-->
+
+<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">
+    <parent>
+        <groupId>org.eclipse.ee4j</groupId>
+        <artifactId>project</artifactId>
+        <version>1.0.6</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.activation</groupId>
+    <artifactId>all</artifactId>
+    <packaging>pom</packaging>
+    <version>1.2.2</version>
+    <name>Jakarta Activation distribution</name>
+    <description>${project.name}</description>
+    <url>https://github.com/eclipse-ee4j/jaf</url>
+
+    <scm>
+        <connection>scm:git:ssh://git@github.com/eclipse/jaf.git</connection>
+        <developerConnection>scm:git:ssh://git@github.com/eclipse/jaf.git</developerConnection>
+        <url>https://github.com/eclipse-ee4j/jaf</url>
+      <tag>HEAD</tag>
+  </scm>
+
+    <issueManagement>
+        <system>github</system>
+        <url>https://github.com/eclipse-ee4j/jaf/issues/</url>
+    </issueManagement>
+
+    <licenses>
+        <license>
+            <name>EDL 1.0</name>
+            <url>http://www.eclipse.org/org/documents/edl-v10.php</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <properties>
+	<activation.spec.version>1.2</activation.spec.version>
+	<!-- defaults that are overridden in activation module -->
+	<activation.extensionName>
+	    ${project.groupId}.${project.artifactId}
+	</activation.extensionName>
+	<activation.specificationTitle>
+	    ${project.groupId}.${project.artifactId}
+	</activation.specificationTitle>
+	<activation.implementationTitle>
+	    ${project.groupId}.${project.artifactId}
+	</activation.implementationTitle>
+	<activation.bundle.symbolicName>
+	    ${project.groupId}.${project.artifactId}
+	</activation.bundle.symbolicName>
+	<activation.bundle.symbolicName>
+	    ${project.groupId}.${project.artifactId}
+	</activation.bundle.symbolicName>
+	<activation.packages.export>
+	    javax.activation.*; version=${activation.spec.version}
+	</activation.packages.export>
+	<activation.packages.import>
+	    *
+	</activation.packages.import>
+	<activation.packages.private>
+	    com.sun.activation.*
+	</activation.packages.private>
+	<!-- for the osgiversion-maven-plugin -->
+	<hk2.plugin.version>2.0.0</hk2.plugin.version>
+	<project.build.sourceEncoding>iso-8859-1</project.build.sourceEncoding>
+	<findbugs.threshold>
+	    High
+	</findbugs.threshold>
+	<findbugs.version>
+	    3.0.1
+	</findbugs.version>
+	<findbugs.skip>
+	    true
+	</findbugs.skip>
+	<findbugs.exclude/>
+        <copyright-plugin.version>2.2</copyright-plugin.version>
+    </properties>
+
+    <developers>
+	<developer>
+	    <id>shannon</id>
+	    <name>Bill Shannon</name>
+	    <email>bill.shannon@oracle.com</email>
+	    <organization>Oracle</organization>
+	    <roles>
+		<role>lead</role>
+	    </roles>
+	</developer>
+    </developers>
+
+    <!-- following to enable use of "mvn site:stage" -->
+    <distributionManagement>
+	<site>
+	    <id>oracle.com</id>
+	    <url>file:/tmp</url> <!-- not used -->
+	</site>
+    </distributionManagement>
+
+    <modules>
+	<module>activation</module>
+	<module>activationapi</module>
+    </modules>
+
+    <profiles>
+	<!--
+	    This profile contains modules that should only be built
+	    but not installed or deployed.
+	-->
+	<profile>
+	    <id>build-only</id>
+	    <modules>
+		<module>demo</module>
+	    </modules>
+	    <activation>
+		<activeByDefault>true</activeByDefault>
+	    </activation>
+	</profile>
+
+	<!--
+	    This profile is used for deploying a Jakarta Activation
+	    final release.
+
+	    Activating this profile manually for deployment causes
+	    the above profile to be deactivated, which works around
+	    an apparent bug in maven that prevents me from manually
+	    deactivating a profile.  This profile purposely has none
+	    of the modules I don't want to be deployed.
+	-->
+	<profile>
+	    <id>oss-release</id>
+	</profile>
+    </profiles>
+
+    <build>
+	<defaultGoal>install</defaultGoal>
+	<plugins>
+	    <!--
+		Make sure we're using the correct version of maven.
+	    -->
+	    <plugin>
+		<groupId>org.apache.maven.plugins</groupId>
+		<artifactId>maven-enforcer-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>enforce-version</id>
+			<goals>
+			    <goal>enforce</goal>
+			</goals>
+			<configuration>
+			    <rules>
+				<requireMavenVersion>
+				    <version>[3.0.3,)</version>
+				</requireMavenVersion>
+				<requireJavaVersion>
+				    <version>[9,)</version>
+				</requireJavaVersion>
+			    </rules>
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		This plugin is reponsible for packaging artifacts
+		as OSGi bundles.  Please refer to
+		http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html
+		for more information about how to use this plugin.
+	    -->
+	    <plugin>
+		<groupId>org.apache.felix</groupId>
+		<artifactId>maven-bundle-plugin</artifactId>
+		<configuration>
+		    <instructions>
+			<Bundle-SymbolicName>
+			    ${activation.bundle.symbolicName}
+			</Bundle-SymbolicName>
+			<Export-Package>
+			    ${activation.packages.export}
+			</Export-Package>
+			<Import-Package>
+			    ${activation.packages.import}
+			</Import-Package>
+			<Private-Package>
+			    ${activation.packages.private}
+			</Private-Package>
+			<DynamicImport-Package>
+			    *
+			</DynamicImport-Package>
+		    </instructions>
+		</configuration>
+		<!--
+		    Since we don't change the packaging type to bundle, we
+		    need to configure the plugin to execute the manifest goal
+		    during the process-classes phase of the build life cycle.
+		-->
+		<executions>
+		    <execution>
+			<id>osgi-manifest</id>
+			<phase>process-classes</phase>
+			<goals>
+			    <goal>manifest</goal>
+			</goals>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Since we don't want a qualifier like b05 or SNAPSHOT to
+		appear in the OSGi package version attribute, we use
+		the following plugin to populate a project property
+		with an OSGi version that is equivalent to the maven
+		version without the qualifier.
+	    -->
+	    <plugin>
+		<groupId>org.glassfish.hk2</groupId>
+		<artifactId>osgiversion-maven-plugin</artifactId>
+		<version>${hk2.plugin.version}</version>
+		<configuration>
+		    <dropVersionComponent>qualifier</dropVersionComponent>
+		    <versionPropertyName>activation.osgiversion</versionPropertyName>
+		</configuration>
+		<executions>
+		    <execution>
+			<id>compute-osgi-version</id>
+			<goals>
+			    <goal>compute-osgi-version</goal>
+			</goals>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Use the JDK 9+ compiler but with -source 1.8 for all
+		but the module-info.java file.
+	    -->
+	    <plugin>
+		<artifactId>maven-compiler-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>default-compile</id>
+			<configuration>
+			    <source>1.8</source>
+			    <target>1.8</target>
+			    <excludes>
+				<exclude>module-info.java</exclude>
+			    </excludes>
+			</configuration>
+		    </execution>
+		    <execution>
+			<id>module-info-compile</id>
+			<goals>
+			    <goal>compile</goal>
+			</goals>
+			<configuration>
+			    <release>9</release>
+			    <includes>
+				<include>module-info.java</include>
+			    </includes>
+			</configuration>
+		    </execution>
+		    <execution>
+			<id>default-testCompile</id>
+			<configuration>
+			    <release>9</release>
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <plugin>
+		<artifactId>maven-jar-plugin</artifactId>
+		<!-- need at least this version to make excludes work -->
+		<configuration>
+		    <finalName>${project.artifactId}</finalName>
+		    <archive>
+			<!--
+			    Configure the maven-jar-plugin to pick up
+			    META-INF/MANIFEST.MF that's generated by
+			    the maven-bundle-plugin.
+			-->
+			<manifestFile>
+			  ${project.build.outputDirectory}/META-INF/MANIFEST.MF
+			</manifestFile>
+			<manifestEntries>
+			    <Extension-Name>
+				${activation.extensionName}
+			    </Extension-Name>
+			    <Specification-Title>
+				${activation.specificationTitle}
+			    </Specification-Title>
+			    <Specification-Version>
+				${activation.spec.version}
+			    </Specification-Version>
+			    <Specification-Vendor>
+				${project.organization.name}
+			    </Specification-Vendor>
+			    <Implementation-Title>
+				${activation.implementationTitle}
+			    </Implementation-Title>
+			    <Implementation-Version>
+				${project.version}
+			    </Implementation-Version>
+			    <Implementation-Vendor>
+				${project.organization.name}
+			    </Implementation-Vendor>
+			    <Implementation-Vendor-Id>
+				com.sun
+			    </Implementation-Vendor-Id>
+			</manifestEntries>
+		    </archive>
+		    <excludes>
+			<exclude>**/*.java</exclude>
+		    </excludes>
+		</configuration>
+	    </plugin>
+
+	    <!--
+		Tell the source plugin about the sources that may have
+		been downloaded by the maven-dependency-plugin.
+	    -->
+
+	    <plugin>
+		<groupId>org.codehaus.mojo</groupId>
+		<artifactId>build-helper-maven-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>add-source</id>
+			<phase>generate-sources</phase>
+			<goals>
+			    <goal>add-source</goal>
+			</goals>
+			<configuration>
+			    <sources>
+				<source> <!-- for dependencies -->
+				    ${project.build.directory}/sources
+				</source>
+			    </sources>
+			</configuration>
+		    </execution>
+		    <execution>
+			<id>add-resource</id>
+			<phase>generate-resources</phase>
+			<goals>
+			    <goal>add-resource</goal>
+			</goals>
+			<configuration>
+			    <resources>
+				<resource>
+				    <directory>${main.basedir}</directory>
+				    <targetPath>META-INF</targetPath>
+				    <includes>
+					<include>LICENSE.md</include>
+					<include>NOTICE.md</include>
+				    </includes>
+				</resource>
+			    </resources>
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Directory plugin to find parent root directory absolute path.
+		Sets ${main.basedir}, used above with build-helper-maven-plugin
+		to include LICENSE.md and NOTICE.md in jar files.
+	    -->
+	    <plugin>
+		<groupId>org.commonjava.maven.plugins</groupId>
+		<artifactId>directory-maven-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>directories</id>
+			<goals>
+			    <goal>highest-basedir</goal>
+			</goals>
+			<phase>initialize</phase>
+			<configuration>
+			    <property>main.basedir</property>
+			</configuration>
+		    </execution>
+		</executions>
+	    </plugin>
+
+	    <!--
+		Configure the source plugin here so that it will know
+		about the sources that may have been downloaded by the
+		maven-dependency-plugin and configured by the
+		build-helper-maven-plugin.
+	    -->
+	    <plugin>
+		<groupId>org.apache.maven.plugins</groupId>
+		<artifactId>maven-source-plugin</artifactId>
+		<executions>
+		    <execution>
+			<id>attach-sources</id>
+			<goals>
+			    <goal>jar-no-fork</goal> 
+			</goals>
+		    </execution>
+		</executions>
+		<configuration>
+		    <includePom>true</includePom>
+		    <!--
+			Since we added the classes directory using the
+			build-helper-maven-plugin above, we need to exclude
+			the class files from the source jar file.
+		    -->
+		    <excludes>
+			<exclude>**/*.class</exclude>
+		    </excludes>
+		</configuration>
+	    </plugin>
+	</plugins>
+
+	<pluginManagement>
+	    <plugins>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-compiler-plugin</artifactId>
+		    <version>3.7.0</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-surefire-plugin</artifactId>
+		    <version>2.4.3</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-jar-plugin</artifactId>
+		    <version>2.4</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.codehaus.mojo</groupId>
+		    <artifactId>build-helper-maven-plugin</artifactId>
+		    <version>1.7</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.commonjava.maven.plugins</groupId>
+		    <artifactId>directory-maven-plugin</artifactId>
+		    <version>0.3</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-assembly-plugin</artifactId>
+		    <version>2.4</version>
+		</plugin>
+		<plugin>
+		    <!--
+			By default, disable the FindBugs plugin for all modules.
+			It's enabled in the modules where we actually want to
+			run it.
+		    -->
+		    <groupId>org.codehaus.mojo</groupId>
+		    <artifactId>findbugs-maven-plugin</artifactId>
+		    <version>${findbugs.version}</version>
+		    <configuration>
+			<skip>${findbugs.skip}</skip>
+			<threshold>${findbugs.threshold}</threshold>
+			<findbugsXmlWithMessages>true</findbugsXmlWithMessages>
+			<excludeFilterFile>
+			    ${findbugs.exclude}
+			</excludeFilterFile>
+		    </configuration>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-enforcer-plugin</artifactId>
+		    <version>1.0</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.felix</groupId>
+		    <artifactId>maven-bundle-plugin</artifactId>
+		    <version>3.5.0</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-source-plugin</artifactId>
+		    <version>2.1.2</version>
+		 </plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-javadoc-plugin</artifactId>
+		    <version>3.1.1</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.apache.maven.plugins</groupId>
+		    <artifactId>maven-project-info-reports-plugin</artifactId>
+		    <version>2.7</version>
+		</plugin>
+		<plugin>
+		    <groupId>org.glassfish.copyright</groupId>
+		    <artifactId>glassfish-copyright-maven-plugin</artifactId>
+		    <version>${copyright-plugin.version}</version>
+		    <configuration>
+			<scm>git</scm>
+			<scmOnly>true</scmOnly> 
+			<excludeFile>
+			    copyright-exclude
+			</excludeFile>
+		    </configuration>
+		</plugin>
+	    </plugins>
+	</pluginManagement>
+    </build>
+
+    <dependencyManagement>
+	<dependencies>
+	    <dependency>
+		<groupId>com.sun.activation</groupId>
+		<artifactId>jakarta.activation</artifactId>
+		<version>${project.version}</version>
+	    </dependency>
+	</dependencies>
+    </dependencyManagement>
+
+    <reporting>
+	<plugins>
+	    <!--
+		Configure FindBugs to run with "mvn site" and
+		generate html output that can be viewed directly.
+	    -->
+	    <plugin>
+		<groupId>org.codehaus.mojo</groupId>
+		<artifactId>findbugs-maven-plugin</artifactId>
+		<version>${findbugs.version}</version>
+		<configuration>
+		    <skip>${findbugs.skip}</skip>
+		    <threshold>${findbugs.threshold}</threshold>
+		    <excludeFilterFile>
+			${findbugs.exclude}
+		    </excludeFilterFile>
+		</configuration>
+	    </plugin>
+	</plugins>
+    </reporting>
+</project>
diff --git a/spec/README.md b/spec/README.md
new file mode 100644
index 0000000..0536e11
--- /dev/null
+++ b/spec/README.md
@@ -0,0 +1,22 @@
+Jakarta Activation Specification
+================================
+
+This project generates the Jakarta Activation Specification.
+
+Building
+--------
+
+Prerequisites:
+
+* JDK8+
+* Maven 3.0.5+
+
+Run the full build:
+
+`mvn install`
+
+Locate the html files:
+- `target/generated-docs/activation-spec-<version>.html`
+
+Locate the PDF files:
+- `target/generated-docs/activation-spec-<version>.pdf`
diff --git a/spec/assembly.xml b/spec/assembly.xml
new file mode 100644
index 0000000..16d6a85
--- /dev/null
+++ b/spec/assembly.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+ 
+    Copyright (c) 2019 Contributors to the Eclipse Foundation.
+ 
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+ 
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+ 
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ 
+-->
+
+<assembly>
+    <id>spec</id>
+    <formats>
+    <format>zip</format>
+    </formats>
+    <baseDirectory>activation-spec</baseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>target/generated-docs</directory>
+            <outputDirectory></outputDirectory>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/spec/pom.xml b/spec/pom.xml
new file mode 100644
index 0000000..3a20a23
--- /dev/null
+++ b/spec/pom.xml
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+<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">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.eclipse.ee4j</groupId>
+        <artifactId>project</artifactId>
+        <version>1.0.5</version>
+	<relativePath/>
+    </parent>
+    <artifactId>activation-spec</artifactId>
+    <version>1.2-RevA</version>
+    <packaging>pom</packaging>
+    <name>Jakarta Activation Specification</name>
+
+    <properties>
+        <site.output.dir>${project.build.directory}/staging</site.output.dir>
+        <maven.site.skip>true</maven.site.skip>
+        <asciidoctor.maven.plugin.version>1.5.7.1</asciidoctor.maven.plugin.version>
+        <asciidoctorj.version>1.6.2</asciidoctorj.version>
+        <asciidoctorj.pdf.version>1.5.0-alpha.16</asciidoctorj.pdf.version>
+        <jruby.version>9.2.6.0</jruby.version>
+        <!-- status: DRAFT, BETA, etc., or blank for final -->
+        <status></status>
+        <maven.build.timestamp.format>MMMM dd, yyyy</maven.build.timestamp.format>
+        <revisiondate>${maven.build.timestamp}</revisiondate>
+    </properties>
+
+    <build>
+        <defaultGoal>package</defaultGoal>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.4.1</version>
+                <executions>
+                    <execution>
+                        <id>enforce-versions</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireJavaVersion>
+                                    <version>[1.8.0,1.9.0)</version>
+                                    <message>You need JDK8 or lower</message>
+                                </requireJavaVersion>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.asciidoctor</groupId>
+                <artifactId>asciidoctor-maven-plugin</artifactId>
+                <version>${asciidoctor.maven.plugin.version}</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.jruby</groupId>
+                        <artifactId>jruby-complete</artifactId>
+                        <version>${jruby.version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.asciidoctor</groupId>
+                        <artifactId>asciidoctorj</artifactId>
+                        <version>${asciidoctorj.version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.asciidoctor</groupId>
+                        <artifactId>asciidoctorj-pdf</artifactId>
+                        <version>${asciidoctorj.pdf.version}</version>
+                    </dependency>
+                </dependencies>
+                <executions>
+                    <execution>
+                        <id>asciidoc-to-html</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>process-asciidoc</goal>
+                        </goals>
+                        <configuration>
+                            <backend>html5</backend>
+                            <outputFile>${project.build.directory}/generated-docs/activation-spec-${project.version}.html</outputFile>
+                            <attributes>
+                                <doctype>book</doctype>
+                                <status>${status}</status>
+                                <data-uri />
+                                <icons>font</icons>
+                                <toc>left</toc>
+                                <icons>font</icons>
+                                <sectanchors>true</sectanchors>
+                                <idprefix />
+                                <idseparator>-</idseparator>
+                                <docinfo1>true</docinfo1>
+                            </attributes>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>asciidoc-to-pdf</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>process-asciidoc</goal>
+                        </goals>
+                        <configuration>
+                            <backend>pdf</backend>
+                            <outputFile>${project.build.directory}/generated-docs/activation-spec-${project.version}.pdf</outputFile>
+                            <attributes>
+                                <pdf-stylesdir>${project.basedir}/src/theme</pdf-stylesdir>
+                                <pdf-style>jakartaee</pdf-style>
+                                <doctype>book</doctype>
+                                <status>${status}</status>
+                                <data-uri />
+                                <icons>font</icons>
+                                <pagenums />
+                                <toc />
+                                <icons>font</icons>
+                                <sectanchors>true</sectanchors>
+                                <idprefix />
+                                <idseparator>-</idseparator>
+                                <docinfo1>true</docinfo1>
+                                <embedAssets>true</embedAssets>
+                            </attributes>
+                        </configuration>
+                    </execution>
+                </executions>
+                <configuration>
+                    <sourceDocumentName>activation-spec.adoc</sourceDocumentName>
+                    <sourceHighlighter>coderay</sourceHighlighter>
+                    <attributes>
+                        <revnumber>${project.version}</revnumber>
+                        <revremark>${status}</revremark>
+                        <revdate>${revisiondate}</revdate>
+                    </attributes>
+                </configuration>
+
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.5.2</version>
+                <configuration>
+                    <mavenExecutorId>forked-path</mavenExecutorId>
+                    <useReleaseProfile>false</useReleaseProfile>
+                    <arguments>${release.arguments}</arguments>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.scm</groupId>
+                        <artifactId>maven-scm-provider-gitexe</artifactId>
+                        <version>1.9.4</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+
+            <!--
+                This is the rule that builds the zip file for download.
+            -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>3.1.1</version>
+                <inherited>false</inherited>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <appendAssemblyId>false</appendAssemblyId>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/spec/src/main/asciidoc/activation-spec.adoc b/spec/src/main/asciidoc/activation-spec.adoc
new file mode 100644
index 0000000..75b00ee
--- /dev/null
+++ b/spec/src/main/asciidoc/activation-spec.adoc
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2017, 2019 Contributors to the Eclipse Foundation
+//
+
+= Jakarta Activation 1.2
+:authors: Jakarta Activation Team, https://projects.eclipse.org/projects/ee4j.jaf
+:email: https://dev.eclipse.org/mailman/listinfo/jaf-dev
+:version-label!:
+:doctype: book
+:license: Eclipse Foundation Specification License v1.0
+:source-highlighter: coderay
+:toc: left
+:toclevels: 4
+:sectnumlevels: 4
+:sectanchors:
+ifdef::backend-pdf[]
+:pagenums:
+:numbered:
+:title-logo-image: image:jakarta_ee_logo_schooner_color_stacked_default.png[pdfwidth=4.25in,align=right]
+endif::[]
+
+// == License
+:sectnums!:
+include::license-efsl.adoc[]
+
+// == Spec
+:sectnums:
+include::activation.adoc[]
diff --git a/spec/src/main/asciidoc/activation.adoc b/spec/src/main/asciidoc/activation.adoc
new file mode 100644
index 0000000..0bd070b
--- /dev/null
+++ b/spec/src/main/asciidoc/activation.adoc
@@ -0,0 +1,837 @@
+== Overview
+
+
+JavaBeans™ is proving to be a popular technology. As
+more people embrace JavaBeans™ and the Java™ platform, some of the
+environment’s shortcomings are brought to light. JavaBeans™ was meant to
+satisfy needs in builder and development environments but its
+capabilities fall short of those needed to deploy stand alone components
+as content editing and creating entities.
+
+Neither JavaBeans™ nor the Java™ platform define a
+consistent strategy for typing data, a method for determining the
+supported data types of a software component, a method for binding typed
+data to a component, or an architecture and implementation that supports
+these features.
+
+Presumably with these pieces in place, a developer can
+write a JavaBeans™ based component that provides helper application like
+functionality in a web browser, added functionality to an office suite,
+or a content viewer in a Java™ application.
+
+== Goals
+
+
+This document describes Jakarta Activation.
+Jakarta Activation implements the following services:
+
+* It determines the type of arbitrary data.
+* It encapsulates access to data.
+* It discovers the operations available on a particular
+type of data.
+* It instantiates the software component that
+corresponds to the desired operation on a particular piece of data.
+
+Jakarta Activation is packaged as a Standard Extension to the
+Java™ platform.
+
+== Architectural Overview
+
+
+The Java™ platform (including JavaBeans™) already
+provides some support for a modest activation framework. Jakarta Activation
+leverages as much of that existing technology as possible. Jakarta Activation
+integrates these mechanisms.
+
+image:activation.png[image]
+
+This diagram shows the major elements comprising the
+Jakarta Activation architecture.
+Note that the framework shown here is not bound to a particular application.
+
+=== The DataHandler Class
+
+The DataHandler class (shown in the diagram above)
+provides a consistent interface between Activation-aware clients and other
+subsystems.
+
+=== The DataSource Interface
+
+The DataSource interface encapsulates an object that
+contains data, and that can return both a stream providing data access,
+and a string defining the MIME type describing the data.
+
+Classes can be implemented for common data sources
+(web, file system, IMAP, ftp, etc.). The DataSource interface can also
+be extended to allow per data source user customizations. Once the
+DataSource is set in the DataHandler, the client can determine the
+operations available on that data.
+
+Jakarta Activation includes two DataSource class implementations
+for convenience:
+
+* FileDataSource accesses data held in a file.
+* URLDataSource accesses data held at a URL.
+
+=== The CommandMap Interface
+
+The CommandMap provides a service that allows consumers
+of its interfaces to determine the ‘commands’ available on a particular
+MIME type as well as an interface to retrieve an object that can operate
+on an object of a particular MIME type (effectively a component
+registry). The Command Map can generate and maintain a list of available
+capabilities on a particular data type by a mechanism defined by the
+implementation of the particular instance of the CommandMap.
+
+The JavaBeans™ package provides the programming model
+for the software components that implement the commands. Each JavaBeans™
+component can use externalization, or can implement the CommandObject
+interface to allow the typed data to be passed to it.
+
+Jakarta Activation defines the CommandMap interface, which
+provides a flexible and extensible framework for the CommandMap. The
+CommandMap interface allows developers to develop their own solutions
+for discovering which commands are available on the system. A possible
+implementation can access the ‘types registry’ on the platform or use a
+server-based solution. Jakarta Activation provides a simple default
+solution based on RFC 1524 (.mailcap) like functionality.
+See “Deliverables” below.
+
+=== The Command Object Interface
+
+Beans extend the CommandObject interface in order to
+interact with Activation services.
+Activation-aware JavaBeans™ components can directly
+access their DataSource and DataHandler objects in order to retrieve the
+data type and to act on the data.
+
+== Using The Framework
+
+
+We intend to make this infrastructure widely available
+for any Java™ Application that needs this functionality. The ‘canonical’
+consumer of this framework accesses it through the DataHandler (although
+the major subsystems are designed to also operate independently). An
+underlying DataSource object is associated with the DataHandler when the
+DataHandler class is constructed.
+
+* The DataHandler retrieves the data typing information
+from the DataSource or gets the data type directly from the constructor.
+* Once this initialization step is complete, a list of
+commands that can be performed on the data item can be accessed from the
+DataHandler.
+
+When an application issues a request for this list, the
+DataHandler uses the MIME data type specifier returned to request a list
+of available commands from the CommandMap object. The CommandMap has
+knowledge of available commands (implemented as Beans) and their
+supported data types. The CommandMap returns a subset of the full list
+of all commands based on the requested MIME type and the semantics of
+the CommandMap implementation, to the DataHandler.
+
+When the application wishes to apply a command to some
+data, it is accomplished through the appropriate DataHandler interface,
+which uses the CommandMap to retrieve the appropriate Bean that is used
+to operate on the data. The container (user of the framework) makes the
+association between the data and the Bean.
+
+== Usage Scenarios
+
+
+This scenario uses the example of a hypothetical file
+viewer application in order to illustrate the normal flow of tasks
+involved when implementing Jakarta Activation. The file viewer is similar to the
+Windows Explorer utility. When launched, it presents the user with a
+display of available files. It includes a function like Explorer’s
+‘right mouse’ menu, where all operations that can be performed on a
+selected data item are listed in a popup menu for that item.
+
+A typical user launches this application to view a
+directory of files. When the user specifies a file by clicking on it,
+the application displays a popup menu that lists the available
+operations on that file. File system viewer utilities normally include
+‘edit,’ ‘view,’ and ‘print’ commands as available operations. For
+instance selecting ‘view’ causes the utility to open the selected file
+in a viewer that can display data of the data type held in that file.
+
+=== Scenario Architecture
+
+Description of tasks performed by the application is
+broken down into three discrete steps, for clarity:
+
+* Initialization: The application constructs a view of
+the file system.
+* Getting the Command List: The application presents
+the command list for a selected data item.
+* Performing the Command: The application performs a
+command on the selected data object.
+
+=== Initialization
+
+One of the interfaces mentioned below is the
+‘DataSource’ object. Recall that the DataSource object encapsulates the
+underlying data object in a class that abstracts the underlying data
+storage mechanism, and presents its consumers with a common data access
+and typing interface. The file viewer application queries the file
+system for its contents.
+
+The viewer instantiates a DataSource object for each
+file in the directory. Then it instantiates a a DataHandler with the
+DataSource as its constructor argument. The DataHandler object provides
+the client application with access to the CommandMap, which provides a
+service that enables access to commands that can operate on the data.
+The application maintains a list of the DataHandler objects, queries
+them for their names to generate its display.
+
+[source, java]
+----
+// for each file in the directory:
+File file = new File(file_name);
+DataSource ds = new FileDataSource(file);
+DataHandler dh = new DataHandler(ds);
+----
+
+=== Getting the Command List
+
+Once the application has been initialized and has
+presented a list of files to the user, the user can select a file on the
+list. When the user selects a file, the application displays a popup
+menu that lists the available operations on that file.
+
+The application implements this functionality by
+requesting the list of available commands from the DataHandler object
+associated with a file. The DataHandler retrieves the MIME type of the
+data from the DataSource object and queries the CommandMap for
+operations that are available on that type. The application interprets
+the list and presents it to the user on a popup menu. The user then
+selects one of the operations from that list.
+
+[source, java]
+----
+// get the command list for an object
+CommandInfo cmdInfo[] = dh.getPreferredCommands();
+
+PopupMenu popup = new PopupMenu(“Item Menu”);
+
+// populate the popup with available commands
+for (i = 0; i < cmdInfo.length; i++)
+    popup.add(cmdInfo[i].getCommandName());
+
+// add and show popup
+add(popup);
+popup.show(x_pos, y_pos);
+----
+
+=== Performing a Command
+
+After the user has selected a command from the popup
+menu, the application uses the appropriate CommandInfo class to retrieve
+the Bean that corresponds to the selected command, and associates the
+data with that Bean using the appropriate mechanism (DataHandler,
+Externalization etc.). Some CommandObjects (viewers for instance) are
+subclassed from java.awt.Component and require that they are given a
+parent container. Others (like a default print Command) might not
+present a user interface. This allows them to be flexible enough to
+function as stand alone viewer/editors, or perhaps as components in a
+compound document system. The ‘application’ is responsible for providing
+the proper environment (containment, life cycle, etc.) for the
+CommandObject to execute in. We expect that the requirements will be
+lightweight (not much beyond JavaBeans™ containers and AWT containment
+for visible components).
+
+[source, java]
+----
+// get the command object
+Object cmdBean = cmdInfo[cmd_id].getCommandObject(dh,
+				this.getClassLoader());
+
+  ...  // use serialization/externalization where appropriate
+
+my_awt_container.add((Component)cmdBean);
+----
+
+=== An Alternative Scenario
+
+The first scenario was the ‘canonical’ case. There are
+also circumstances where the application has already created objects to
+represent its data. In this case creating an in-memory instance of a
+DataSource that converted an existing object into an InputStream is an
+inefficient use of system resources and can result in a loss of data
+fidelity.
+
+In these cases, the application can instantiate a
+DataHandler, using the DataHandler(Object obj, String mimeType)
+constructor. DataHandler implements the Transferable interface, so the
+consuming Bean can request representations other than InputStreams. The
+DataHandler also constructs a DataSource for consumers that request it.
+The DataContentHandler mechanism is extended to also allow conversion
+from Objects to InputStreams.
+
+The following code is an example of a database front
+end using Jakarta Activation, which provides query results in terms of objects.
+
+[source, java]
+----
+ /**
+  * Get the viewer to view my query results:
+  */
+ Component getQueryViewer(QueryObject qo) throws Exception {
+ String mime_type = qo.getType();
+ Object q_result = qo.getResultObject();
+ DataHandler my_dh = new DataHandler(q_result, mime_type);
+
+ return (Component)my_dh.getCommand(“view”).
+			getCommandObject(my_dh, null));
+ }
+----
+
+== Primary Framework Interfaces
+
+
+This section describes interfaces required to implement the
+Jakarta Activation architecture introduced in Section Three.
+
+=== The DataSource Interface
+
+The DataSource interface is used by the DataHandler
+(and possibly other classes elsewhere) to access the underlying data.
+The DataSource object encapsulates the underlying data object in a class
+that abstracts the underlying data storage and typing mechanism, and
+presents its consumers with a common data access interface.
+
+Jakarta Activation provides DataSource implementations that
+support file systems and URLs. Application system vendors can use the
+DataSource interface to implement their own specialized DataSource
+classes to support IMAP servers, object databases, or other sources.
+
+There is a one-to-one correspondence between underlying
+data items (files for instance) and DataSource objects. Also note that
+the class that implements the DataSource interface is responsible for
+typing the data. To manage a file system, a DataSource can use a simple
+mechanism such as a file extension to type data, while a DataSource that
+supports incoming web-based data can actually examine the data stream to
+determine its type.
+
+=== The DataHandler Class
+
+The DataHandler class encapsulates a Data object, and
+provides methods which act on that data.
+
+DataHandler encapsulates the type-to-command object
+binding service of the CommandMap interface for applications. It
+provides a handle to the operations and data available on a data
+element.
+
+DataHandler also implements the Transferable interface.
+This allows applications and applets to retrieve alternative
+representations of the underlying data, in the form of objects. The
+DataHandler encapsulates the interface to the component repository and
+data source.
+
+Let’s examine these groups of features in more detail:
+
+====  Data Encapsulation
+
+A DataHandler object can only be instantiated with
+data. The data can be in the form of an object implementing the
+DataSource interface (the preferred way) or as an object with an
+associated content type.
+
+Once instantiated, the DataHandler tries to provide its
+data in a flexible way. The DataHandler implements the Transferable
+interface which allows an object to provide alternative representations
+of the data. The Transferable interface’s functionality can be extended
+via objects implementing the DataContentHandler interface, and then made
+available to the DataHandler either by a DataContentHandlerFactory
+object, or via a CommandMap.
+
+==== Command Binding
+
+The DataHandler provides wrappers around commonly used
+functions for command discovery. DataHandler has methods that call into
+the current CommandMap associated with the DataHandler. By default the
+DataHandler calls CommandMap’s getDefaultCommandMap method if no
+CommandMap was explicitly set. As a convenience, DataHandler uses the
+content type of its data when calls are made to the CommandMap.
+
+=== The DataContentHandler Interface
+
+The DataContentHandler interface is implemented by
+classes that are used by the DataHandler to convert InputStreams into
+objects and vice versa. In effect, the DataHandler object uses a
+DataContentHandler object to implement the Transferable interface.
+DataContentHandlers are discovered via the current CommandMap. A
+DataContentHandler uses DataFlavors to represent the data types it can
+access.
+
+The DataContentHandler also converts data from objects
+into InputStreams. For instance, if an application needs to access a
+.gif file, it passes the file to the image/gif DataContentHandler. The
+image/gif DataContentHandler converts the image object into a
+gif-formatted byte stream.
+
+Applications will typically need to provide
+DataContentHandlers for all the MIME types they intend to support. (Note
+that the Jakarta Mail implementation provides DataContentHandlers
+for many of the MIME types used in mail messages.)
+
+===  The CommandMap Interface
+
+Once the DataHandler has a MIME type describing the
+content, it can query the CommandMap for the operations, or commands
+that are available for that data type. The application requests commands
+available through the DataHandler and specifies a command on that list.
+The DataHandler uses the CommandMap to retrieve the Bean associated with
+that command. Some or all of the command map is stored in some ‘common’
+place, like a .mailcap (RFC 1524) file. Other more complex
+implementations can be distributed, or can provide licensing or
+authentication features.
+
+=== The CommandInfo Class
+
+The CommandInfo class is used to represent commands in
+an underlying registry. From a CommandInfo object, an application can
+instantiate the Bean or request the verb (command) it describes.
+
+=== The CommandObject Interface
+
+Beans designed specifically for use with Jakarta Activation
+should implement the CommandObject interface. This
+interface provides direct access to DataHandler methods and notifies an
+Activation-aware Bean which verb was used to call it. Upon instantiation, the
+Bean takes a string specifying a user-selected command verb, and the
+DataHandler object managing the target data. The DataHandler takes a
+DataSource object, which provides an input stream linked to that data,
+and a string specifying the data type.
+
+=== The DataContentHandlerFactory
+
+Like the ContentHandler factory in the java.net
+package, the DataContentHandlerFactory is an interface that allows
+developers to write objects that map MIME types to DataContentHandlers.
+The interface is extremely simple, in order to allow developers as much
+design and implementation freedom as possible.
+
+== Writing Beans for the Framework
+
+
+=== Overview
+
+This section describes the specification of
+well-behaved Activation-aware Bean viewers. Note that this proposal assumes the
+reader is comfortable with the JavaBeans™ Specification.
+Developers intending to implement viewer Beans for Jakarta Activation
+should be familiar with JavaBeans™ concepts and architecture.
+
+=== Viewer Goals
+
+. Make the implementation of viewers and editors as
+simple as implementing Beans. That is, require low cost of entry to be a
+good citizen.
+
+. Allow developers to have a certain amount of flexibility in their
+implementations.
+
+=== General
+
+We are attempting to limit the amount of extra baggage
+that needs to be implemented beyond ‘generic’ Beans. In many cases,
+JavaBeans™ components that weren’t developed with knowledge of the
+framework can be used. Jakarta Activation exploits the existing features of
+JavaBeans™ and the JDK™, and defines as few additional interfaces and
+policies as possible.
+
+We expect that viewers/editors will be bound to data
+via a simple registry mechanism similar in function to a .mailcap file.
+In addition, mailcap format files may be bundled with components,
+allowing additional packages to be added at runtime.
+
+Our viewers/editors and related classes and files are
+encapsulated into JAR files, as is the preferred method for JavaBeans™.
+Jakarta Activation does not restrict the choice of classes used to implement
+Activaiton-aware ‘viewer’ Beans, beyond those expected of well-behaved Beans.
+
+=== Interfaces
+
+A viewer Bean that communicates directly with a Jakarta Activation
+DataHandler should implement the CommandObject interface. This interface
+is small and easy to implement. However, Beans can still use standard
+Serialization and Externalization methods available in the JDK.
+
+=== Storage
+
+Jakarta Activation expects applications and viewer Beans to
+implement storage tasks via the DataSource object. However; it is
+possible to use Externalization. An Activation-aware application can implement
+the following storage mechanism:
+
+[source, java]
+----
+ObjectOutputStream oos = new ObjectOutputStream(
+			data_handler.getOutputStream());
+my_externalizable_bean.writeExternal(oos);
+----
+
+=== Packaging
+
+The basic format for packaging of the Viewer/Editors is
+the JAR file as described in the JavaBeans™ Specification. This format
+allows the convenient packaging of collections of files that are related
+to a particular Bean or applet. For more information concerning
+integration points, see Section 8.
+
+=== Container Support
+
+Jakarta Activation is designed to be flexible enough to support
+the needs of a variety of applications. Jakarta Activation expects these
+applications to provide the appropriate containers and life cycle
+support for these Beans. Beans written for the framework should be
+compatible with the guidelines in the JavaBeans™ documentation and
+should be tested against the BDK BeanBox (and the JDK Appletviewer if
+they are subclassed from Applet).
+
+=== Lifecycle
+
+In general Jakarta Activation expects that its viewer bean life
+cycle semantics are the same as those for all Beans. In the case of
+Beans that implement the CommandObject interface we encourage
+application developers to not parent Beans subclassed from
+java.awt.Component to an AWT container until after they have called the
+javax.activation.CommandObject.setCommandContext method.
+
+=== Command Verbs
+
+The MailcapCommandMap implementation provides a
+mechanism that allows for an extensible set of command verbs.
+Applications using Jakarta Activation can query the system for commands
+available for a particular MIME type, and retrieve the Bean associated
+with that MIME type.
+
+== Framework Integration Points
+
+
+This section presents several examples that clarify how
+JavaBeans™ developers can write Beans that are integrated with
+Jakarta Activation.
+
+First, let’s review the pluggable components of the
+Jakarta Activation framework:
+
+* A mechanism that accesses target data where it is
+stored: DataSource
+* A mechanism to convert data objects to and from an
+external byte stream format: DataContentHandler
+* A mechanism to locate visual components that operate
+on data objects: CommandMap
+* The visual components that operate on data objects:
+Activation-aware Beans
+
+As a JavaBeans™ developer, you may build visual Beans.
+You can also develop DataContentHandlers to supply data to those Beans.
+You might also need to develop a new DataSource or CommandMap class to
+access data and specify a data type.
+
+=== Bean
+
+Suppose you’re building a new Wombat Editor product,
+with its corresponding Wombat file format. You’ve built the Wombat
+Editor as one big Bean. Your WombatBean can do anything and everything
+that you might want to do with a Wombat. It can edit, it can print, it
+can view, it can save Wombats to files, and it can read Wombats in from
+files. You’ve defined a language-independent Wombat file format. You
+consider the Wombat data and file formats to be proprietary so you have
+no need to offer programmatic interfaces to Wombats beyond what your
+WombatBean supports.
+
+You’ve chosen the MIME type “application/x-wombat” to
+describe your Wombat file format, and you’ve chosen the filename
+extension “.wom” to be used by files containing Wombats.
+
+To integrate with the framework, you’ll need some
+simple wrappers for your WombatBean for each command you want to
+implement. For example, for a Print command wrapper you can write the
+following code:
+
+[source, java]
+----
+public class WombatPrintBean extends WombatBean {
+    public WombatPrintBean() {
+        super();
+        initPrinting();
+    }
+}
+----
+
+You will need to create a mailcap file that lists the
+MIME type “application/x-wombat” and user visible commands that are
+supported by your WombatBean. Your WombatBean wrappers will be listed as
+the objects supporting each of these commands.
+
+[source]
+----
+application/x-wombat; ; x-java-view=com.foo.WombatViewBean; \
+    x-java-edit=com.foo.WombatEditBean; \
+    x-java-print=com.foo.WombatPrintBean
+----
+
+You’ll also need to create a mime.types file with an
+entry:
+
+[source]
+----
+type=application/x-wombat desc=”Wombat” exts=wom
+----
+
+All of these components are packaged in a JAR file:
+
+[source]
+----
+META-INF/mailcap
+META-INF/mime.types
+com/foo/WombatBean.class
+com/foo/WombatEditBean.class
+com/foo/WombatViewBean.class
+----
+
+Because everything is built into one Bean, and because
+no third party programmatic access to your Wombat objects is required,
+there’s no need for a DataContentHandler. Your WombatBean can therefore
+implement the Externalizable interface instead; and use its methods to
+read and write your Wombat files. The DataHandler can call the
+Externalizable methods when appropriate.
+
+=== Beans
+
+Your Wombat Editor product has really taken off, and
+you’re now adding significant new functionality and flexibility to your
+Wombat Editor. It’s no longer feasible to put everything into one giant
+Bean. Instead, you’ve broken the product into a number of Beans and
+other components:
+
+* A WombatViewer Bean that can be used to quickly view
+a Wombat in read-only mode.
+* A WombatEditor Bean that is heavier than the
+WombatViewer, but also allows editing.
+* A WombatPrinter Bean that simply prints a Wombat.
+* A component that reads and writes Wombat files.
+* A Wombat class that encapsulates the Wombat data and
+is used by your other Beans and components.
+
+In addition, customers have demanded to be able to
+programmatically manipulate Wombats, independently from the visual
+viewer or editor Beans. You’ll need to create a DataContentHandler that
+can convert a byte stream to and from a Wombat object. When reading, the
+WombatDataContentHandler reads a byte stream and returns a new Wombat
+object. When writing, the WombatDataContentHandler takes a Wombat object
+and produces a corresponding byte stream. You’ll need to publish the API
+to the Wombat class.
+
+The WombatDataContentHandler is delivered as a class
+and is designated as a DataContentHandler that can operate on Wombats in
+the mailcap file included in your JAR file.
+
+Your mailcap file changes to list the appropriate
+Wombat Beans, which implement user commands:
+
+[source]
+----
+application/x-wombat; ; x-java-View=com.foo.WombatViewBean; \
+    x-java-edit=com.foo.WombatEditBean; \
+    x-java-print=com.foo.WombatPrintBean; \
+    x-java-content-handler=com.foo.WombatDataContentHandler
+----
+
+Your Wombat Beans can continue to implement the
+Externalizable interface, and thus read and write Wombat byte streams.
+They are more likely to simply operate on Wombat objects directly. To
+find the Wombat object they’re being invoked to operate on, they
+implement the CommandObject interface. The setCommandContext method
+refers them to the corresponding DataHandler, from which they can invoke
+the getContent method, which will return a Wombat object (produced by
+the WombatDataContentHandler).
+
+All components are packaged in a JAR file.
+
+===  Viewer Only
+
+The Wombat product has been wildly successful. The
+ViewAll Company has decided that it can produce a Wombat viewer that’s
+much faster than the WombatViewer Bean. Since they don’t want to depend
+on the presence of any Wombat components, their viewer must parse the
+Wombat file format, which they reverse engineered.
+
+The ViewAll WombatViewerBean implements the
+Externalizable interface to read the Wombat data format.
+
+ViewAll delivers an appropriate mailcap file:
+
+[source]
+----
+application/x-wombat; ; x-java-view=com.viewall.WombatViewer
+----
+
+and mime.types file:
+
+[source]
+----
+type=application/x-wombat desc=”Wombat” exts=wom
+----
+
+All components are packaged in a JAR file.
+
+===  ContentHandler Bean Only
+
+Now that everyone is using Wombats, you’ve decided that
+it would be nice if you could notify people by email when new Wombats
+are created. You have designed a new WombatNotification class and a
+corresponding data format to be sent by email using the MIME type
+“application/x-wombat-notification”. Your server detects the presence of
+new Wombats, constructs a WombatNotification object, and constructs and
+sends an email message with the Wombat notification data as an
+attachment. Your customers run a program that scans their email INBOX
+for messages with Wombat notification attachments and use the
+WombatNotification class to notify their users of the new Wombats.
+
+In addition to the server application and user
+application described, you’ll need a DataContentHandler to plug into the
+DataHandler infrastructure and construct the WombatNotification objects.
+The WombatNotification DataContentHandler is delivered as a class named
+WombatNotificationDataContentHandler and is delivered in a JAR file with
+the following mailcap file:
+
+[source]
+----
+application/x-wombat-notification; \
+    WombatNotificationDataContentHandler
+----
+
+The server application creates DataHandlers for its
+WombatNotification objects. The email system uses the DataHandler to
+fetch a byte stream corresponding to the WombatNotification object. (The
+DataHandler uses the DataContentHandler to do this.)
+
+The client application retrieves a DataHandler for the
+email attachment and uses the getContent method to get the corresponding
+WombatNotification object, which will then notify the user.
+
+
+
+== Framework Deliverables
+
+
+=== Packaging Details
+
+Jakarta Activation is implemented as a Standard Extension to the
+Java™ Platform.
+The following are some more details about the package:
+
+* The package name is javax.activation.
+* The Jakarta Activation implementation does not include
+DataContentHandlers for any MIME data types; applications must include
+the DataContentHandlers they need. Note that the Jakarta Mail
+implementation includes DataContentHandlers for some basic data types
+used in mail messages.
+
+=== Framework Core Classes
+
+**interface DataSource:** The DataSource interface provides
+Jakarta Activation with an abstraction of some arbitrary
+collection of data. It provides a type for that data as well as access
+to it in the form of InputStreams and OutputStreams where appropriate.
+
+**class DataHandler:** The DataHandler class provides a
+consistent interface to data available in many different sources and
+formats. It manages simple stream to string conversions and related
+operations using DataContentHandlers. It provides access to commands
+that can operate on the data. The commands are found using a CommandMap.
+
+**interface DataContentHandler:** The DataContentHandler
+interface is implemented by objects that can be used to extend the
+capabilities of the DataHandler’s implementation of the Transferable
+interface. Through DataContentHandlers the framework can be extended to
+convert streams in to objects, and to write objects to streams.
+
+**interface DataContentHandlerFactory:** This interface
+defines a factory for DataContentHandlers. An implementation of this
+interface should map a MIME type into an instance of DataContentHandler.
+The design pattern for classes implementing this interface is the same
+as for the ContentHandler mechanism used in java.net.URL.
+
+**class CommandMap:** The CommandMap class provides an
+interface to the registry of viewer, editor, print, etc. objects
+available in the system. Developers are expected to either use the
+CommandMap implementation included with this package (MailcapCommandMap)
+or develop their own. Note that some of the methods in this class are
+abstract.
+
+**interface CommandObject:** Beans that are Activation
+aware implement this interface to find out which command verb
+they’re being asked to perform, and to obtain the DataHandler
+representing the data they should operate on. Beans that don’t implement
+this interface may be used as well. Such commands may obtain the data
+using the Externalizable interface, or using an application-specific
+method.
+
+**class CommandInfo:** The CommandInfo class is used by
+CommandMap implementations to describe the results of command requests.
+It provides the requestor with both the verb requested, as well as an
+instance of the bean. There is also a method that will return the name
+of the class that implements the command but it is not guaranteed to
+return a valid value. The reason for this is to allow CommandMap
+implementations that subclass CommandInfo to provide special behavior.
+For example a CommandMap could dynamically generate Beans. In this case,
+it might not be possible to create an object with all the correct state
+information solely from the class name.
+
+=== Framework Auxiliary Classes
+
+**class FileDataSource:** The FileDataSource class
+implements a simple DataSource object that encapsulates a file. It
+provides data typing services via a FileTypeMap object.
+
+**class FileTypeMap:** The FileTypeMap is an abstract class
+that provides a data typing interface for files. Implementations of this
+class will implement the getContentType methods which will derive a
+content type from a file name or a File object. FileTypeMaps could use
+any scheme to determine the data type, from examining the file extension
+of a file (like the MimetypesFileTypeMap) to opening the file and trying
+to derive its type from the contents of the file. The FileDataSource
+class uses the default FileTypeMap (a MimetypesFileTypeMap unless
+changed) to determine the content type of files.
+
+**class MimetypesFileTypeMap:** This class extends
+FileTypeMap and provides data typing of files via their file extension.
+It uses the .mime.types format.
+
+**class URLDataSource:** The URLDataSource class provides
+an object that wraps a URL object in a DataSource interface.
+URLDataSource simplifies the handling of data described by URLs within
+Jakarta Activation because this class can be used to
+create new DataHandlers.
+
+**class MailcapCommandMap:** MailcapCommandMap extends the
+CommandMap abstract class. It implements a CommandMap whose
+configuration is based on mailcap files (RFC 1524). The
+MailcapCommandMap can be configured both programmatically and via
+configuration files.
+
+**class ActivationDataFlavor:** The ActivationDataFlavor is
+a special subclass of java.awt.datatransfer.DataFlavor. It allows
+Jakarta Activation to set all three values stored by the DataFlavor
+class via a new constructor as well as improved MIME parsing in the
+equals method.
+Except for the improved parsing, its semantics are identical to that of
+the JDK’s DataFlavor class.
+
+**class UnsupportedDataTypeException:** Signals that
+requested operation does not support the requested data type.
+
+**class MimeType:** A Multipurpose Internet Extension
+(MIME) type, as defined in RFC 2045 and 2046.
+
+**class com.sun.activation.viewers.*:** A few simple
+example viewer Beans (text and image).
+
+== Document Change History
+
+Oct 21, 2019: First complete Jakarta EE version.
diff --git a/spec/src/main/asciidoc/images/activation.png b/spec/src/main/asciidoc/images/activation.png
new file mode 100644
index 0000000..d2b4a73
--- /dev/null
+++ b/spec/src/main/asciidoc/images/activation.png
Binary files differ
diff --git a/spec/src/main/asciidoc/images/jakarta_ee_logo_schooner_color_stacked_default.png b/spec/src/main/asciidoc/images/jakarta_ee_logo_schooner_color_stacked_default.png
new file mode 100644
index 0000000..97b46ce
--- /dev/null
+++ b/spec/src/main/asciidoc/images/jakarta_ee_logo_schooner_color_stacked_default.png
Binary files differ
diff --git a/spec/src/main/asciidoc/license-efsl.adoc b/spec/src/main/asciidoc/license-efsl.adoc
new file mode 100644
index 0000000..a544e8d
--- /dev/null
+++ b/spec/src/main/asciidoc/license-efsl.adoc
@@ -0,0 +1,79 @@
+[subs="normal"]
+....
+Specification: {doctitle}
+
+Version: {revnumber}
+
+ifeval::["{revremark}" != ""]
+Status: {revremark}
+endif::[]
+ifeval::["{revremark}" == ""]
+Status: Final Release
+endif::[]
+
+Release: {revdate}
+....
+
+Copyright (c) 2019 Eclipse Foundation.
+
+=== Eclipse Foundation Specification License
+
+By using and/or copying this document, or the Eclipse Foundation
+document from which this statement is linked, you (the licensee) agree
+that you have read, understood, and will comply with the following
+terms and conditions:
+
+Permission to copy, and distribute the contents of this document, or
+the Eclipse Foundation document from which this statement is linked, in
+any medium for any purpose and without fee or royalty is hereby
+granted, provided that you include the following on ALL copies of the
+document, or portions thereof, that you use:
+
+* link or URL to the original Eclipse Foundation document.
+* All existing copyright notices, or if one does not exist, a notice
+  (hypertext is preferred, but a textual representation is permitted)
+  of the form: "Copyright (c) [$date-of-document]
+  Eclipse Foundation, Inc. <<url to this license>>"
+
+Inclusion of the full text of this NOTICE must be provided. We
+request that authorship attribution be provided in any software,
+documents, or other items or products that you create pursuant to the
+implementation of the contents of this document, or any portion
+thereof.
+
+No right to create modifications or derivatives of Eclipse Foundation
+documents is granted pursuant to this license, except anyone may
+prepare and distribute derivative works and portions of this document
+in software that implements the specification, in supporting materials
+accompanying such software, and in documentation of such software,
+PROVIDED that all such works include the notice below. HOWEVER, the
+publication of derivative works of this document for use as a technical
+specification is expressly prohibited.
+
+The notice is:
+
+"Copyright (c) 2018 Eclipse Foundation. This software or
+document includes material copied from or derived from [title and URI
+of the Eclipse Foundation specification document]."
+
+==== Disclaimers
+
+THIS DOCUMENT IS PROVIDED &quot;AS IS,&quot; AND THE COPYRIGHT
+HOLDERS AND THE ECLIPSE FOUNDATION MAKE NO REPRESENTATIONS OR
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
+NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE
+SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS
+WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR
+OTHER RIGHTS.
+
+THE COPYRIGHT HOLDERS AND THE ECLIPSE FOUNDATION WILL NOT BE LIABLE
+FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT
+OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE
+CONTENTS THEREOF.
+
+The name and trademarks of the copyright holders or the Eclipse
+Foundation may NOT be used in advertising or publicity pertaining to
+this document or its contents without specific, written prior
+permission. Title to copyright in this document will at all times
+remain with copyright holders.
diff --git a/spec/src/theme/jakartaee-theme.yml b/spec/src/theme/jakartaee-theme.yml
new file mode 100644
index 0000000..6092a2f
--- /dev/null
+++ b/spec/src/theme/jakartaee-theme.yml
@@ -0,0 +1,299 @@
+#
+# Following is the asciidoctor-pdf default theme [1], with small
+# customizations, mostly for header and footer, marked "EE".
+#
+# [1] https://github.com/asciidoctor/asciidoctor-pdf/blob/master/data/themes/default-theme.yml
+#
+font:
+  catalog:
+    # Noto Serif supports Latin, Latin-1 Supplement, Latin Extended-A, Greek, Cyrillic, Vietnamese & an assortment of symbols
+    Noto Serif:
+      normal: notoserif-regular-subset.ttf
+      bold: notoserif-bold-subset.ttf
+      italic: notoserif-italic-subset.ttf
+      bold_italic: notoserif-bold_italic-subset.ttf
+    # M+ 1mn supports ASCII and the circled numbers used for conums
+    M+ 1mn:
+      normal: mplus1mn-regular-ascii-conums.ttf
+      bold: mplus1mn-bold-ascii.ttf
+      italic: mplus1mn-italic-ascii.ttf
+      bold_italic: mplus1mn-bold_italic-ascii.ttf
+    # M+ 1p supports Latin, Latin-1 Supplement, Latin Extended, Greek, Cyrillic, Vietnamese, Japanese & an assortment of symbols
+    # It also provides arrows for ->, <-, => and <= replacements in case these glyphs are missing from font
+    M+ 1p Fallback:
+      normal: mplus1p-regular-fallback.ttf
+      bold: mplus1p-regular-fallback.ttf
+      italic: mplus1p-regular-fallback.ttf
+      bold_italic: mplus1p-regular-fallback.ttf
+  fallbacks:
+    - M+ 1p Fallback
+page:
+  background_color: ffffff
+  layout: portrait
+  margin: [0.5in, 0.67in, 0.67in, 0.67in]
+  # margin_inner and margin_outer keys are used for recto/verso print margins when media=prepress
+  margin_inner: 0.75in
+  margin_outer: 0.59in
+  #size: A4                                     # EE
+  size: Letter                                  # EE
+base:
+  align: justify
+  # color as hex string (leading # is optional)
+  font_color: 333333
+  # color as RGB array
+  #font_color: [51, 51, 51]
+  # color as CMYK array (approximated)
+  #font_color: [0, 0, 0, 0.92]
+  #font_color: [0, 0, 0, 92%]
+  font_family: Noto Serif
+  # choose one of these font_size/line_height_length combinations
+  #font_size: 14
+  #line_height_length: 20
+  #font_size: 11.25
+  #line_height_length: 18
+  #font_size: 11.2
+  #line_height_length: 16
+  font_size: 10.5
+  #line_height_length: 15
+  # correct line height for Noto Serif metrics
+  line_height_length: 12
+  #font_size: 11.25
+  #line_height_length: 18
+  line_height: $base_line_height_length / $base_font_size
+  font_size_large: round($base_font_size * 1.25)
+  font_size_small: round($base_font_size * 0.85)
+  font_size_min: $base_font_size * 0.75
+  font_style: normal
+  border_color: eeeeee
+  border_radius: 4
+  border_width: 0.5
+# FIXME vertical_rhythm is weird; we should think in terms of ems
+#vertical_rhythm: $base_line_height_length * 2 / 3
+# correct line height for Noto Serif metrics (comes with built-in line height)
+vertical_rhythm: $base_line_height_length
+horizontal_rhythm: $base_line_height_length
+# QUESTION should vertical_spacing be block_spacing instead?
+vertical_spacing: $vertical_rhythm
+link:
+  font_color: 428bca
+# literal is currently used for inline monospaced in prose and table cells
+literal:
+  font_color: b12146
+  font_family: M+ 1mn
+menu_caret_content: " <font size=\"1.15em\"><color rgb=\"b12146\">\u203a</color></font> "
+heading:
+  align: left
+  #font_color: 181818
+  font_color: $base_font_color
+  font_family: $base_font_family
+  font_style: bold
+  # h1 is used for part titles (book doctype) or the doctitle (article doctype)
+  #h1_font_size: floor($base_font_size * 2.6) # EE
+  h1_font_size: floor($base_font_size * 2.5) # EE, squeeze title onto one line
+  # h2 is used for chapter titles (book doctype only)
+  h2_font_size: floor($base_font_size * 2.15)
+  h3_font_size: round($base_font_size * 1.7)
+  h4_font_size: $base_font_size_large
+  h5_font_size: $base_font_size
+  h6_font_size: $base_font_size_small
+  #line_height: 1.4
+  # correct line height for Noto Serif metrics (comes with built-in line height)
+  line_height: 1
+  margin_top: $vertical_rhythm * 0.4
+  margin_bottom: $vertical_rhythm * 0.9
+title_page:
+  align: right
+  logo:
+    top: 10%
+  title:
+    top: 55%
+    font_size: $heading_h1_font_size
+    font_color: 999999
+    line_height: 0.9
+  subtitle:
+    font_size: $heading_h3_font_size
+    font_style: bold_italic
+    line_height: 1
+  authors:
+    margin_top: $base_font_size * 1.25
+    font_size: $base_font_size_large
+    font_color: 181818
+  revision:
+    margin_top: $base_font_size * 1.25
+block:
+  margin_top: 0
+  margin_bottom: $vertical_rhythm
+caption:
+  align: left
+  font_size: $base_font_size * 0.95
+  font_style: italic
+  # FIXME perhaps set line_height instead of / in addition to margins?
+  margin_inside: $vertical_rhythm / 3
+  #margin_inside: $vertical_rhythm / 4
+  margin_outside: 0
+lead:
+  font_size: $base_font_size_large
+  line_height: 1.4
+abstract:
+  font_color: 5c6266
+  font_size: $lead_font_size
+  line_height: $lead_line_height
+  font_style: italic
+  first_line_font_style: bold
+  title:
+    align: center
+    font_color: $heading_font_color
+    font_family: $heading_font_family
+    font_size: $heading_h4_font_size
+    font_style: $heading_font_style
+admonition:
+  column_rule_color: $base_border_color
+  column_rule_width: $base_border_width
+  padding: [0, $horizontal_rhythm, 0, $horizontal_rhythm]
+  #icon:
+  #  tip:
+  #    name: fa-lightbulb-o
+  #    stroke_color: 111111
+  #    size: 24
+  label:
+    text_transform: uppercase
+    font_style: bold
+blockquote:
+  font_color: $base_font_color
+  font_size: $base_font_size_large
+  border_color: $base_border_color
+  border_width: 5
+  # FIXME disable negative padding bottom once margin collapsing is implemented
+  padding: [0, $horizontal_rhythm, $block_margin_bottom * -0.75, $horizontal_rhythm + $blockquote_border_width / 2]
+  cite_font_size: $base_font_size_small
+  cite_font_color: 999999
+# code is used for source blocks (perhaps change to source or listing?)
+code:
+  font_color: $base_font_color
+  font_family: $literal_font_family
+  font_size: ceil($base_font_size)
+  padding: $code_font_size
+  line_height: 1.25
+  # line_gap is an experimental property to control how a background color is applied to an inline block element
+  line_gap: 3.8
+  background_color: f5f5f5
+  border_color: cccccc
+  border_radius: $base_border_radius
+  border_width: 0.75
+conum:
+  font_family: M+ 1mn
+  font_color: $literal_font_color
+  font_size: $base_font_size
+  line_height: 4 / 3
+example:
+  border_color: $base_border_color
+  border_radius: $base_border_radius
+  border_width: 0.75
+  background_color: ffffff
+  # FIXME reenable padding bottom once margin collapsing is implemented
+  padding: [$vertical_rhythm, $horizontal_rhythm, 0, $horizontal_rhythm]
+image:
+  align: left
+prose:
+  margin_top: $block_margin_top
+  margin_bottom: $block_margin_bottom
+sidebar:
+  background_color: eeeeee
+  border_color: e1e1e1
+  border_radius: $base_border_radius
+  border_width: $base_border_width
+  # FIXME reenable padding bottom once margin collapsing is implemented
+  padding: [$vertical_rhythm, $vertical_rhythm * 1.25, 0, $vertical_rhythm * 1.25]
+  title:
+    align: center
+    font_color: $heading_font_color
+    font_family: $heading_font_family
+    font_size: $heading_h4_font_size
+    font_style: $heading_font_style
+thematic_break:
+  border_color: $base_border_color
+  border_style: solid
+  border_width: $base_border_width
+  margin_top: $vertical_rhythm * 0.5
+  margin_bottom: $vertical_rhythm * 1.5
+description_list:
+  term_font_style: bold
+  term_spacing: $vertical_rhythm / 4
+  description_indent: $horizontal_rhythm * 1.25
+outline_list:
+  indent: $horizontal_rhythm * 1.5
+  #marker_font_color: 404040
+  # NOTE outline_list_item_spacing applies to list items that do not have complex content
+  item_spacing: $vertical_rhythm / 2
+table:
+  background_color: $page_background_color
+  #head_background_color: <hex value>
+  #head_font_color: $base_font_color
+  head_font_style: bold
+  #body_background_color: <hex value>
+  body_stripe_background_color: f9f9f9
+  foot_background_color: f0f0f0
+  border_color: dddddd
+  border_width: $base_border_width
+  cell_padding: 3
+toc:
+  indent: $horizontal_rhythm
+  line_height: 1.4
+  dot_leader:
+    #content: ". "
+    font_color: a9a9a9
+    #levels: 2 3
+# NOTE in addition to footer, header is also supported
+footer:
+  font_size: $base_font_size_small
+  # NOTE if background_color is set, background and border will span width of page
+  #border_color: dddddd                         # EE
+  #border_width: 0.25                           # EE
+  height: $base_line_height_length * 2.5
+  line_height: 1
+  padding: [$base_line_height_length / 2, 1, 0, 1]
+  vertical_align: top
+  #image_vertical_align: <alignment> or <number>
+  # additional attributes for content:
+  # * {page-count}
+  # * {page-number}
+  # * {document-title}
+  # * {document-subtitle}
+  # * {chapter-title}
+  # * {section-title}
+  # * {section-or-chapter-title}
+  recto:
+    #columns: "<50% =0% >50%"
+    right:
+      #content: '{page-number}'                 # EE
+      #content: '{section-or-chapter-title} | {page-number}'
+      #content: '{document-title} | {page-number}'
+      content: '{document-title}{nbsp}{nbsp}{nbsp} *{page-number}*' # EE
+    #center:
+    #  content: '{page-number}'
+    left:                                       # EE
+      content: '{status}'                       # EE
+  verso:
+    #columns: $footer_recto_columns
+    left:
+      #content: $footer_recto_right_content     # EE
+      #content: '{page-number} | {chapter-title}'
+      content: '*{page-number}* {nbsp}{nbsp}{nbsp}{document-title}' # EE
+    #center:
+    #  content: '{page-number}'
+    right:                                      # EE
+      content: '{status}'                       # EE
+header:                                         # EE
+  font_size: $base_font_size_small              # EE
+  border_color: dddddd                          # EE
+  border_width: 0.25                            # EE
+  height: $base_line_height_length * 2.5        # EE
+  line_height: 1                                # EE
+  padding: [$base_line_height_length / 2, 1, 0, 1] # EE
+  vertical_align: top                           # EE
+  recto:                                        # EE
+    right:                                      # EE
+      content: '{section-or-chapter-title}'     # EE
+  verso:                                        # EE
+    left:                                       # EE
+      content: '{section-or-chapter-title}'     # EE