mirror of https://github.com/M66B/FairEmail.git
parent
21fb16e678
commit
d88b7036e1
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logging related methods.
|
||||||
|
*/
|
||||||
|
public class LogSupport {
|
||||||
|
private static boolean debug = false;
|
||||||
|
private static Logger logger;
|
||||||
|
private static final Level level = Level.FINE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
debug = Boolean.getBoolean("javax.activation.debug");
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// ignore any errors
|
||||||
|
}
|
||||||
|
logger = Logger.getLogger("javax.activation");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
private LogSupport() {
|
||||||
|
// private constructor, can't create instances
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(String msg) {
|
||||||
|
if (debug)
|
||||||
|
System.out.println(msg);
|
||||||
|
logger.log(level, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(String msg, Throwable t) {
|
||||||
|
if (debug)
|
||||||
|
System.out.println(msg + "; Exception: " + t);
|
||||||
|
logger.log(level, msg, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLoggable() {
|
||||||
|
return debug || logger.isLoggable(level);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,548 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MailcapFile {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map indexed by MIME type (string) that references
|
||||||
|
* a Map of commands for each type. The comand Map
|
||||||
|
* is indexed by the command name and references a List of
|
||||||
|
* class names (strings) for each command.
|
||||||
|
*/
|
||||||
|
private Map type_hash = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Another Map like above, but for fallback entries.
|
||||||
|
*/
|
||||||
|
private Map fallback_hash = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map indexed by MIME type (string) that references
|
||||||
|
* a List of native commands (string) corresponding to the type.
|
||||||
|
*/
|
||||||
|
private Map native_commands = new HashMap();
|
||||||
|
|
||||||
|
private static boolean addReverse = false;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
addReverse = Boolean.getBoolean("javax.activation.addreverse");
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// ignore any errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor that takes a filename as an argument.
|
||||||
|
*
|
||||||
|
* @param new_fname The file name of the mailcap file.
|
||||||
|
*/
|
||||||
|
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 <i>type</i>/* 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 <i>type</i>/* 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<br>
|
||||||
|
*
|
||||||
|
* 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("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to encapsulate Mailcap parsing related exceptions
|
||||||
|
*/
|
||||||
|
public class MailcapParseException extends Exception {
|
||||||
|
|
||||||
|
public MailcapParseException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MailcapParseException(String inInfo) {
|
||||||
|
super(inInfo);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tokenizer for strings in the form of "foo/bar; prop1=val1; ... ".
|
||||||
|
* Useful for parsing MIME content types.
|
||||||
|
*/
|
||||||
|
public class MailcapTokenizer {
|
||||||
|
|
||||||
|
public static final int UNKNOWN_TOKEN = 0;
|
||||||
|
public static final int START_TOKEN = 1;
|
||||||
|
public static final int STRING_TOKEN = 2;
|
||||||
|
public static final int EOI_TOKEN = 5;
|
||||||
|
public static final int SLASH_TOKEN = '/';
|
||||||
|
public static final int SEMICOLON_TOKEN = ';';
|
||||||
|
public static final int EQUALS_TOKEN = '=';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param inputString the string to tokenize
|
||||||
|
*/
|
||||||
|
public MailcapTokenizer(String inputString) {
|
||||||
|
data = inputString;
|
||||||
|
dataIndex = 0;
|
||||||
|
dataLength = inputString.length();
|
||||||
|
|
||||||
|
currentToken = START_TOKEN;
|
||||||
|
currentTokenValue = "";
|
||||||
|
|
||||||
|
isAutoquoting = false;
|
||||||
|
autoquoteChar = ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether auto-quoting is on or off.
|
||||||
|
*
|
||||||
|
* Auto-quoting means that all characters after the first
|
||||||
|
* non-whitespace, non-control character up to the auto-quote
|
||||||
|
* terminator character or EOI (minus any whitespace immediatley
|
||||||
|
* preceeding it) is considered a token.
|
||||||
|
*
|
||||||
|
* This is required for handling command strings in a mailcap entry.
|
||||||
|
*/
|
||||||
|
public void setIsAutoquoting(boolean value) {
|
||||||
|
isAutoquoting = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve current token.
|
||||||
|
*
|
||||||
|
* @return The current token value
|
||||||
|
*/
|
||||||
|
public int getCurrentToken() {
|
||||||
|
return currentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a String that describes the given token.
|
||||||
|
*/
|
||||||
|
public static String nameForToken(int token) {
|
||||||
|
String name = "really unknown";
|
||||||
|
|
||||||
|
switch(token) {
|
||||||
|
case UNKNOWN_TOKEN:
|
||||||
|
name = "unknown";
|
||||||
|
break;
|
||||||
|
case START_TOKEN:
|
||||||
|
name = "start";
|
||||||
|
break;
|
||||||
|
case STRING_TOKEN:
|
||||||
|
name = "string";
|
||||||
|
break;
|
||||||
|
case EOI_TOKEN:
|
||||||
|
name = "EOI";
|
||||||
|
break;
|
||||||
|
case SLASH_TOKEN:
|
||||||
|
name = "'/'";
|
||||||
|
break;
|
||||||
|
case SEMICOLON_TOKEN:
|
||||||
|
name = "';'";
|
||||||
|
break;
|
||||||
|
case EQUALS_TOKEN:
|
||||||
|
name = "'='";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve current token value.
|
||||||
|
*
|
||||||
|
* @return A String containing the current token value
|
||||||
|
*/
|
||||||
|
public String getCurrentTokenValue() {
|
||||||
|
return currentTokenValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process the next token.
|
||||||
|
*
|
||||||
|
* @return 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("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
import java.lang.*;
|
||||||
|
|
||||||
|
public class MimeTypeEntry {
|
||||||
|
private String type;
|
||||||
|
private String extension;
|
||||||
|
|
||||||
|
public MimeTypeEntry(String mime_type, String file_ext) {
|
||||||
|
type = mime_type;
|
||||||
|
extension = file_ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMIMEType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileExtension() {
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "MIMETypeEntry: " + type + ", " + extension;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.activation.registries;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class MimeTypeFile {
|
||||||
|
private String fname = null;
|
||||||
|
private Hashtable type_hash = new Hashtable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The construtor that takes a filename as an argument.
|
||||||
|
*
|
||||||
|
* @param new_fname The file name of the mime types file.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
//import java.awt.datatransfer.DataFlavor;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.activation.MimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ActivationDataFlavor class is a special subclass of
|
||||||
|
* <code>java.awt.datatransfer.DataFlavor</code>. It allows the JAF to
|
||||||
|
* set all three values stored by the DataFlavor class via a new
|
||||||
|
* constructor. It also contains improved MIME parsing in the <code>equals
|
||||||
|
* </code> method. Except for the improved parsing, its semantics are
|
||||||
|
* identical to that of the JDK's DataFlavor class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ActivationDataFlavor /*extends DataFlavor*/ {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Raison d'etre:
|
||||||
|
*
|
||||||
|
* The DataFlavor class included in JDK 1.1 has several limitations
|
||||||
|
* including piss poor MIME type parsing, and the limitation of
|
||||||
|
* only supporting serialized objects and InputStreams as
|
||||||
|
* representation objects. This class 'fixes' that.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// I think for now I'll keep copies of all the variables and
|
||||||
|
// then later I may choose try to better coexist with the base
|
||||||
|
// class *sigh*
|
||||||
|
private String mimeType = null;
|
||||||
|
private MimeType mimeObject = null;
|
||||||
|
private String humanPresentableName = null;
|
||||||
|
private Class representationClass = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a DataFlavor that represents an arbitrary
|
||||||
|
* Java object. This constructor is an extension of the
|
||||||
|
* JDK's DataFlavor in that it allows the explicit setting
|
||||||
|
* of all three DataFlavor attributes.
|
||||||
|
* <p>
|
||||||
|
* The returned DataFlavor will have the following characteristics:
|
||||||
|
* <p>
|
||||||
|
* representationClass = representationClass<br>
|
||||||
|
* mimeType = mimeType<br>
|
||||||
|
* humanName = humanName
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @param representationClass the class used in this DataFlavor
|
||||||
|
* @param mimeType the MIME type of the data represented by this class
|
||||||
|
* @param humanPresentableName the human presentable name of the flavor
|
||||||
|
*/
|
||||||
|
public ActivationDataFlavor(Class representationClass,
|
||||||
|
String mimeType, String humanPresentableName) {
|
||||||
|
//super(mimeType, humanPresentableName); // need to call super
|
||||||
|
|
||||||
|
// init private variables:
|
||||||
|
this.mimeType = mimeType;
|
||||||
|
this.humanPresentableName = humanPresentableName;
|
||||||
|
this.representationClass = representationClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a DataFlavor that represents a MimeType.
|
||||||
|
* <p>
|
||||||
|
* The returned DataFlavor will have the following characteristics:
|
||||||
|
* <p>
|
||||||
|
* If the mimeType is "application/x-java-serialized-object;
|
||||||
|
* class=", the result is the same as calling new
|
||||||
|
* DataFlavor(Class.forName()) as above.
|
||||||
|
* <p>
|
||||||
|
* otherwise:
|
||||||
|
* <p>
|
||||||
|
* representationClass = InputStream<p>
|
||||||
|
* mimeType = mimeType<p>
|
||||||
|
*
|
||||||
|
* @param representationClass the class used in this DataFlavor
|
||||||
|
* @param humanPresentableName the human presentable name of the flavor
|
||||||
|
*/
|
||||||
|
public ActivationDataFlavor(Class representationClass,
|
||||||
|
String humanPresentableName) {
|
||||||
|
//super(representationClass, humanPresentableName);
|
||||||
|
//this.mimeType = super.getMimeType();
|
||||||
|
this.mimeType = "application/x-java-serialized-object";
|
||||||
|
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(ActivationDataFlavor dataFlavor) {
|
||||||
|
return (isMimeTypeEqual(dataFlavor.mimeType) &&
|
||||||
|
dataFlavor.getRepresentationClass() == representationClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the string representation of the MIME type passed in equivalent
|
||||||
|
* to the MIME type of this DataFlavor. <p>
|
||||||
|
*
|
||||||
|
* ActivationDataFlavor delegates the comparison of MIME types to
|
||||||
|
* the MimeType class included as part of Jakarta Activation.
|
||||||
|
* This provides a more robust comparison than is normally
|
||||||
|
* available in the DataFlavor class.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @return true if the same MIME type
|
||||||
|
*/
|
||||||
|
public boolean isMimeTypeEqual(String mimeType) {
|
||||||
|
MimeType mt = null;
|
||||||
|
try {
|
||||||
|
if (mimeObject == null)
|
||||||
|
mimeObject = new MimeType(this.mimeType);
|
||||||
|
mt = new MimeType(mimeType);
|
||||||
|
} catch (MimeTypeParseException e) {
|
||||||
|
// something didn't parse, do a crude comparison
|
||||||
|
return this.mimeType.equalsIgnoreCase(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mimeObject.match(mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on DataFlavor for every MIME Type parameter to allow DataFlavor
|
||||||
|
* subclasses to handle special parameters like the text/plain charset
|
||||||
|
* parameters, whose values are case insensitive. (MIME type parameter
|
||||||
|
* values are supposed to be case sensitive).
|
||||||
|
* <p>
|
||||||
|
* This method is called for each parameter name/value pair and should
|
||||||
|
* return the normalized representation of the parameterValue.
|
||||||
|
* This method is never invoked by this implementation.
|
||||||
|
*
|
||||||
|
* @param parameterName the parameter name
|
||||||
|
* @param parameterValue the parameter value
|
||||||
|
* @return the normalized parameter value
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
protected String normalizeMimeTypeParameter(String parameterName,
|
||||||
|
String parameterValue) {
|
||||||
|
return parameterValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called for each MIME type string to give DataFlavor subtypes the
|
||||||
|
* opportunity to change how the normalization of MIME types is
|
||||||
|
* accomplished.
|
||||||
|
* One possible use would be to add default parameter/value pairs in cases
|
||||||
|
* where none are present in the MIME type string passed in.
|
||||||
|
* This method is never invoked by this implementation.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @return the normalized MIME type
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
protected String normalizeMimeType(String mimeType) {
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CommandInfo class is used by CommandMap implementations to
|
||||||
|
* describe the results of command requests. It provides the requestor
|
||||||
|
* with both the verb requested, as well as an instance of the
|
||||||
|
* bean. There is also a method that will return the name of the
|
||||||
|
* class that implements the command but <i>it is not guaranteed to
|
||||||
|
* return a valid value</i>. The reason for this is to allow CommandMap
|
||||||
|
* implmentations that subclass CommandInfo to provide special
|
||||||
|
* behavior. For example a CommandMap could dynamically generate
|
||||||
|
* JavaBeans. In this case, it might not be possible to create an
|
||||||
|
* object with all the correct state information solely from the class
|
||||||
|
* name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CommandInfo {
|
||||||
|
private String verb;
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Constructor for CommandInfo.
|
||||||
|
* @param verb The command verb this CommandInfo decribes.
|
||||||
|
* @param className The command's fully qualified class name.
|
||||||
|
*/
|
||||||
|
public CommandInfo(String verb, String className) {
|
||||||
|
this.verb = verb;
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the command verb.
|
||||||
|
*
|
||||||
|
* @return the command verb.
|
||||||
|
*/
|
||||||
|
public String getCommandName() {
|
||||||
|
return verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the command's class name. <i>This method MAY return null in
|
||||||
|
* cases where a CommandMap subclassed CommandInfo for its
|
||||||
|
* own purposes.</i> In other words, it might not be possible to
|
||||||
|
* create the correct state in the command by merely knowing
|
||||||
|
* its class name. <b>DO NOT DEPEND ON THIS METHOD RETURNING
|
||||||
|
* A VALID VALUE!</b>
|
||||||
|
*
|
||||||
|
* @return The class name of the command, or <i>null</i>
|
||||||
|
*/
|
||||||
|
public String getCommandClass() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the instantiated JavaBean component.
|
||||||
|
* <p>
|
||||||
|
* If the current runtime environment supports
|
||||||
|
* {@link java.beans.Beans#instantiate Beans.instantiate},
|
||||||
|
* use it to instantiate the JavaBeans component. Otherwise, use
|
||||||
|
* {@link java.lang.Class#forName Class.forName}.
|
||||||
|
* <p>
|
||||||
|
* The component class needs to be public.
|
||||||
|
* On Java SE 9 and newer, if the component class is in a named module,
|
||||||
|
* it needs to be in an exported package.
|
||||||
|
* <p>
|
||||||
|
* If the bean implements the <code>javax.activation.CommandObject</code>
|
||||||
|
* interface, call its <code>setCommandContext</code> method.
|
||||||
|
* <p>
|
||||||
|
* If the DataHandler parameter is null, then the bean is
|
||||||
|
* instantiated with no data. NOTE: this may be useful
|
||||||
|
* if for some reason the DataHandler that is passed in
|
||||||
|
* throws IOExceptions when this method attempts to
|
||||||
|
* access its InputStream. It will allow the caller to
|
||||||
|
* retrieve a reference to the bean if it can be
|
||||||
|
* instantiated.
|
||||||
|
* <p>
|
||||||
|
* If the bean does NOT implement the CommandObject interface,
|
||||||
|
* this method will check if it implements the
|
||||||
|
* java.io.Externalizable interface. If it does, the bean's
|
||||||
|
* readExternal method will be called if an InputStream
|
||||||
|
* can be acquired from the DataHandler.<p>
|
||||||
|
*
|
||||||
|
* @param dh The DataHandler that describes the data to be
|
||||||
|
* passed to the command.
|
||||||
|
* @param loader The ClassLoader to be used to instantiate the bean.
|
||||||
|
* @return The bean
|
||||||
|
* @exception IOException for failures reading data
|
||||||
|
* @exception ClassNotFoundException if command object class can't
|
||||||
|
* be found
|
||||||
|
* @see java.beans.Beans#instantiate
|
||||||
|
* @see javax.activation.CommandObject
|
||||||
|
*/
|
||||||
|
public Object getCommandObject(DataHandler dh, ClassLoader loader)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
Object new_bean = null;
|
||||||
|
|
||||||
|
// try to instantiate the bean
|
||||||
|
new_bean = Beans.instantiate(loader, className);
|
||||||
|
|
||||||
|
// if we got one and it is a CommandObject
|
||||||
|
if (new_bean != null) {
|
||||||
|
if (new_bean instanceof CommandObject) {
|
||||||
|
((CommandObject)new_bean).setCommandContext(verb, dh);
|
||||||
|
} else if (new_bean instanceof Externalizable) {
|
||||||
|
if (dh != null) {
|
||||||
|
InputStream is = dh.getInputStream();
|
||||||
|
if (is != null) {
|
||||||
|
((Externalizable)new_bean).readExternal(
|
||||||
|
new ObjectInputStream(is));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to invoke Beans.instantiate reflectively or the equivalent
|
||||||
|
* with core reflection when module java.desktop is not readable.
|
||||||
|
*/
|
||||||
|
private static final class Beans {
|
||||||
|
static final Method instantiateMethod;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Method m;
|
||||||
|
try {
|
||||||
|
Class<?> c = Class.forName("java.beans.Beans");
|
||||||
|
m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
m = null;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
m = null;
|
||||||
|
}
|
||||||
|
instantiateMethod = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to invoking java.beans.Beans.instantiate(loader, cn)
|
||||||
|
*/
|
||||||
|
static Object instantiate(ClassLoader loader, String cn)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
|
||||||
|
Exception exception;
|
||||||
|
|
||||||
|
if (instantiateMethod != null) {
|
||||||
|
|
||||||
|
// invoke Beans.instantiate
|
||||||
|
try {
|
||||||
|
return instantiateMethod.invoke(null, loader, cn);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
exception = e;
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
exception = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
SecurityManager security = System.getSecurityManager();
|
||||||
|
if (security != null) {
|
||||||
|
// if it's ok with the SecurityManager, it's ok with me.
|
||||||
|
String cname = cn.replace('/', '.');
|
||||||
|
if (cname.startsWith("[")) {
|
||||||
|
int b = cname.lastIndexOf('[') + 2;
|
||||||
|
if (b > 1 && b < cname.length()) {
|
||||||
|
cname = cname.substring(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int i = cname.lastIndexOf('.');
|
||||||
|
if (i != -1) {
|
||||||
|
security.checkPackageAccess(cname.substring(0, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beans.instantiate specified to use SCL when loader is null
|
||||||
|
if (loader == null) {
|
||||||
|
loader = (ClassLoader)
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
ClassLoader cl = null;
|
||||||
|
try {
|
||||||
|
cl = ClassLoader.getSystemClassLoader();
|
||||||
|
} catch (SecurityException ex) { }
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Class<?> beanClass = Class.forName(cn, true, loader);
|
||||||
|
try {
|
||||||
|
return beanClass.newInstance();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new ClassNotFoundException(beanClass + ": " + ex, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CommandMap class provides an interface to a registry of
|
||||||
|
* command objects available in the system.
|
||||||
|
* Developers are expected to either use the CommandMap
|
||||||
|
* implementation included with this package (MailcapCommandMap) or
|
||||||
|
* develop their own. Note that some of the methods in this class are
|
||||||
|
* abstract.
|
||||||
|
*/
|
||||||
|
public abstract class CommandMap {
|
||||||
|
private static CommandMap defaultCommandMap = null;
|
||||||
|
private static Map<ClassLoader,CommandMap> map =
|
||||||
|
new WeakHashMap<ClassLoader,CommandMap>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default CommandMap.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li> In cases where a CommandMap instance has been previously set
|
||||||
|
* to some value (via <i>setDefaultCommandMap</i>)
|
||||||
|
* return the CommandMap.
|
||||||
|
* <li>
|
||||||
|
* In cases where no CommandMap has been set, the CommandMap
|
||||||
|
* creates an instance of <code>MailcapCommandMap</code> and
|
||||||
|
* set that to the default, returning its value.
|
||||||
|
*
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @return the CommandMap
|
||||||
|
*/
|
||||||
|
public static synchronized CommandMap getDefaultCommandMap() {
|
||||||
|
if (defaultCommandMap != null)
|
||||||
|
return defaultCommandMap;
|
||||||
|
|
||||||
|
// fetch per-thread-context-class-loader default
|
||||||
|
ClassLoader tccl = SecuritySupport.getContextClassLoader();
|
||||||
|
CommandMap def = map.get(tccl);
|
||||||
|
if (def == null) {
|
||||||
|
def = new MailcapCommandMap();
|
||||||
|
map.put(tccl, def);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default CommandMap. Reset the CommandMap to the default by
|
||||||
|
* calling this method with <code>null</code>.
|
||||||
|
*
|
||||||
|
* @param commandMap The new default CommandMap.
|
||||||
|
* @exception SecurityException if the caller doesn't have permission
|
||||||
|
* to change the default
|
||||||
|
*/
|
||||||
|
public static synchronized void setDefaultCommandMap(CommandMap commandMap) {
|
||||||
|
SecurityManager security = System.getSecurityManager();
|
||||||
|
if (security != null) {
|
||||||
|
try {
|
||||||
|
// if it's ok with the SecurityManager, it's ok with me...
|
||||||
|
security.checkSetFactory();
|
||||||
|
} catch (SecurityException ex) {
|
||||||
|
// otherwise, we also allow it if this code and the
|
||||||
|
// factory come from the same (non-system) class loader (e.g.,
|
||||||
|
// the JAF classes were loaded with the applet classes).
|
||||||
|
ClassLoader cl = CommandMap.class.getClassLoader();
|
||||||
|
if (cl == null || cl.getParent() == null ||
|
||||||
|
cl != commandMap.getClass().getClassLoader()) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove any per-thread-context-class-loader CommandMap
|
||||||
|
map.remove(SecuritySupport.getContextClassLoader());
|
||||||
|
defaultCommandMap = commandMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the preferred command list from a MIME Type. The actual semantics
|
||||||
|
* are determined by the implementation of the CommandMap.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @return the CommandInfo classes that represent the command Beans.
|
||||||
|
*/
|
||||||
|
abstract public CommandInfo[] getPreferredCommands(String mimeType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the preferred command list from a MIME Type. The actual semantics
|
||||||
|
* are determined by the implementation of the CommandMap. <p>
|
||||||
|
*
|
||||||
|
* The <code>DataSource</code> provides extra information, such as
|
||||||
|
* the file name, that a CommandMap implementation may use to further
|
||||||
|
* refine the list of commands that are returned. The implementation
|
||||||
|
* in this class simply calls the <code>getPreferredCommands</code>
|
||||||
|
* method that ignores this argument.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @param ds a DataSource for the data
|
||||||
|
* @return the CommandInfo classes that represent the command Beans.
|
||||||
|
* @since JAF 1.1
|
||||||
|
*/
|
||||||
|
public CommandInfo[] getPreferredCommands(String mimeType, DataSource ds) {
|
||||||
|
return getPreferredCommands(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the available commands for this type. This method
|
||||||
|
* should return all the possible commands for this MIME type.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @return the CommandInfo objects representing all the commands.
|
||||||
|
*/
|
||||||
|
abstract public CommandInfo[] getAllCommands(String mimeType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the available commands for this type. This method
|
||||||
|
* should return all the possible commands for this MIME type. <p>
|
||||||
|
*
|
||||||
|
* The <code>DataSource</code> provides extra information, such as
|
||||||
|
* the file name, that a CommandMap implementation may use to further
|
||||||
|
* refine the list of commands that are returned. The implementation
|
||||||
|
* in this class simply calls the <code>getAllCommands</code>
|
||||||
|
* method that ignores this argument.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @param ds a DataSource for the data
|
||||||
|
* @return the CommandInfo objects representing all the commands.
|
||||||
|
* @since JAF 1.1
|
||||||
|
*/
|
||||||
|
public CommandInfo[] getAllCommands(String mimeType, DataSource ds) {
|
||||||
|
return getAllCommands(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default command corresponding to the MIME type.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @param cmdName the command name
|
||||||
|
* @return the CommandInfo corresponding to the command.
|
||||||
|
*/
|
||||||
|
abstract public CommandInfo getCommand(String mimeType, String cmdName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default command corresponding to the MIME type. <p>
|
||||||
|
*
|
||||||
|
* The <code>DataSource</code> provides extra information, such as
|
||||||
|
* the file name, that a CommandMap implementation may use to further
|
||||||
|
* refine the command that is chosen. The implementation
|
||||||
|
* in this class simply calls the <code>getCommand</code>
|
||||||
|
* method that ignores this argument.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @param cmdName the command name
|
||||||
|
* @param ds a DataSource for the data
|
||||||
|
* @return the CommandInfo corresponding to the command.
|
||||||
|
* @since JAF 1.1
|
||||||
|
*/
|
||||||
|
public CommandInfo getCommand(String mimeType, String cmdName,
|
||||||
|
DataSource ds) {
|
||||||
|
return getCommand(mimeType, cmdName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a DataContentHandler that corresponds to the MIME type.
|
||||||
|
* The mechanism and semantics for determining this are determined
|
||||||
|
* by the implementation of the particular CommandMap.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @return the DataContentHandler for the MIME type
|
||||||
|
*/
|
||||||
|
abstract public DataContentHandler createDataContentHandler(String
|
||||||
|
mimeType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a DataContentHandler that corresponds to the MIME type.
|
||||||
|
* The mechanism and semantics for determining this are determined
|
||||||
|
* by the implementation of the particular CommandMap. <p>
|
||||||
|
*
|
||||||
|
* The <code>DataSource</code> provides extra information, such as
|
||||||
|
* the file name, that a CommandMap implementation may use to further
|
||||||
|
* refine the choice of DataContentHandler. The implementation
|
||||||
|
* in this class simply calls the <code>createDataContentHandler</code>
|
||||||
|
* method that ignores this argument.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type
|
||||||
|
* @param ds a DataSource for the data
|
||||||
|
* @return the DataContentHandler for the MIME type
|
||||||
|
* @since JAF 1.1
|
||||||
|
*/
|
||||||
|
public DataContentHandler createDataContentHandler(String mimeType,
|
||||||
|
DataSource ds) {
|
||||||
|
return createDataContentHandler(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the MIME types known to this command map.
|
||||||
|
* If the command map doesn't support this operation,
|
||||||
|
* null is returned.
|
||||||
|
*
|
||||||
|
* @return array of MIME types as strings, or null if not supported
|
||||||
|
* @since JAF 1.1
|
||||||
|
*/
|
||||||
|
public String[] getMimeTypes() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JavaBeans components that are Jakarta Activation aware implement
|
||||||
|
* this interface to find out which command verb they're being asked
|
||||||
|
* to perform, and to obtain the DataHandler representing the
|
||||||
|
* data they should operate on. JavaBeans that don't implement
|
||||||
|
* this interface may be used as well. Such commands may obtain
|
||||||
|
* the data using the Externalizable interface, or using an
|
||||||
|
* application-specific method.
|
||||||
|
*/
|
||||||
|
public interface CommandObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Command with the verb it is requested to handle
|
||||||
|
* and the DataHandler that describes the data it will
|
||||||
|
* operate on. <b>NOTE:</b> it is acceptable for the caller
|
||||||
|
* to pass <i>null</i> as the value for <code>DataHandler</code>.
|
||||||
|
*
|
||||||
|
* @param verb The Command Verb this object refers to.
|
||||||
|
* @param dh The DataHandler.
|
||||||
|
* @exception IOException for failures accessing data
|
||||||
|
*/
|
||||||
|
public void setCommandContext(String verb, DataHandler dh)
|
||||||
|
throws IOException;
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
//import java.awt.datatransfer.DataFlavor;
|
||||||
|
//import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import javax.activation.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataContentHandler interface is implemented by objects that can
|
||||||
|
* be used to extend the capabilities of the DataHandler's implementation
|
||||||
|
* of the Transferable interface. Through <code>DataContentHandlers</code>
|
||||||
|
* the framework can be extended to convert streams in to objects, and
|
||||||
|
* to write objects to streams. <p>
|
||||||
|
*
|
||||||
|
* Applications don't generally call the methods in DataContentHandlers
|
||||||
|
* directly. Instead, an application calls the equivalent methods in
|
||||||
|
* DataHandler. The DataHandler will attempt to find an appropriate
|
||||||
|
* DataContentHandler that corresponds to its MIME type using the
|
||||||
|
* current DataContentHandlerFactory. The DataHandler then calls
|
||||||
|
* through to the methods in the DataContentHandler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface DataContentHandler {
|
||||||
|
/**
|
||||||
|
* Returns an array of DataFlavor objects indicating the flavors the
|
||||||
|
* data can be provided in. The array should be ordered according to
|
||||||
|
* preference for providing the data (from most richly descriptive to
|
||||||
|
* least descriptive).
|
||||||
|
*
|
||||||
|
* @return The DataFlavors.
|
||||||
|
*/
|
||||||
|
public ActivationDataFlavor[] 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 IOException if the data can't be accessed
|
||||||
|
*/
|
||||||
|
public Object getTransferData(ActivationDataFlavor 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;
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface defines a factory for <code>DataContentHandlers</code>. An
|
||||||
|
* implementation of this interface should map a MIME type into an
|
||||||
|
* instance of DataContentHandler. The design pattern for classes implementing
|
||||||
|
* this interface is the same as for the ContentHandler mechanism used in
|
||||||
|
* <code>java.net.URL</code>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface DataContentHandlerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DataContentHandler object for the MIME type.
|
||||||
|
*
|
||||||
|
* @param mimeType the MIME type to create the DataContentHandler for.
|
||||||
|
* @return The new <code>DataContentHandler</code>, or <i>null</i>
|
||||||
|
* if none are found.
|
||||||
|
*/
|
||||||
|
public DataContentHandler createDataContentHandler(String mimeType);
|
||||||
|
}
|
@ -0,0 +1,881 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.net.URL;
|
||||||
|
//import java.awt.datatransfer.Transferable;
|
||||||
|
//import java.awt.datatransfer.DataFlavor;
|
||||||
|
//import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataHandler class provides a consistent interface to data
|
||||||
|
* available in many different sources and formats.
|
||||||
|
* It manages simple stream to string conversions and related operations
|
||||||
|
* using DataContentHandlers.
|
||||||
|
* It provides access to commands that can operate on the data.
|
||||||
|
* The commands are found using a CommandMap. <p>
|
||||||
|
*
|
||||||
|
* <b>DataHandler and the Transferable Interface</b><p>
|
||||||
|
* DataHandler implements the Transferable interface so that data can
|
||||||
|
* be used in AWT data transfer operations, such as cut and paste and
|
||||||
|
* drag and drop. The implementation of the Transferable interface
|
||||||
|
* relies on the availability of an installed DataContentHandler
|
||||||
|
* object corresponding to the MIME type of the data represented in
|
||||||
|
* the specific instance of the DataHandler.<p>
|
||||||
|
*
|
||||||
|
* <b>DataHandler and CommandMaps</b><p>
|
||||||
|
* The DataHandler keeps track of the current CommandMap that it uses to
|
||||||
|
* service requests for commands (<code>getCommand</code>,
|
||||||
|
* <code>getAllCommands</code>, <code>getPreferredCommands</code>).
|
||||||
|
* Each instance of a DataHandler may have a CommandMap associated with
|
||||||
|
* it using the <code>setCommandMap</code> method. If a CommandMap was
|
||||||
|
* not set, DataHandler calls the <code>getDefaultCommandMap</code>
|
||||||
|
* method in CommandMap and uses the value it returns. See
|
||||||
|
* <i>CommandMap</i> for more information. <p>
|
||||||
|
*
|
||||||
|
* <b>DataHandler and URLs</b><p>
|
||||||
|
* The current DataHandler implementation creates a private
|
||||||
|
* instance of URLDataSource when it is constructed with a URL.
|
||||||
|
*
|
||||||
|
* @see javax.activation.CommandMap
|
||||||
|
* @see javax.activation.DataContentHandler
|
||||||
|
* @see javax.activation.DataSource
|
||||||
|
* @see javax.activation.URLDataSource
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DataHandler /*implements Transferable*/ {
|
||||||
|
|
||||||
|
// Use the datasource to indicate whether we were started via the
|
||||||
|
// DataSource constructor or the object constructor.
|
||||||
|
private DataSource dataSource = null;
|
||||||
|
private DataSource objDataSource = null;
|
||||||
|
|
||||||
|
// The Object and mimetype from the constructor (if passed in).
|
||||||
|
// object remains null if it was instantiated with a
|
||||||
|
// DataSource.
|
||||||
|
private Object object = null;
|
||||||
|
private String objectMimeType = null;
|
||||||
|
|
||||||
|
// Keep track of the CommandMap
|
||||||
|
private CommandMap currentCommandMap = null;
|
||||||
|
|
||||||
|
// our transfer flavors
|
||||||
|
private static final ActivationDataFlavor emptyFlavors[] = new ActivationDataFlavor[0];
|
||||||
|
private ActivationDataFlavor 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
|
||||||
|
*
|
||||||
|
* @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 ActivationDataFlavor[] 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(ActivationDataFlavor flavor) {
|
||||||
|
ActivationDataFlavor[] 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 IOException if an I/O error occurs
|
||||||
|
* @see javax.activation.ActivationDataFlavor
|
||||||
|
*/
|
||||||
|
public Object getTransferData(ActivationDataFlavor 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 ActivationDataFlavor 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 ActivationDataFlavor[] getTransferDataFlavors() {
|
||||||
|
|
||||||
|
if (transferFlavors == null) {
|
||||||
|
if (dch != null) { // is there a dch?
|
||||||
|
transferFlavors = dch.getTransferDataFlavors();
|
||||||
|
} else {
|
||||||
|
transferFlavors = new ActivationDataFlavor[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(ActivationDataFlavor 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);
|
||||||
|
throw new IOException("Unsupported DataFlavor: " + 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 ActivationDataFlavor 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 ActivationDataFlavor[] getTransferDataFlavors() {
|
||||||
|
if (transferFlavors == null) {
|
||||||
|
if (dch != null) {
|
||||||
|
transferFlavors = dch.getTransferDataFlavors();
|
||||||
|
} else {
|
||||||
|
transferFlavors = new ActivationDataFlavor[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(ActivationDataFlavor 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);
|
||||||
|
throw new IOException("Unsupported DataFlavor: " + 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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DataSource interface provides Jakarta Activation
|
||||||
|
* with an abstraction of an arbitrary collection of data. It
|
||||||
|
* provides a type for that data as well as access
|
||||||
|
* to it in the form of <code>InputStreams</code> and
|
||||||
|
* <code>OutputStreams</code> where appropriate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface DataSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an <code>InputStream</code> representing
|
||||||
|
* the data and throws the appropriate exception if it can
|
||||||
|
* not do so. Note that a new <code>InputStream</code> object must be
|
||||||
|
* returned each time this method is called, and the stream must be
|
||||||
|
* positioned at the beginning of the data.
|
||||||
|
*
|
||||||
|
* @return an InputStream
|
||||||
|
* @exception IOException for failures creating the InputStream
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an <code>OutputStream</code> where the
|
||||||
|
* data can be written and throws the appropriate exception if it can
|
||||||
|
* not do so. Note that a new <code>OutputStream</code> object must
|
||||||
|
* be returned each time this method is called, and the stream must
|
||||||
|
* be positioned at the location the data is to be written.
|
||||||
|
*
|
||||||
|
* @return an OutputStream
|
||||||
|
* @exception IOException for failures creating the OutputStream
|
||||||
|
*/
|
||||||
|
public OutputStream getOutputStream() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the MIME type of the data in the form of a
|
||||||
|
* string. It should always return a valid type. It is suggested
|
||||||
|
* that getContentType return "application/octet-stream" if the
|
||||||
|
* DataSource implementation can not determine the data type.
|
||||||
|
*
|
||||||
|
* @return the MIME Type
|
||||||
|
*/
|
||||||
|
public String getContentType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the <i>name</i> of this object where the name of the object
|
||||||
|
* is dependant on the nature of the underlying objects. DataSources
|
||||||
|
* encapsulating files may choose to return the filename of the object.
|
||||||
|
* (Typically this would be the last component of the filename, not an
|
||||||
|
* entire pathname.)
|
||||||
|
*
|
||||||
|
* @return the name of the object.
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import com.sun.activation.registries.MimeTypeFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FileDataSource class implements a simple DataSource object
|
||||||
|
* that encapsulates a file. It provides data typing services via
|
||||||
|
* a FileTypeMap object. <p>
|
||||||
|
*
|
||||||
|
* <b>FileDataSource Typing Semantics</b><p>
|
||||||
|
*
|
||||||
|
* The FileDataSource class delegates data typing of files
|
||||||
|
* to an object subclassed from the FileTypeMap class.
|
||||||
|
* The <code>setFileTypeMap</code> method can be used to explicitly
|
||||||
|
* set the FileTypeMap for an instance of FileDataSource. If no
|
||||||
|
* FileTypeMap is set, the FileDataSource will call the FileTypeMap's
|
||||||
|
* getDefaultFileTypeMap method to get the System's default FileTypeMap.
|
||||||
|
*
|
||||||
|
* @see javax.activation.DataSource
|
||||||
|
* @see javax.activation.FileTypeMap
|
||||||
|
* @see javax.activation.MimetypesFileTypeMap
|
||||||
|
*/
|
||||||
|
public class FileDataSource implements DataSource {
|
||||||
|
|
||||||
|
// keep track of original 'ref' passed in, non-null
|
||||||
|
// one indicated which was passed in:
|
||||||
|
private File _file = null;
|
||||||
|
private FileTypeMap typeMap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FileDataSource from a File object. <i>Note:
|
||||||
|
* The file will not actually be opened until a method is
|
||||||
|
* called that requires the file to be opened.</i>
|
||||||
|
*
|
||||||
|
* @param file the file
|
||||||
|
*/
|
||||||
|
public FileDataSource(File file) {
|
||||||
|
_file = file; // save the file Object...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FileDataSource from
|
||||||
|
* the specified path name. <i>Note:
|
||||||
|
* The file will not actually be opened until a method is
|
||||||
|
* called that requires the file to be opened.</i>
|
||||||
|
*
|
||||||
|
* @param name the system-dependent file name.
|
||||||
|
*/
|
||||||
|
public FileDataSource(String name) {
|
||||||
|
this(new File(name)); // use the file constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return an InputStream representing the
|
||||||
|
* the data and will throw an IOException if it can
|
||||||
|
* not do so. This method will return a new
|
||||||
|
* instance of InputStream with each invocation.
|
||||||
|
*
|
||||||
|
* @return an InputStream
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new FileInputStream(_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will return an OutputStream representing the
|
||||||
|
* the data and will throw an IOException if it can
|
||||||
|
* not do so. This method will return a new instance of
|
||||||
|
* OutputStream with each invocation.
|
||||||
|
*
|
||||||
|
* @return an OutputStream
|
||||||
|
*/
|
||||||
|
public OutputStream getOutputStream() throws IOException {
|
||||||
|
return new FileOutputStream(_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the MIME type of the data in the form of a
|
||||||
|
* string. This method uses the currently installed FileTypeMap. If
|
||||||
|
* there is no FileTypeMap explictly set, the FileDataSource will
|
||||||
|
* call the <code>getDefaultFileTypeMap</code> method on
|
||||||
|
* FileTypeMap to acquire a default FileTypeMap. <i>Note: By
|
||||||
|
* default, the FileTypeMap used will be a MimetypesFileTypeMap.</i>
|
||||||
|
*
|
||||||
|
* @return the MIME Type
|
||||||
|
* @see javax.activation.FileTypeMap#getDefaultFileTypeMap
|
||||||
|
*/
|
||||||
|
public String getContentType() {
|
||||||
|
// check to see if the type map is null?
|
||||||
|
if (typeMap == null)
|
||||||
|
return FileTypeMap.getDefaultFileTypeMap().getContentType(_file);
|
||||||
|
else
|
||||||
|
return typeMap.getContentType(_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the <i>name</i> of this object. The FileDataSource
|
||||||
|
* will return the file name of the object.
|
||||||
|
*
|
||||||
|
* @return the name of the object.
|
||||||
|
* @see javax.activation.DataSource
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return _file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the File object that corresponds to this FileDataSource.
|
||||||
|
* @return the File object for the file represented by this object.
|
||||||
|
*/
|
||||||
|
public File getFile() {
|
||||||
|
return _file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the FileTypeMap to use with this FileDataSource
|
||||||
|
*
|
||||||
|
* @param map The FileTypeMap for this object.
|
||||||
|
*/
|
||||||
|
public void setFileTypeMap(FileTypeMap map) {
|
||||||
|
typeMap = map;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The FileTypeMap is an abstract class that provides a data typing
|
||||||
|
* interface for files. Implementations of this class will
|
||||||
|
* implement the getContentType methods which will derive a content
|
||||||
|
* type from a file name or a File object. FileTypeMaps could use any
|
||||||
|
* scheme to determine the data type, from examining the file extension
|
||||||
|
* of a file (like the MimetypesFileTypeMap) to opening the file and
|
||||||
|
* trying to derive its type from the contents of the file. The
|
||||||
|
* FileDataSource class uses the default FileTypeMap (a MimetypesFileTypeMap
|
||||||
|
* unless changed) to determine the content type of files.
|
||||||
|
*
|
||||||
|
* @see javax.activation.FileTypeMap
|
||||||
|
* @see javax.activation.FileDataSource
|
||||||
|
* @see javax.activation.MimetypesFileTypeMap
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class FileTypeMap {
|
||||||
|
|
||||||
|
private static FileTypeMap defaultMap = null;
|
||||||
|
private static Map<ClassLoader,FileTypeMap> map =
|
||||||
|
new WeakHashMap<ClassLoader,FileTypeMap>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default constructor.
|
||||||
|
*/
|
||||||
|
public FileTypeMap() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the type of the file object. This method should
|
||||||
|
* always return a valid MIME type.
|
||||||
|
*
|
||||||
|
* @param file A file to be typed.
|
||||||
|
* @return The content type.
|
||||||
|
*/
|
||||||
|
abstract public String getContentType(File file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the type of the file passed in. This method should
|
||||||
|
* always return a valid MIME type.
|
||||||
|
*
|
||||||
|
* @param filename the pathname of the file.
|
||||||
|
* @return The content type.
|
||||||
|
*/
|
||||||
|
abstract public String getContentType(String filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default FileTypeMap for the system. This instance
|
||||||
|
* will be returned to callers of getDefaultFileTypeMap.
|
||||||
|
*
|
||||||
|
* @param fileTypeMap The FileTypeMap.
|
||||||
|
* @exception SecurityException if the caller doesn't have permission
|
||||||
|
* to change the default
|
||||||
|
*/
|
||||||
|
public static synchronized void setDefaultFileTypeMap(FileTypeMap fileTypeMap) {
|
||||||
|
SecurityManager security = System.getSecurityManager();
|
||||||
|
if (security != null) {
|
||||||
|
try {
|
||||||
|
// if it's ok with the SecurityManager, it's ok with me...
|
||||||
|
security.checkSetFactory();
|
||||||
|
} catch (SecurityException ex) {
|
||||||
|
// otherwise, we also allow it if this code and the
|
||||||
|
// factory come from the same (non-system) class loader (e.g.,
|
||||||
|
// the JAF classes were loaded with the applet classes).
|
||||||
|
ClassLoader cl = FileTypeMap.class.getClassLoader();
|
||||||
|
if (cl == null || cl.getParent() == null ||
|
||||||
|
cl != fileTypeMap.getClass().getClassLoader())
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove any per-thread-context-class-loader FileTypeMap
|
||||||
|
map.remove(SecuritySupport.getContextClassLoader());
|
||||||
|
defaultMap = fileTypeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the default FileTypeMap for the system.
|
||||||
|
* If setDefaultFileTypeMap was called, return
|
||||||
|
* that instance, otherwise return an instance of
|
||||||
|
* <code>MimetypesFileTypeMap</code>.
|
||||||
|
*
|
||||||
|
* @return The default FileTypeMap
|
||||||
|
* @see javax.activation.FileTypeMap#setDefaultFileTypeMap
|
||||||
|
*/
|
||||||
|
public static synchronized FileTypeMap getDefaultFileTypeMap() {
|
||||||
|
if (defaultMap != null)
|
||||||
|
return defaultMap;
|
||||||
|
|
||||||
|
// fetch per-thread-context-class-loader default
|
||||||
|
ClassLoader tccl = SecuritySupport.getContextClassLoader();
|
||||||
|
FileTypeMap def = map.get(tccl);
|
||||||
|
if (def == null) {
|
||||||
|
def = new MimetypesFileTypeMap();
|
||||||
|
map.put(tccl, def);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,707 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import com.sun.activation.registries.MailcapFile;
|
||||||
|
import com.sun.activation.registries.LogSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MailcapCommandMap extends the CommandMap
|
||||||
|
* abstract class. It implements a CommandMap whose configuration
|
||||||
|
* is based on mailcap files
|
||||||
|
* (<A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>).
|
||||||
|
* The MailcapCommandMap can be configured both programmatically
|
||||||
|
* and via configuration files.
|
||||||
|
* <p>
|
||||||
|
* <b>Mailcap file search order:</b><p>
|
||||||
|
* The MailcapCommandMap looks in various places in the user's
|
||||||
|
* system for mailcap file entries. When requests are made
|
||||||
|
* to search for commands in the MailcapCommandMap, it searches
|
||||||
|
* mailcap files in the following order:
|
||||||
|
* <ol>
|
||||||
|
* <li> Programatically added entries to the MailcapCommandMap instance.
|
||||||
|
* <li> The file <code>.mailcap</code> in the user's home directory.
|
||||||
|
* <li> The file <code>mailcap</code> in the Java runtime.
|
||||||
|
* <li> The file or resources named <code>META-INF/mailcap</code>.
|
||||||
|
* <li> The file or resource named <code>META-INF/mailcap.default</code>
|
||||||
|
* (usually found only in the <code>activation.jar</code> file).
|
||||||
|
* </ol>
|
||||||
|
* <p>
|
||||||
|
* (The current implementation looks for the <code>mailcap</code> file
|
||||||
|
* in the Java runtime in the directory <code><i>java.home</i>/conf</code>
|
||||||
|
* if it exists, and otherwise in the directory
|
||||||
|
* <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
|
||||||
|
* of the "java.home" System property. Note that the "conf" directory was
|
||||||
|
* introduced in JDK 9.)
|
||||||
|
* <p>
|
||||||
|
* <b>Mailcap file format:</b><p>
|
||||||
|
*
|
||||||
|
* Mailcap files must conform to the mailcap
|
||||||
|
* file specification (RFC 1524, <i>A User Agent Configuration Mechanism
|
||||||
|
* For Multimedia Mail Format Information</i>).
|
||||||
|
* The file format consists of entries corresponding to
|
||||||
|
* particular MIME types. In general, the specification
|
||||||
|
* specifies <i>applications</i> for clients to use when they
|
||||||
|
* themselves cannot operate on the specified MIME type. The
|
||||||
|
* MailcapCommandMap extends this specification by using a parameter mechanism
|
||||||
|
* in mailcap files that allows JavaBeans(tm) components to be specified as
|
||||||
|
* corresponding to particular commands for a MIME type.<p>
|
||||||
|
*
|
||||||
|
* When a mailcap file is
|
||||||
|
* parsed, the MailcapCommandMap recognizes certain parameter signatures,
|
||||||
|
* specifically those parameter names that begin with <code>x-java-</code>.
|
||||||
|
* The MailcapCommandMap uses this signature to find
|
||||||
|
* command entries for inclusion into its registries.
|
||||||
|
* Parameter names with the form <code>x-java-<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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Multipurpose Internet Mail Extension (MIME) type, as defined
|
||||||
|
* in RFC 2045 and 2046.
|
||||||
|
*/
|
||||||
|
public class MimeType implements Externalizable {
|
||||||
|
|
||||||
|
private String primaryType;
|
||||||
|
private String subType;
|
||||||
|
private MimeTypeParameterList parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string that holds all the special chars.
|
||||||
|
*/
|
||||||
|
private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public MimeType() {
|
||||||
|
primaryType = "application";
|
||||||
|
subType = "*";
|
||||||
|
parameters = new MimeTypeParameterList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor that builds a MimeType from a String.
|
||||||
|
*
|
||||||
|
* @param rawdata the MIME type string
|
||||||
|
* @exception MimeTypeParseException if the MIME type can't be parsed
|
||||||
|
*/
|
||||||
|
public MimeType(String rawdata) throws MimeTypeParseException {
|
||||||
|
parse(rawdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor that builds a MimeType with the given primary and sub type
|
||||||
|
* but has an empty parameter list.
|
||||||
|
*
|
||||||
|
* @param primary the primary MIME type
|
||||||
|
* @param sub the MIME sub-type
|
||||||
|
* @exception MimeTypeParseException if the primary type or subtype
|
||||||
|
* is not a valid token
|
||||||
|
*/
|
||||||
|
public MimeType(String primary, String sub) throws MimeTypeParseException {
|
||||||
|
// check to see if primary is valid
|
||||||
|
if (isValidToken(primary)) {
|
||||||
|
primaryType = primary.toLowerCase(Locale.ENGLISH);
|
||||||
|
} else {
|
||||||
|
throw new MimeTypeParseException("Primary type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if sub is valid
|
||||||
|
if (isValidToken(sub)) {
|
||||||
|
subType = sub.toLowerCase(Locale.ENGLISH);
|
||||||
|
} else {
|
||||||
|
throw new MimeTypeParseException("Sub type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters = new MimeTypeParameterList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A routine for parsing the MIME type out of a String.
|
||||||
|
*/
|
||||||
|
private void parse(String rawdata) throws MimeTypeParseException {
|
||||||
|
int slashIndex = rawdata.indexOf('/');
|
||||||
|
int semIndex = rawdata.indexOf(';');
|
||||||
|
if ((slashIndex < 0) && (semIndex < 0)) {
|
||||||
|
// neither character is present, so treat it
|
||||||
|
// as an error
|
||||||
|
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||||
|
} else if ((slashIndex < 0) && (semIndex >= 0)) {
|
||||||
|
// we have a ';' (and therefore a parameter list),
|
||||||
|
// but no '/' indicating a sub type is present
|
||||||
|
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||||
|
} else if ((slashIndex >= 0) && (semIndex < 0)) {
|
||||||
|
// we have a primary and sub type but no parameter list
|
||||||
|
primaryType = rawdata.substring(0, slashIndex).trim().
|
||||||
|
toLowerCase(Locale.ENGLISH);
|
||||||
|
subType = rawdata.substring(slashIndex + 1).trim().
|
||||||
|
toLowerCase(Locale.ENGLISH);
|
||||||
|
parameters = new MimeTypeParameterList();
|
||||||
|
} else if (slashIndex < semIndex) {
|
||||||
|
// we have all three items in the proper sequence
|
||||||
|
primaryType = rawdata.substring(0, slashIndex).trim().
|
||||||
|
toLowerCase(Locale.ENGLISH);
|
||||||
|
subType = rawdata.substring(slashIndex + 1, semIndex).trim().
|
||||||
|
toLowerCase(Locale.ENGLISH);
|
||||||
|
parameters = new MimeTypeParameterList(rawdata.substring(semIndex));
|
||||||
|
} else {
|
||||||
|
// we have a ';' lexically before a '/' which means we
|
||||||
|
// have a primary type and a parameter list but no sub type
|
||||||
|
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// now validate the primary and sub types
|
||||||
|
|
||||||
|
// check to see if primary is valid
|
||||||
|
if (!isValidToken(primaryType))
|
||||||
|
throw new MimeTypeParseException("Primary type is invalid.");
|
||||||
|
|
||||||
|
// check to see if sub is valid
|
||||||
|
if (!isValidToken(subType))
|
||||||
|
throw new MimeTypeParseException("Sub type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the primary type of this object.
|
||||||
|
*
|
||||||
|
* @return the primary MIME type
|
||||||
|
*/
|
||||||
|
public String getPrimaryType() {
|
||||||
|
return primaryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the primary type for this object to the given String.
|
||||||
|
*
|
||||||
|
* @param primary the primary MIME type
|
||||||
|
* @exception MimeTypeParseException if the primary type
|
||||||
|
* is not a valid token
|
||||||
|
*/
|
||||||
|
public void setPrimaryType(String primary) throws MimeTypeParseException {
|
||||||
|
// check to see if primary is valid
|
||||||
|
if (!isValidToken(primaryType))
|
||||||
|
throw new MimeTypeParseException("Primary type is invalid.");
|
||||||
|
primaryType = primary.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the subtype of this object.
|
||||||
|
*
|
||||||
|
* @return the MIME subtype
|
||||||
|
*/
|
||||||
|
public String getSubType() {
|
||||||
|
return subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the subtype for this object to the given String.
|
||||||
|
*
|
||||||
|
* @param sub the MIME subtype
|
||||||
|
* @exception MimeTypeParseException if the subtype
|
||||||
|
* is not a valid token
|
||||||
|
*/
|
||||||
|
public void setSubType(String sub) throws MimeTypeParseException {
|
||||||
|
// check to see if sub is valid
|
||||||
|
if (!isValidToken(subType))
|
||||||
|
throw new MimeTypeParseException("Sub type is invalid.");
|
||||||
|
subType = sub.toLowerCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve this object's parameter list.
|
||||||
|
*
|
||||||
|
* @return a MimeTypeParameterList object representing the parameters
|
||||||
|
*/
|
||||||
|
public MimeTypeParameterList getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value associated with the given name, or null if there
|
||||||
|
* is no current association.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
* @return the paramter's value
|
||||||
|
*/
|
||||||
|
public String getParameter(String name) {
|
||||||
|
return parameters.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value to be associated with the given name, replacing
|
||||||
|
* any previous association.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param value the paramter's value
|
||||||
|
*/
|
||||||
|
public void setParameter(String name, String value) {
|
||||||
|
parameters.set(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any value associated with the given name.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
*/
|
||||||
|
public void removeParameter(String name) {
|
||||||
|
parameters.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the String representation of this object.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getBaseType() + parameters.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a String representation of this object
|
||||||
|
* without the parameter list.
|
||||||
|
*
|
||||||
|
* @return the MIME type and sub-type
|
||||||
|
*/
|
||||||
|
public String getBaseType() {
|
||||||
|
return primaryType + "/" + subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the primary and sub type of this object is
|
||||||
|
* the same as what is in the given type.
|
||||||
|
*
|
||||||
|
* @param type the MimeType object to compare with
|
||||||
|
* @return true if they match
|
||||||
|
*/
|
||||||
|
public boolean match(MimeType type) {
|
||||||
|
return primaryType.equals(type.getPrimaryType())
|
||||||
|
&& (subType.equals("*")
|
||||||
|
|| type.getSubType().equals("*")
|
||||||
|
|| (subType.equals(type.getSubType())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the primary and sub type of this object is
|
||||||
|
* the same as the content type described in rawdata.
|
||||||
|
*
|
||||||
|
* @param rawdata the MIME type string to compare with
|
||||||
|
* @return true if they match
|
||||||
|
* @exception MimeTypeParseException if the MIME type can't be parsed
|
||||||
|
*/
|
||||||
|
public boolean match(String rawdata) throws MimeTypeParseException {
|
||||||
|
return match(new MimeType(rawdata));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object implements the writeExternal method to save its contents
|
||||||
|
* by calling the methods of DataOutput for its primitive values or
|
||||||
|
* calling the writeObject method of ObjectOutput for objects, strings
|
||||||
|
* and arrays.
|
||||||
|
*
|
||||||
|
* @param out the ObjectOutput object to write to
|
||||||
|
* @exception IOException Includes any I/O exceptions that may occur
|
||||||
|
*/
|
||||||
|
public void writeExternal(ObjectOutput out) throws IOException {
|
||||||
|
out.writeUTF(toString());
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object implements the readExternal method to restore its
|
||||||
|
* contents by calling the methods of DataInput for primitive
|
||||||
|
* types and readObject for objects, strings and arrays. The
|
||||||
|
* readExternal method must read the values in the same sequence
|
||||||
|
* and with the same types as were written by writeExternal.
|
||||||
|
*
|
||||||
|
* @param in the ObjectInput object to read from
|
||||||
|
* @exception ClassNotFoundException If the class for an object being
|
||||||
|
* restored cannot be found.
|
||||||
|
*/
|
||||||
|
public void readExternal(ObjectInput in)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
parse(in.readUTF());
|
||||||
|
} catch (MimeTypeParseException e) {
|
||||||
|
throw new IOException(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// below here be scary parsing related things
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether or not a given character belongs to a legal token.
|
||||||
|
*/
|
||||||
|
private static boolean isTokenChar(char c) {
|
||||||
|
return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether or not a given string is a legal token.
|
||||||
|
*/
|
||||||
|
private boolean isValidToken(String s) {
|
||||||
|
int len = s.length();
|
||||||
|
if (len > 0) {
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
char c = s.charAt(i);
|
||||||
|
if (!isTokenChar(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple parser test,
|
||||||
|
* for debugging...
|
||||||
|
*
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws MimeTypeParseException, IOException {
|
||||||
|
for (int i = 0; i < args.length; ++i) {
|
||||||
|
System.out.println("Original: " + args[i]);
|
||||||
|
|
||||||
|
MimeType type = new MimeType(args[i]);
|
||||||
|
|
||||||
|
System.out.println("Short: " + type.getBaseType());
|
||||||
|
System.out.println("Parsed: " + type.toString());
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parameter list of a MimeType
|
||||||
|
* as defined in RFC 2045 and 2046. The Primary type of the
|
||||||
|
* object must already be stripped off.
|
||||||
|
*
|
||||||
|
* @see javax.activation.MimeType
|
||||||
|
*/
|
||||||
|
public class MimeTypeParameterList {
|
||||||
|
private Hashtable parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string that holds all the special chars.
|
||||||
|
*/
|
||||||
|
private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
public MimeTypeParameterList() {
|
||||||
|
parameters = new Hashtable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new MimeTypeParameterList with the passed in data.
|
||||||
|
*
|
||||||
|
* @param parameterList an RFC 2045, 2046 compliant parameter list.
|
||||||
|
* @exception MimeTypeParseException if the MIME type can't be parsed
|
||||||
|
*/
|
||||||
|
public MimeTypeParameterList(String parameterList)
|
||||||
|
throws MimeTypeParseException {
|
||||||
|
parameters = new Hashtable();
|
||||||
|
|
||||||
|
// now parse rawdata
|
||||||
|
parse(parameterList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A routine for parsing the parameter list out of a String.
|
||||||
|
*
|
||||||
|
* @param parameterList an RFC 2045, 2046 compliant parameter list.
|
||||||
|
* @exception MimeTypeParseException if the MIME type can't be parsed
|
||||||
|
*/
|
||||||
|
protected void parse(String parameterList) throws MimeTypeParseException {
|
||||||
|
if (parameterList == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int length = parameterList.length();
|
||||||
|
if (length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
char c;
|
||||||
|
for (i = skipWhiteSpace(parameterList, 0);
|
||||||
|
i < length && (c = parameterList.charAt(i)) == ';';
|
||||||
|
i = skipWhiteSpace(parameterList, i)) {
|
||||||
|
int lastIndex;
|
||||||
|
String name;
|
||||||
|
String value;
|
||||||
|
|
||||||
|
// eat the ';'
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// now parse the parameter name
|
||||||
|
|
||||||
|
// skip whitespace
|
||||||
|
i = skipWhiteSpace(parameterList, i);
|
||||||
|
|
||||||
|
// tolerate trailing semicolon, even though it violates the spec
|
||||||
|
if (i >= length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// find the end of the token char run
|
||||||
|
lastIndex = i;
|
||||||
|
while ((i < length) && isTokenChar(parameterList.charAt(i)))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
name = parameterList.substring(lastIndex, i).
|
||||||
|
toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
|
// now parse the '=' that separates the name from the value
|
||||||
|
i = skipWhiteSpace(parameterList, i);
|
||||||
|
|
||||||
|
if (i >= length || parameterList.charAt(i) != '=')
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"Couldn't find the '=' that separates a " +
|
||||||
|
"parameter name from its value.");
|
||||||
|
|
||||||
|
// eat it and parse the parameter value
|
||||||
|
i++;
|
||||||
|
i = skipWhiteSpace(parameterList, i);
|
||||||
|
|
||||||
|
if (i >= length)
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"Couldn't find a value for parameter named " + name);
|
||||||
|
|
||||||
|
// now find out whether or not we have a quoted value
|
||||||
|
c = parameterList.charAt(i);
|
||||||
|
if (c == '"') {
|
||||||
|
// yup it's quoted so eat it and capture the quoted string
|
||||||
|
i++;
|
||||||
|
if (i >= length)
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"Encountered unterminated quoted parameter value.");
|
||||||
|
|
||||||
|
lastIndex = i;
|
||||||
|
|
||||||
|
// find the next unescaped quote
|
||||||
|
while (i < length) {
|
||||||
|
c = parameterList.charAt(i);
|
||||||
|
if (c == '"')
|
||||||
|
break;
|
||||||
|
if (c == '\\') {
|
||||||
|
// found an escape sequence
|
||||||
|
// so skip this and the
|
||||||
|
// next character
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (c != '"')
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"Encountered unterminated quoted parameter value.");
|
||||||
|
|
||||||
|
value = unquote(parameterList.substring(lastIndex, i));
|
||||||
|
// eat the quote
|
||||||
|
i++;
|
||||||
|
} else if (isTokenChar(c)) {
|
||||||
|
// nope it's an ordinary token so it
|
||||||
|
// ends with a non-token char
|
||||||
|
lastIndex = i;
|
||||||
|
while (i < length && isTokenChar(parameterList.charAt(i)))
|
||||||
|
i++;
|
||||||
|
value = parameterList.substring(lastIndex, i);
|
||||||
|
} else {
|
||||||
|
// it ain't a value
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"Unexpected character encountered at index " + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now put the data into the hashtable
|
||||||
|
parameters.put(name, value);
|
||||||
|
}
|
||||||
|
if (i < length) {
|
||||||
|
throw new MimeTypeParseException(
|
||||||
|
"More characters encountered in input than expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of name-value pairs in this list.
|
||||||
|
*
|
||||||
|
* @return the number of parameters
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return parameters.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether or not this list is empty.
|
||||||
|
*
|
||||||
|
* @return true if there are no parameters
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return parameters.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the value associated with the given name, or null if there
|
||||||
|
* is no current association.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
* @return the parameter's value
|
||||||
|
*/
|
||||||
|
public String get(String name) {
|
||||||
|
return (String)parameters.get(name.trim().toLowerCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value to be associated with the given name, replacing
|
||||||
|
* any previous association.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param value the parameter's value
|
||||||
|
*/
|
||||||
|
public void set(String name, String value) {
|
||||||
|
parameters.put(name.trim().toLowerCase(Locale.ENGLISH), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any value associated with the given name.
|
||||||
|
*
|
||||||
|
* @param name the parameter name
|
||||||
|
*/
|
||||||
|
public void remove(String name) {
|
||||||
|
parameters.remove(name.trim().toLowerCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an enumeration of all the names in this list.
|
||||||
|
*
|
||||||
|
* @return an enumeration of all parameter names
|
||||||
|
*/
|
||||||
|
public Enumeration getNames() {
|
||||||
|
return parameters.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string representation of this object.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.ensureCapacity(parameters.size() * 16);
|
||||||
|
// heuristic: 8 characters per field
|
||||||
|
|
||||||
|
Enumeration keys = parameters.keys();
|
||||||
|
while (keys.hasMoreElements()) {
|
||||||
|
String key = (String)keys.nextElement();
|
||||||
|
buffer.append("; ");
|
||||||
|
buffer.append(key);
|
||||||
|
buffer.append('=');
|
||||||
|
buffer.append(quote((String)parameters.get(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// below here be scary parsing related things
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether or not a given character belongs to a legal token.
|
||||||
|
*/
|
||||||
|
private static boolean isTokenChar(char c) {
|
||||||
|
return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the index of the first non white space character in
|
||||||
|
* rawdata at or after index i.
|
||||||
|
*/
|
||||||
|
private static int skipWhiteSpace(String rawdata, int i) {
|
||||||
|
int length = rawdata.length();
|
||||||
|
while ((i < length) && Character.isWhitespace(rawdata.charAt(i)))
|
||||||
|
i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A routine that knows how and when to quote and escape the given value.
|
||||||
|
*/
|
||||||
|
private static String quote(String value) {
|
||||||
|
boolean needsQuotes = false;
|
||||||
|
|
||||||
|
// check to see if we actually have to quote this thing
|
||||||
|
int length = value.length();
|
||||||
|
for (int i = 0; (i < length) && !needsQuotes; i++) {
|
||||||
|
needsQuotes = !isTokenChar(value.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsQuotes) {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.ensureCapacity((int)(length * 1.5));
|
||||||
|
|
||||||
|
// add the initial quote
|
||||||
|
buffer.append('"');
|
||||||
|
|
||||||
|
// add the properly escaped text
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if ((c == '\\') || (c == '"'))
|
||||||
|
buffer.append('\\');
|
||||||
|
buffer.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the closing quote
|
||||||
|
buffer.append('"');
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A routine that knows how to strip the quotes and
|
||||||
|
* escape sequences from the given value.
|
||||||
|
*/
|
||||||
|
private static String unquote(String value) {
|
||||||
|
int valueLength = value.length();
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
buffer.ensureCapacity(valueLength);
|
||||||
|
|
||||||
|
boolean escaped = false;
|
||||||
|
for (int i = 0; i < valueLength; ++i) {
|
||||||
|
char currentChar = value.charAt(i);
|
||||||
|
if (!escaped && (currentChar != '\\')) {
|
||||||
|
buffer.append(currentChar);
|
||||||
|
} else if (escaped) {
|
||||||
|
buffer.append(currentChar);
|
||||||
|
escaped = false;
|
||||||
|
} else {
|
||||||
|
escaped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to encapsulate MimeType parsing related exceptions.
|
||||||
|
*/
|
||||||
|
public class MimeTypeParseException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a MimeTypeParseException with no specified detail message.
|
||||||
|
*/
|
||||||
|
public MimeTypeParseException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a MimeTypeParseException with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param s the detail message.
|
||||||
|
*/
|
||||||
|
public MimeTypeParseException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import com.sun.activation.registries.MimeTypeFile;
|
||||||
|
import com.sun.activation.registries.LogSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class extends FileTypeMap and provides data typing of files
|
||||||
|
* via their file extension. It uses the <code>.mime.types</code> format. <p>
|
||||||
|
*
|
||||||
|
* <b>MIME types file search order:</b><p>
|
||||||
|
* The MimetypesFileTypeMap looks in various places in the user's
|
||||||
|
* system for MIME types file entries. When requests are made
|
||||||
|
* to search for MIME types in the MimetypesFileTypeMap, it searches
|
||||||
|
* MIME types files in the following order:
|
||||||
|
* <ol>
|
||||||
|
* <li> Programmatically added entries to the MimetypesFileTypeMap instance.
|
||||||
|
* <li> The file <code>.mime.types</code> in the user's home directory.
|
||||||
|
* <li> The file <code>mime.types</code> in the Java runtime.
|
||||||
|
* <li> The file or resources named <code>META-INF/mime.types</code>.
|
||||||
|
* <li> The file or resource named <code>META-INF/mimetypes.default</code>
|
||||||
|
* (usually found only in the <code>activation.jar</code> file).
|
||||||
|
* </ol>
|
||||||
|
* <p>
|
||||||
|
* (The current implementation looks for the <code>mime.types</code> file
|
||||||
|
* in the Java runtime in the directory <code><i>java.home</i>/conf</code>
|
||||||
|
* if it exists, and otherwise in the directory
|
||||||
|
* <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
|
||||||
|
* of the "java.home" System property. Note that the "conf" directory was
|
||||||
|
* introduced in JDK 9.)
|
||||||
|
* <p>
|
||||||
|
* <b>MIME types file format:</b><p>
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* # comments begin with a '#'<br>
|
||||||
|
* # the format is <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);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security related methods that only work on J2SE 1.2 and newer.
|
||||||
|
*/
|
||||||
|
class SecuritySupport {
|
||||||
|
|
||||||
|
private SecuritySupport() {
|
||||||
|
// private constructor, can't create an instance
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassLoader getContextClassLoader() {
|
||||||
|
return (ClassLoader)
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
ClassLoader cl = null;
|
||||||
|
try {
|
||||||
|
cl = Thread.currentThread().getContextClassLoader();
|
||||||
|
} catch (SecurityException ex) { }
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getResourceAsStream(final Class c,
|
||||||
|
final String name) throws IOException {
|
||||||
|
try {
|
||||||
|
return (InputStream)
|
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws IOException {
|
||||||
|
return c.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (PrivilegedActionException e) {
|
||||||
|
throw (IOException)e.getException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static URL[] getResources(final ClassLoader cl, final String name) {
|
||||||
|
return (URL[])
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
URL[] ret = null;
|
||||||
|
try {
|
||||||
|
List v = new ArrayList();
|
||||||
|
Enumeration e = cl.getResources(name);
|
||||||
|
while (e != null && e.hasMoreElements()) {
|
||||||
|
URL url = (URL)e.nextElement();
|
||||||
|
if (url != null)
|
||||||
|
v.add(url);
|
||||||
|
}
|
||||||
|
if (v.size() > 0) {
|
||||||
|
ret = new URL[v.size()];
|
||||||
|
ret = (URL[])v.toArray(ret);
|
||||||
|
}
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
} catch (SecurityException ex) { }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static URL[] getSystemResources(final String name) {
|
||||||
|
return (URL[])
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
URL[] ret = null;
|
||||||
|
try {
|
||||||
|
List v = new ArrayList();
|
||||||
|
Enumeration e = ClassLoader.getSystemResources(name);
|
||||||
|
while (e != null && e.hasMoreElements()) {
|
||||||
|
URL url = (URL)e.nextElement();
|
||||||
|
if (url != null)
|
||||||
|
v.add(url);
|
||||||
|
}
|
||||||
|
if (v.size() > 0) {
|
||||||
|
ret = new URL[v.size()];
|
||||||
|
ret = (URL[])v.toArray(ret);
|
||||||
|
}
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
} catch (SecurityException ex) { }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream openStream(final URL url) throws IOException {
|
||||||
|
try {
|
||||||
|
return (InputStream)
|
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws IOException {
|
||||||
|
return url.openStream();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (PrivilegedActionException e) {
|
||||||
|
throw (IOException)e.getException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URLDataSource class provides an object that wraps a <code>URL</code>
|
||||||
|
* object in a DataSource interface. URLDataSource simplifies the handling
|
||||||
|
* of data described by URLs within Jakarta Activation
|
||||||
|
* because this class can be used to create new DataHandlers. <i>NOTE: The
|
||||||
|
* DataHandler object creates a URLDataSource internally,
|
||||||
|
* when it is constructed with a URL.</i>
|
||||||
|
*
|
||||||
|
* @see javax.activation.DataSource
|
||||||
|
* @see javax.activation.DataHandler
|
||||||
|
*/
|
||||||
|
public class URLDataSource implements DataSource {
|
||||||
|
private URL url = null;
|
||||||
|
private URLConnection url_conn = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URLDataSource constructor. The URLDataSource class will
|
||||||
|
* not open a connection to the URL until a method requiring it
|
||||||
|
* to do so is called.
|
||||||
|
*
|
||||||
|
* @param url The URL to be encapsulated in this object.
|
||||||
|
*/
|
||||||
|
public URLDataSource(URL url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the URL content-type header field.
|
||||||
|
* It calls the URL's <code>URLConnection.getContentType</code> method
|
||||||
|
* after retrieving a URLConnection object.
|
||||||
|
* <i>Note: this method attempts to call the <code>openConnection</code>
|
||||||
|
* method on the URL. If this method fails, or if a content type is not
|
||||||
|
* returned from the URLConnection, getContentType returns
|
||||||
|
* "application/octet-stream" as the content type.</i>
|
||||||
|
*
|
||||||
|
* @return the content type.
|
||||||
|
*/
|
||||||
|
public String getContentType() {
|
||||||
|
String type = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (url_conn == null)
|
||||||
|
url_conn = url.openConnection();
|
||||||
|
} catch (IOException e) { }
|
||||||
|
|
||||||
|
if (url_conn != null)
|
||||||
|
type = url_conn.getContentType();
|
||||||
|
|
||||||
|
if (type == null)
|
||||||
|
type = "application/octet-stream";
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the <code>getFile</code> method on the URL used to
|
||||||
|
* instantiate the object.
|
||||||
|
*
|
||||||
|
* @return the result of calling the URL's getFile method.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return url.getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getInputStream method from the URL. Calls the
|
||||||
|
* <code>openStream</code> method on the URL.
|
||||||
|
*
|
||||||
|
* @return the InputStream.
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return url.openStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getOutputStream method from the URL. First an attempt is
|
||||||
|
* made to get the URLConnection object for the URL. If that
|
||||||
|
* succeeds, the getOutputStream method on the URLConnection
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* @return the OutputStream.
|
||||||
|
*/
|
||||||
|
public OutputStream getOutputStream() throws IOException {
|
||||||
|
// get the url connection if it is available
|
||||||
|
url_conn = url.openConnection();
|
||||||
|
|
||||||
|
if (url_conn != null) {
|
||||||
|
url_conn.setDoOutput(true);
|
||||||
|
return url_conn.getOutputStream();
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL used to create this DataSource.
|
||||||
|
*
|
||||||
|
* @return The URL.
|
||||||
|
*/
|
||||||
|
public URL getURL() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package javax.activation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that the requested operation does not support the
|
||||||
|
* requested data type.
|
||||||
|
*
|
||||||
|
* @see javax.activation.DataHandler
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class UnsupportedDataTypeException extends IOException {
|
||||||
|
/**
|
||||||
|
* Constructs an UnsupportedDataTypeException with no detail
|
||||||
|
* message.
|
||||||
|
*/
|
||||||
|
public UnsupportedDataTypeException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an UnsupportedDataTypeException with the specified
|
||||||
|
* message.
|
||||||
|
*
|
||||||
|
* @param s The detail message.
|
||||||
|
*/
|
||||||
|
public UnsupportedDataTypeException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright (c) 1997, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
|
This program and the accompanying materials are made available under the
|
||||||
|
terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||||
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<TITLE>javax.activation package</TITLE>
|
||||||
|
</HEAD>
|
||||||
|
<BODY BGCOLOR="white">
|
||||||
|
|
||||||
|
<P>
|
||||||
|
Jakarta Activation is used by Jakarta Mail to manage MIME data.
|
||||||
|
</P>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# This is a very simple 'mailcap' file
|
||||||
|
#
|
||||||
|
# No default viewers are included so these entries are commented out.
|
||||||
|
#
|
||||||
|
#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
|
@ -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
|
Loading…
Reference in new issue