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