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 © 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-<name></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>
+ * <mime type>; ; <parameter list><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 <mime type> <space separated file extensions><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 © 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