Internal change

PiperOrigin-RevId: 441490263
Change-Id: Ic53dcf949846bed13f60ce2fec55d194ee56fef3
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4a00ba9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,362 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates or
+    contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+    Software, prior Modifications used by a Contributor (if any), and
+    the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+    Modifications, or (c) the combination of files containing Original
+    Software with files containing Modifications, in each case including
+    portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other than
+    Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+    makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+    portions thereof with code not governed by the terms of this License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+    extent possible, whether at the time of the initial grant or
+    subsequently acquired, any and all of the rights conveyed herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+    any of the following:
+
+    A. Any file that results from an addition to, deletion from or
+    modification of the contents of a file containing Original Software
+    or previous Modifications;
+
+    B. Any new file that contains any part of the Original Software or
+    previous Modification; or
+
+    C. Any new file that is contributed or otherwise made available
+    under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable form
+    of computer software code that is originally released under this
+    License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+    hereafter acquired, including without limitation, method, process,
+    and apparatus claims, in any patent Licensable by grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+    code in which modifications are made and (b) associated
+    documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+    exercising rights under, and complying with all of the terms of,
+    this License. For legal entities, "You" includes any entity which
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject
+    to third party intellectual property claims, the Initial Developer
+    hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+    (a) under intellectual property rights (other than patent or
+    trademark) Licensable by Initial Developer, to use, reproduce,
+    modify, display, perform, sublicense and distribute the Original
+    Software (or portions thereof), with or without Modifications,
+    and/or as part of a Larger Work; and
+
+    (b) under Patent Claims infringed by the making, using or selling of
+    Original Software, to make, have made, use, practice, sell, and
+    offer for sale, and/or otherwise dispose of the Original Software
+    (or portions thereof).
+
+    (c) The licenses granted in Sections 2.1(a) and (b) are effective on
+    the date Initial Developer first distributes or otherwise makes the
+    Original Software available to a third party under the terms of this
+    License.
+
+    (d) Notwithstanding Section 2.1(b) above, no patent license is
+    granted: (1) for code that You delete from the Original Software, or
+    (2) for infringements caused by: (i) the modification of the
+    Original Software, or (ii) the combination of the Original Software
+    with other software or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject
+    to third party intellectual property claims, each Contributor hereby
+    grants You a world-wide, royalty-free, non-exclusive license:
+
+    (a) under intellectual property rights (other than patent or
+    trademark) Licensable by Contributor to use, reproduce, modify,
+    display, perform, sublicense and distribute the Modifications
+    created by such Contributor (or portions thereof), either on an
+    unmodified basis, with other Modifications, as Covered Software
+    and/or as part of a Larger Work; and
+
+    (b) under Patent Claims infringed by the making, using, or selling
+    of Modifications made by that Contributor either alone and/or in
+    combination with its Contributor Version (or portions of such
+    combination), to make, use, sell, offer for sale, have made, and/or
+    otherwise dispose of: (1) Modifications made by that Contributor (or
+    portions thereof); and (2) the combination of Modifications made by
+    that Contributor with its Contributor Version (or portions of such
+    combination).
+
+    (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
+    on the date Contributor first distributes or otherwise makes the
+    Modifications available to a third party.
+
+    (d) Notwithstanding Section 2.2(b) above, no patent license is
+    granted: (1) for any code that Contributor has deleted from the
+    Contributor Version; (2) for infringements caused by: (i) third
+    party modifications of Contributor Version, or (ii) the combination
+    of Modifications made by that Contributor with other software
+    (except as part of the Contributor Version) or other devices; or (3)
+    under Patent Claims infringed by Covered Software in the absence of
+    Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make available
+    in Executable form must also be made available in Source Code form
+    and that Source Code form must be distributed only under the terms
+    of this License. You must include a copy of this License with every
+    copy of the Source Code form of the Covered Software You distribute
+    or otherwise make available. You must inform recipients of any such
+    Covered Software in Executable form as to how they can obtain such
+    Covered Software in Source Code form in a reasonable manner on or
+    through a medium customarily used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License. You represent that You
+    believe Your Modifications are Your original creation(s) and/or You
+    have sufficient rights to grant the rights conveyed by this License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification. You may not
+    remove or alter any copyright, patent or trademark notices contained
+    within the Covered Software, or any notices of licensing or any
+    descriptive text giving attribution to any Contributor or the
+    Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version of
+    this License or the recipients' rights hereunder. You may choose to
+    offer, and to charge a fee for, warranty, support, indemnity or
+    liability obligations to one or more recipients of Covered Software.
+    However, you may do so only on Your own behalf, and not on behalf of
+    the Initial Developer or any Contributor. You must make it
+    absolutely clear that any such warranty, support, indemnity or
+    liability obligation is offered by You alone, and You hereby agree
+    to indemnify the Initial Developer and every Contributor for any
+    liability incurred by the Initial Developer or such Contributor as a
+    result of warranty, support, indemnity or liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software under
+    the terms of this License or under the terms of a license of Your
+    choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License. If You distribute the Covered
+    Software in Executable form under a different license, You must make
+    it absolutely clear that any terms which differ from this License
+    are offered by You alone, not by the Initial Developer or
+    Contributor. You hereby agree to indemnify the Initial Developer and
+    every Contributor for any liability incurred by the Initial
+    Developer or such Contributor as a result of any such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and distribute
+    the Larger Work as a single product. In such a case, You must make
+    sure the requirements of this License are fulfilled for the Covered
+    Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Oracle is the initial license steward and may publish revised and/or
+    new versions of this License from time to time. Each version will be
+    given a distinguishing version number. Except as provided in Section
+    4.3, no one other than the license steward has the right to modify
+    this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software. If
+    the Initial Developer includes a notice in the Original Software
+    prohibiting it from being distributed or otherwise made available
+    under any subsequent version of the License, You must distribute and
+    make the Covered Software available under the terms of the version
+    of the License under which You originally received the Covered
+    Software. Otherwise, You may also choose to use, distribute or
+    otherwise make the Covered Software available under the terms of any
+    subsequent version of the License published by the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license and
+    remove any references to the name of the license steward (except to
+    note that the license differs from this License); and (b) otherwise
+    make it clear that the license contains terms which differ from this
+    License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+    WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
+    IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+    NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+    THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+    DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+    OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+    REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+    ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
+    AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond the
+    termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that the
+    Participant Software (meaning the Contributor Version where the
+    Participant is a Contributor or the Original Software where the
+    Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if the
+    Initial Developer is not the Participant) and all Contributors under
+    Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
+    from Participant terminate prospectively and automatically at the
+    expiration of such 60 day notice period, unless if within such 60
+    day period You withdraw Your claim with respect to the Participant
+    Software against such Participant either unilaterally or pursuant to
+    a written agreement with Participant.
+
+    6.3. If You assert a patent infringement claim against Participant
+    alleging that the Participant Software directly or indirectly
+    infringes any patent where such claim is resolved (such as by
+    license or settlement) prior to the initiation of patent
+    infringement litigation, then the reasonable value of the licenses
+    granted by such Participant under Sections 2.1 or 2.2 shall be taken
+    into account in determining the amount or value of any payment or
+    license.
+
+    6.4. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
+    TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
+    FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+    LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+    POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
+    APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+    PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+    LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+    LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+    AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is defined
+    in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+    software" (as that term is defined at 48 C.F.R. §
+    252.227-7014(a)(1)) and "commercial computer software documentation"
+    as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
+    with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
+    (June 1995), all U.S. Government End Users acquire Covered Software
+    with only those rights set forth herein. This U.S. Government Rights
+    clause is in lieu of, and supersedes, any other FAR, DFAR, or other
+    clause or provision that addresses Government rights in computer
+    software under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof. If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable. This License shall be governed by
+    the law of the jurisdiction specified in a notice contained within
+    the Original Software (except to the extent applicable law, if any,
+    provides otherwise), excluding such jurisdiction's conflict-of-law
+    provisions. Any litigation relating to this License shall be subject
+    to the jurisdiction of the courts located in the jurisdiction and
+    venue specified in a notice contained within the Original Software,
+    with the losing party responsible for costs, including, without
+    limitation, court costs and reasonable attorneys' fees and expenses.
+    The application of the United Nations Convention on Contracts for
+    the International Sale of Goods is expressly excluded. Any law or
+    regulation which provides that the language of a contract shall be
+    construed against the drafter shall not apply to this License. You
+    agree that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use, distribute
+    or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or indirectly,
+    out of its utilization of rights under this License and You agree to
+    work with Initial Developer and Contributors to distribute such
+    responsibility on an equitable basis. Nothing herein is intended or
+    shall be deemed to constitute any admission of liability.
+
+------------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The code released under the CDDL shall be governed by the laws of the
+State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction
+of the Federal Courts of the Northern District of California and the
+state courts of the State of California, with venue lying in Santa Clara
+County, California.
diff --git a/v1_2_0/LICENSE b/src/main/java/META-INF/LICENSE.txt
similarity index 100%
rename from v1_2_0/LICENSE
rename to src/main/java/META-INF/LICENSE.txt
diff --git a/src/main/java/META-INF/mailcap.default b/src/main/java/META-INF/mailcap.default
new file mode 100644
index 0000000..542de7d
--- /dev/null
+++ b/src/main/java/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/src/main/java/META-INF/mimetypes.default b/src/main/java/META-INF/mimetypes.default
new file mode 100644
index 0000000..1b4056b
--- /dev/null
+++ b/src/main/java/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/src/main/java/com/sun/activation/registries/LogSupport.java b/src/main/java/com/sun/activation/registries/LogSupport.java
new file mode 100644
index 0000000..1ccdb35
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/LogSupport.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/com/sun/activation/registries/MailcapFile.java b/src/main/java/com/sun/activation/registries/MailcapFile.java
new file mode 100644
index 0000000..3553968
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/MailcapFile.java
@@ -0,0 +1,578 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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.
+     */
+    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
+     */
+    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 <type>/\* and return that. Return the
+     * list of all that hit.
+     */
+    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 <type>/\* and return that. Return the
+     * list of all that hit.
+     */
+    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.
+     */
+    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.
+     */
+    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<nl>
+     *
+     * Example:
+     * # this is a comment
+     * image/gif       jaf.viewers.ImageViewer
+     */
+    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.
+     */
+    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/src/main/java/com/sun/activation/registries/MailcapParseException.java b/src/main/java/com/sun/activation/registries/MailcapParseException.java
new file mode 100644
index 0000000..eca133b
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/MailcapParseException.java
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/com/sun/activation/registries/MailcapTokenizer.java b/src/main/java/com/sun/activation/registries/MailcapTokenizer.java
new file mode 100644
index 0000000..9643568
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/MailcapTokenizer.java
@@ -0,0 +1,337 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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
+     *
+     *  @parameter  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.
+     */
+    public void setIsAutoquoting(boolean value) {
+	isAutoquoting = value;
+    }
+
+    /**
+     *  Retrieve current token.
+     *
+     *  @returns    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/src/main/java/com/sun/activation/registries/MimeTypeEntry.java b/src/main/java/com/sun/activation/registries/MimeTypeEntry.java
new file mode 100644
index 0000000..6714936
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/MimeTypeEntry.java
@@ -0,0 +1,65 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/com/sun/activation/registries/MimeTypeFile.java b/src/main/java/com/sun/activation/registries/MimeTypeFile.java
new file mode 100644
index 0000000..43bf327
--- /dev/null
+++ b/src/main/java/com/sun/activation/registries/MimeTypeFile.java
@@ -0,0 +1,332 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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.
+     */
+    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
+     */
+    public MimeTypeEntry getMimeTypeEntry(String file_ext) {
+	return (MimeTypeEntry)type_hash.get((Object)file_ext);
+    }
+
+    /**
+     * Get the MIME type string corresponding to the file extension.
+     */
+    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
+     */
+    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/src/main/java/com/sun/activation/viewers/ImageViewer.java b/src/main/java/com/sun/activation/viewers/ImageViewer.java
new file mode 100644
index 0000000..eea8add
--- /dev/null
+++ b/src/main/java/com/sun/activation/viewers/ImageViewer.java
@@ -0,0 +1,138 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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 DataHandler 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/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java b/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java
new file mode 100644
index 0000000..54f897c
--- /dev/null
+++ b/src/main/java/com/sun/activation/viewers/ImageViewerCanvas.java
@@ -0,0 +1,95 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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
+   */
+  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/src/main/java/com/sun/activation/viewers/TextEditor.java b/src/main/java/com/sun/activation/viewers/TextEditor.java
new file mode 100644
index 0000000..66a153f
--- /dev/null
+++ b/src/main/java/com/sun/activation/viewers/TextEditor.java
@@ -0,0 +1,203 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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.
+   */
+    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/src/main/java/com/sun/activation/viewers/TextViewer.java b/src/main/java/com/sun/activation/viewers/TextViewer.java
new file mode 100644
index 0000000..6019fc7
--- /dev/null
+++ b/src/main/java/com/sun/activation/viewers/TextViewer.java
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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.
+   */
+  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/src/main/java/doc-files/speclicense.html b/src/main/java/doc-files/speclicense.html
new file mode 100644
index 0000000..922d5df
--- /dev/null
+++ b/src/main/java/doc-files/speclicense.html
@@ -0,0 +1,213 @@
+<html>
+<head>
+<title>Specification License</title>
+</head>
+<body>
+Specification: JSR-925 JavaBeans Activation Framework ("Specification")
+<br/>
+Version: 1.2
+<br/>
+Status: Maintenance Release
+<br/>
+Specification Lead: Oracle America, Inc. ("Specification Lead")
+<br/>
+Release: July 2017
+<br/>
+
+<br/>
+Copyright &#169; 2017 Oracle America, Inc.  All rights reserved.
+<br/>
+<p>
+LIMITED LICENSE GRANTS
+<br/>
+1. License for Evaluation Purposes. Specification Lead hereby grants
+you a fully-paid, non-exclusive, non-transferable, worldwide, limited
+license (without the right to sublicense), under Specification Lead's
+applicable intellectual property rights to view, download, use and
+reproduce the Specification only for the purpose of internal
+evaluation.  This includes (i) developing applications intended to run
+on an implementation of the Specification, provided that such
+applications do not themselves implement any portion(s) of the
+Specification, and (ii) discussing the Specification with any third
+party; and (iii) excerpting brief portions of the Specification in oral
+or written communications which discuss the Specification provided that
+such excerpts do not in the aggregate constitute a significant portion
+of the Specification.
+</p>
+<p>
+2. License for the Distribution of Compliant Implementations.
+Specification Lead  also grants you a perpetual, non-exclusive,
+non-transferable, worldwide, fully paid-up, royalty free, limited
+license (without the right to sublicense) under any applicable
+copyrights or, subject to the provisions of subsection 4 below, patent
+rights it may have covering the Specification to create and/or
+distribute an Independent Implementation of the Specification that: (a)
+fully implements the Specification including all its required
+interfaces and functionality; (b) does not modify, subset, superset or
+otherwise extend the Licensor Name Space, or include any public or
+protected packages, classes, Java interfaces, fields or methods within
+the Licensor Name Space other than those required/authorized by the
+Specification or Specifications being implemented; and (c) passes the
+Technology Compatibility Kit (including satisfying the requirements of
+the applicable TCK Users Guide) for such Specification ("Compliant
+Implementation").  In addition, the foregoing license is expressly
+conditioned on your not acting outside its scope.  No license is
+granted hereunder for any other purpose (including, for example,
+modifying the Specification, other than to the extent of your fair use
+rights, or distributing the Specification to third parties).  Also, no
+right, title, or interest in or to any trademarks, service marks, or
+trade names of Specification Lead or Specification Lead's licensors is
+granted hereunder.  Java, and Java-related logos, marks and names are
+trademarks or registered trademarks of Oracle America, Inc. in the U.S.
+and other countries.
+</p>
+<p>
+3. Pass-through Conditions. You need not include limitations (a)-(c)
+from the previous paragraph or any other particular "pass through"
+requirements in any license You grant concerning the use of your
+Independent Implementation or products derived from it.  However,
+except with respect to Independent Implementations (and products
+derived from them) that satisfy limitations (a)-(c) from the previous
+paragraph, You may neither:  (a) grant or otherwise pass through to
+your licensees any licenses under Specification Lead's  applicable
+intellectual property rights; nor (b) authorize your licensees to make
+any claims concerning their implementation's compliance with the
+Specification in question.
+</p>
+<p>
+4. Reciprocity Concerning Patent Licenses.  
+<br/>
+a.  With respect to any patent claims covered by the license granted
+under subparagraph 2 above that would be infringed by all technically
+feasible implementations of the Specification, such license is
+conditioned upon your offering on fair, reasonable and
+non-discriminatory terms, to any party seeking it from You, a
+perpetual, non-exclusive, non-transferable, worldwide license under
+Your patent rights which are or would be infringed by all technically
+feasible implementations of the Specification to develop, distribute
+and use a Compliant Implementation.
+<br/>
+b.  With respect to any patent claims owned by Specification Lead and
+covered by the license granted under subparagraph 2, whether or not
+their infringement can be avoided in a technically feasible manner when
+implementing the Specification, such license shall terminate with
+respect to such claims if You initiate a claim against Specification
+Lead that it has, in the course of performing its responsibilities as
+the Specification Lead, induced any other entity to infringe Your
+patent rights.
+<br/>
+c.  Also with respect to any patent claims owned by Specification Lead
+and covered by the license granted under subparagraph 2 above, where
+the infringement of such claims can be avoided in a technically
+feasible manner when implementing the Specification such license, with
+respect to such claims, shall terminate if You initiate a claim against
+Specification Lead  that its making, having made, using, offering to
+sell, selling or importing a Compliant Implementation infringes Your
+patent rights.
+</p>
+<p>
+5. Definitions. For the purposes of this Agreement:  "Independent
+Implementation" shall mean an implementation of the Specification that
+neither derives from any of Specification Lead's  source code or binary
+code materials nor, except with an appropriate and separate license
+from Specification Lead, includes any of Specification Lead's  source
+code or binary code materials; "Licensor Name Space" shall mean the
+public class or interface declarations whose names begin with "java",
+"javax", "com.oracle", "com.sun" or their equivalents in any subsequent
+naming convention adopted by Oracle America, Inc. through the Java
+Community Process, or any recognized successors or replacements
+thereof; and "Technology Compatibility Kit" or "TCK" shall mean the
+test suite and accompanying TCK User's Guide provided by Specification
+Lead  which corresponds to the Specification and that was available
+either (i) from Specification Lead 120 days before the first release of
+Your Independent Implementation that allows its use for commercial
+purposes, or (ii) more recently than 120 days from such release but
+against which You elect to test Your implementation of the
+Specification.
+</p>
+<p>
+This Agreement will terminate immediately without notice from
+Specification Lead if you breach the Agreement or act outside the scope
+of the licenses granted above.
+</p>
+<p>
+DISCLAIMER OF WARRANTIES 
+<br/>
+THE SPECIFICATION IS PROVIDED "AS IS". SPECIFICATION LEAD MAKES NO
+REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, NON-INFRINGEMENT (INCLUDING AS A CONSEQUENCE OF ANY PRACTICE
+OR IMPLEMENTATION OF THE SPECIFICATION), OR THAT THE CONTENTS OF THE
+SPECIFICATION ARE SUITABLE FOR ANY PURPOSE.  This document does not
+represent any commitment to release or implement any portion of the
+Specification in any product. In addition, the Specification could
+include technical inaccuracies or typographical errors.
+</p>
+<p>
+LIMITATION OF LIABILITY
+<br/>
+TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SPECIFICATION
+LEAD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT
+LIMITATION, LOST REVENUE, PROFITS OR DATA, OR FOR SPECIAL, INDIRECT,
+CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED IN ANY
+WAY TO YOUR HAVING, IMPLEMENTING OR OTHERWISE USING THE SPECIFICATION,
+EVEN IF SPECIFICATION LEAD AND/OR ITS LICENSORS HAVE BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.  You will indemnify, hold harmless,
+and defend Specification Lead and its licensors from any claims arising
+or resulting from: (i) your use of the Specification; (ii) the use or
+distribution of your Java application, applet and/or implementation;
+and/or (iii) any claims that later versions or releases of any
+Specification furnished to you are incompatible with the Specification
+provided to you under this license.
+</p>
+<p>
+RESTRICTED RIGHTS LEGEND 
+<br/>
+U.S. Government: If this Specification is being acquired by or on
+behalf of the U.S. Government or by a U.S. Government prime contractor
+or subcontractor (at any tier), then the Government's rights in the
+Software and accompanying documentation shall be only as set forth in
+this license; this is in accordance with 48 C.F.R. 227.7201 through
+227.7202-4 (for Department of Defense (DoD) acquisitions) and with 48
+C.F.R. 2.101 and 12.212 (for non-DoD acquisitions).
+</p>
+<p>
+REPORT
+<br/>
+If you provide Specification Lead with any comments or suggestions
+concerning the Specification ("Feedback"), you hereby: (i) agree that
+such Feedback is provided on a non-proprietary and non-confidential
+basis, and (ii) grant Specification Lead a perpetual, non-exclusive,
+worldwide, fully paid-up, irrevocable license, with the right to
+sublicense through multiple levels of sublicensees, to incorporate,
+disclose, and use without limitation the Feedback for any purpose.
+</p>
+<p>
+GENERAL TERMS
+<br/>
+Any action related to this Agreement will be governed by California law
+and controlling U.S. federal law. The U.N. Convention for the
+International Sale of Goods and the choice of law rules of any
+jurisdiction will not apply.
+</p>
+<p>
+The Specification is subject to U.S. export control laws and may be
+subject to export or import regulations in other countries. Licensee
+agrees to comply strictly with all such laws and regulations and
+acknowledges that it has the responsibility to obtain such licenses to
+export, re-export or import as may be required after delivery to
+Licensee.
+</p>
+<p>
+This Agreement is the parties' entire agreement relating to its subject
+matter. It supersedes all prior or contemporaneous oral or written
+communications, proposals, conditions, representations and warranties
+and prevails over any conflicting or additional terms of any quote,
+order,  acknowledgment, or other communication between the parties
+relating to its subject matter during the term of this Agreement. No
+modification to this Agreement will be binding, unless in writing and
+signed by an authorized representative of each party.
+</p>
+</body>
+</html>
diff --git a/src/main/java/javax/activation/ActivationDataFlavor.java b/src/main/java/javax/activation/ActivationDataFlavor.java
new file mode 100644
index 0000000..e1b456e
--- /dev/null
+++ b/src/main/java/javax/activation/ActivationDataFlavor.java
@@ -0,0 +1,263 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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 the JavaBeans Activation
+     * Framework. 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/src/main/java/javax/activation/CommandInfo.java b/src/main/java/javax/activation/CommandInfo.java
new file mode 100644
index 0000000..0297938
--- /dev/null
+++ b/src/main/java/javax/activation/CommandInfo.java
@@ -0,0 +1,245 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/CommandMap.java b/src/main/java/javax/activation/CommandMap.java
new file mode 100644
index 0000000..f51064c
--- /dev/null
+++ b/src/main/java/javax/activation/CommandMap.java
@@ -0,0 +1,249 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/CommandObject.java b/src/main/java/javax/activation/CommandObject.java
new file mode 100644
index 0000000..f37f687
--- /dev/null
+++ b/src/main/java/javax/activation/CommandObject.java
@@ -0,0 +1,68 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.activation;
+
+import java.io.IOException;
+
+/**
+ * JavaBeans components that are Activation Framework 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/src/main/java/javax/activation/DataContentHandler.java b/src/main/java/javax/activation/DataContentHandler.java
new file mode 100644
index 0000000..78c01ca
--- /dev/null
+++ b/src/main/java/javax/activation/DataContentHandler.java
@@ -0,0 +1,114 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/DataContentHandlerFactory.java b/src/main/java/javax/activation/DataContentHandlerFactory.java
new file mode 100644
index 0000000..3e60d3e
--- /dev/null
+++ b/src/main/java/javax/activation/DataContentHandlerFactory.java
@@ -0,0 +1,61 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/DataHandler.java b/src/main/java/javax/activation/DataHandler.java
new file mode 100644
index 0000000..4f38c52
--- /dev/null
+++ b/src/main/java/javax/activation/DataHandler.java
@@ -0,0 +1,912 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/DataSource.java b/src/main/java/javax/activation/DataSource.java
new file mode 100644
index 0000000..51745b5
--- /dev/null
+++ b/src/main/java/javax/activation/DataSource.java
@@ -0,0 +1,101 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.activation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The DataSource interface provides the JavaBeans Activation Framework
+ * 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/src/main/java/javax/activation/FileDataSource.java b/src/main/java/javax/activation/FileDataSource.java
new file mode 100644
index 0000000..caf1c2b
--- /dev/null
+++ b/src/main/java/javax/activation/FileDataSource.java
@@ -0,0 +1,171 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/FileTypeMap.java b/src/main/java/javax/activation/FileTypeMap.java
new file mode 100644
index 0000000..74b2638
--- /dev/null
+++ b/src/main/java/javax/activation/FileTypeMap.java
@@ -0,0 +1,145 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/MailcapCommandMap.java b/src/main/java/javax/activation/MailcapCommandMap.java
new file mode 100644
index 0000000..c7c8508
--- /dev/null
+++ b/src/main/java/javax/activation/MailcapCommandMap.java
@@ -0,0 +1,737 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/MimeType.java b/src/main/java/javax/activation/MimeType.java
new file mode 100644
index 0000000..bed48a8
--- /dev/null
+++ b/src/main/java/javax/activation/MimeType.java
@@ -0,0 +1,359 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/MimeTypeParameterList.java b/src/main/java/javax/activation/MimeTypeParameterList.java
new file mode 100644
index 0000000..4f4926b
--- /dev/null
+++ b/src/main/java/javax/activation/MimeTypeParameterList.java
@@ -0,0 +1,354 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/MimeTypeParseException.java b/src/main/java/javax/activation/MimeTypeParseException.java
new file mode 100644
index 0000000..d17f760
--- /dev/null
+++ b/src/main/java/javax/activation/MimeTypeParseException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/MimetypesFileTypeMap.java b/src/main/java/javax/activation/MimetypesFileTypeMap.java
new file mode 100644
index 0000000..77d7ee9
--- /dev/null
+++ b/src/main/java/javax/activation/MimetypesFileTypeMap.java
@@ -0,0 +1,373 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/SecuritySupport.java b/src/main/java/javax/activation/SecuritySupport.java
new file mode 100644
index 0000000..cf6943e
--- /dev/null
+++ b/src/main/java/javax/activation/SecuritySupport.java
@@ -0,0 +1,144 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/URLDataSource.java b/src/main/java/javax/activation/URLDataSource.java
new file mode 100644
index 0000000..f5b937e
--- /dev/null
+++ b/src/main/java/javax/activation/URLDataSource.java
@@ -0,0 +1,150 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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 the JavaBeans Activation Framework
+ * 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/src/main/java/javax/activation/UnsupportedDataTypeException.java b/src/main/java/javax/activation/UnsupportedDataTypeException.java
new file mode 100644
index 0000000..6358d6d
--- /dev/null
+++ b/src/main/java/javax/activation/UnsupportedDataTypeException.java
@@ -0,0 +1,70 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+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/src/main/java/javax/activation/package.html b/src/main/java/javax/activation/package.html
new file mode 100644
index 0000000..8392470
--- /dev/null
+++ b/src/main/java/javax/activation/package.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The JavaBeans(TM) Activation Framework is used by the JavaMail(TM)
+API to manage MIME data.
+
+</BODY>
+</HTML>
diff --git a/src/main/java/pom.xml b/src/main/java/pom.xml
new file mode 100644
index 0000000..5d30bef
--- /dev/null
+++ b/src/main/java/pom.xml
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<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.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.sun.activation</groupId>
+    <artifactId>javax.activation</artifactId>
+    <packaging>jar</packaging>
+    <name>JavaBeans Activation Framework</name>
+
+    <properties>
+	<activation.extensionName>
+	    javax.activation
+	</activation.extensionName>
+	<activation.moduleName>
+	    java.activation
+	</activation.moduleName>
+	<activation.specificationTitle>
+	    JavaBeans(TM) Activation Framework 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>
+			    <source>1.5</source>
+			    <target>1.5</target>
+			    <fork>true</fork>
+			    <!--
+				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>
+		    <execution>
+			<id>default-testCompile</id>
+			<configuration>
+			    <source>1.5</source>
+			    <target>1.5</target>
+			</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>
+				JavaBeans Activation Framework API documentation
+			    </description>
+			    <doctitle>
+				JavaBeans Activation Framework API documentation
+			    </doctitle>
+			    <windowtitle>
+				JavaBeans Activation Framework API documentation
+			    </windowtitle>
+			    <splitindex>true</splitindex>
+			    <use>true</use>
+			    <notimestamp>true</notimestamp>
+			    <serialwarn>true</serialwarn>
+			    <quiet>true</quiet>
+			    <bottom>
+<![CDATA[Copyright &#169; 1996-2017,
+    <a href="http://www.oracle.com">Oracle</a>
+    and/or its affiliates. All Rights Reserved.
+    Use is subject to
+    <a href="{@docRoot}/doc-files/speclicense.html" target="_top">license terms</a>.
+]]>
+			    </bottom>
+			    <groups>
+				<group>
+				    <title>JavaBeans Activation Framework API Packages</title>
+				    <packages>javax.*</packages>
+				</group>
+			    </groups>
+			    <subpackages>javax.activation</subpackages>
+			    <!--
+				Links to Java SE javadocs.
+
+				XXX - links need to include a trailing "/."
+				      because Maven strips off a trailing "/"
+				      before passing the option to the javadoc
+				      command, which then strips off the last
+				      name if it doesn't end with "/".
+			    -->
+			    <links>
+				<link>http://docs.oracle.com/javase/1.5.0/docs/api/.</link>
+			    </links>
+			</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/v1_2_0/LICENSE b/src/main/resources/META-INF/LICENSE.txt
similarity index 100%
copy from v1_2_0/LICENSE
copy to src/main/resources/META-INF/LICENSE.txt
diff --git a/src/main/resources/META-INF/mailcap.default b/src/main/resources/META-INF/mailcap.default
new file mode 100644
index 0000000..542de7d
--- /dev/null
+++ b/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/src/main/resources/META-INF/mimetypes.default b/src/main/resources/META-INF/mimetypes.default
new file mode 100644
index 0000000..1b4056b
--- /dev/null
+++ b/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/v1_2_0/javax.activation-1.2.0-sources.jar b/v1_2_0/javax.activation-1.2.0-sources.jar
deleted file mode 100644
index 69e2e8a..0000000
--- a/v1_2_0/javax.activation-1.2.0-sources.jar
+++ /dev/null
Binary files differ
diff --git a/v1_2_0/javax.activation.jar b/v1_2_0/javax.activation.jar
deleted file mode 100644
index c0b9b29..0000000
--- a/v1_2_0/javax.activation.jar
+++ /dev/null
Binary files differ