Java tutorial
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * https://oss.oracle.com/licenses/CDDL+GPL-1.1 * or LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package javax.activation; import java.util.*; import java.io.*; import java.net.*; import java.security.AccessController; import java.security.PrivilegedAction; import com.sun.activation.registries.MailcapFile; import com.sun.activation.registries.LogSupport; /** * MailcapCommandMap extends the CommandMap * abstract class. It implements a CommandMap whose configuration * is based on mailcap files * (<A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>). * The MailcapCommandMap can be configured both programmatically * and via configuration files. * <p> * <b>Mailcap file search order:</b><p> * The MailcapCommandMap looks in various places in the user's * system for mailcap file entries. When requests are made * to search for commands in the MailcapCommandMap, it searches * mailcap files in the following order: * <ol> * <li> Programatically added entries to the MailcapCommandMap instance. * <li> The file <code>.mailcap</code> in the user's home directory. * <li> The file <code>mailcap</code> in the Java runtime. * <li> The file or resources named <code>META-INF/mailcap</code>. * <li> The file or resource named <code>META-INF/mailcap.default</code> * (usually found only in the <code>activation.jar</code> file). * </ol> * <p> * (The current implementation looks for the <code>mailcap</code> file * in the Java runtime in the directory <code><i>java.home</i>/conf</code> * if it exists, and otherwise in the directory * <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value * of the "java.home" System property. Note that the "conf" directory was * introduced in JDK 9.) * <p> * <b>Mailcap file format:</b><p> * * Mailcap files must conform to the mailcap * file specification (RFC 1524, <i>A User Agent Configuration Mechanism * For Multimedia Mail Format Information</i>). * The file format consists of entries corresponding to * particular MIME types. In general, the specification * specifies <i>applications</i> for clients to use when they * themselves cannot operate on the specified MIME type. The * MailcapCommandMap extends this specification by using a parameter mechanism * in mailcap files that allows JavaBeans(tm) components to be specified as * corresponding to particular commands for a MIME type.<p> * * When a mailcap file is * parsed, the MailcapCommandMap recognizes certain parameter signatures, * specifically those parameter names that begin with <code>x-java-</code>. * The MailcapCommandMap uses this signature to find * command entries for inclusion into its registries. * Parameter names with the form <code>x-java-<name></code> * are read by the MailcapCommandMap as identifying a command * with the name <i>name</i>. When the <i>name</i> is <code> * content-handler</code> the MailcapCommandMap recognizes the class * signified by this parameter as a <i>DataContentHandler</i>. * All other commands are handled generically regardless of command * name. The command implementation is specified by a fully qualified * class name of a JavaBean(tm) component. For example; a command for viewing * some data can be specified as: <code>x-java-view=com.foo.ViewBean</code>.<p> * * When the command name is <code>fallback-entry</code>, the value of * the command may be <code>true</code> or <code>false</code>. An * entry for a MIME type that includes a parameter of * <code>x-java-fallback-entry=true</code> defines fallback commands * for that MIME type that will only be used if no non-fallback entry * can be found. For example, an entry of the form <code>text/*; ; * x-java-fallback-entry=true; x-java-view=com.sun.TextViewer</code> * specifies a view command to be used for any text MIME type. This * view command would only be used if a non-fallback view command for * the MIME type could not be found.<p> * * MailcapCommandMap aware mailcap files have the * following general form:<p> * <code> * # Comments begin with a '#' and continue to the end of the line.<br> * <mime type>; ; <parameter list><br> * # Where a parameter list consists of one or more parameters,<br> * # where parameters look like: x-java-view=com.sun.TextViewer<br> * # and a parameter list looks like: <br> * text/plain; ; x-java-view=com.sun.TextViewer; x-java-edit=com.sun.TextEdit * <br> * # Note that mailcap entries that do not contain 'x-java' parameters<br> * # and comply to RFC 1524 are simply ignored:<br> * image/gif; /usr/dt/bin/sdtimage %s<br> * * </code> * <p> * * @author Bart Calder * @author Bill Shannon */ public class MailcapCommandMap extends CommandMap { /* * We manage a collection of databases, searched in order. */ private MailcapFile[] DB; private static final int PROG = 0; // programmatically added entries private static final String confDir; static { String dir = null; try { dir = (String) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { String home = System.getProperty("java.home"); String newdir = home + File.separator + "conf"; File conf = new File(newdir); if (conf.exists()) return newdir + File.separator; else return home + File.separator + "lib" + File.separator; } }); } catch (Exception ex) { // ignore any exceptions } confDir = dir; } /** * The default Constructor. */ public MailcapCommandMap() { super(); List dbv = new ArrayList(5); // usually 5 or less databases MailcapFile mf = null; dbv.add(null); // place holder for PROG entry LogSupport.log("MailcapCommandMap: load HOME"); try { String user_home = System.getProperty("user.home"); if (user_home != null) { String path = user_home + File.separator + ".mailcap"; mf = loadFile(path); if (mf != null) dbv.add(mf); } } catch (SecurityException ex) { } LogSupport.log("MailcapCommandMap: load SYS"); try { // check system's home if (confDir != null) { mf = loadFile(confDir + "mailcap"); if (mf != null) dbv.add(mf); } } catch (SecurityException ex) { } LogSupport.log("MailcapCommandMap: load JAR"); // load from the app's jar file loadAllResources(dbv, "META-INF/mailcap"); LogSupport.log("MailcapCommandMap: load DEF"); mf = loadResource("/META-INF/mailcap.default"); if (mf != null) dbv.add(mf); DB = new MailcapFile[dbv.size()]; DB = (MailcapFile[]) dbv.toArray(DB); } /** * Load from the named resource. */ private MailcapFile loadResource(String name) { InputStream clis = null; try { clis = SecuritySupport.getResourceAsStream(this.getClass(), name); if (clis != null) { MailcapFile mf = new MailcapFile(clis); if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: successfully loaded " + "mailcap file: " + name); return mf; } else { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: not loading " + "mailcap file: " + name); } } catch (IOException e) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: can't load " + name, e); } catch (SecurityException sex) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: can't load " + name, sex); } finally { try { if (clis != null) clis.close(); } catch (IOException ex) { } // ignore it } return null; } /** * Load all of the named resource. */ private void loadAllResources(List v, String name) { boolean anyLoaded = false; try { URL[] urls; ClassLoader cld = null; // First try the "application's" class loader. cld = SecuritySupport.getContextClassLoader(); if (cld == null) cld = this.getClass().getClassLoader(); if (cld != null) urls = SecuritySupport.getResources(cld, name); else urls = SecuritySupport.getSystemResources(name); if (urls != null) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: getResources"); for (int i = 0; i < urls.length; i++) { URL url = urls[i]; InputStream clis = null; if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: URL " + url); try { clis = SecuritySupport.openStream(url); if (clis != null) { v.add(new MailcapFile(clis)); anyLoaded = true; if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: " + "successfully loaded " + "mailcap file from URL: " + url); } else { if (LogSupport.isLoggable()) LogSupport.log( "MailcapCommandMap: " + "not loading mailcap " + "file from URL: " + url); } } catch (IOException ioex) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: can't load " + url, ioex); } catch (SecurityException sex) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: can't load " + url, sex); } finally { try { if (clis != null) clis.close(); } catch (IOException cex) { } } } } } catch (Exception ex) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: can't load " + name, ex); } // if failed to load anything, fall back to old technique, just in case if (!anyLoaded) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: !anyLoaded"); MailcapFile mf = loadResource("/" + name); if (mf != null) v.add(mf); } } /** * Load from the named file. */ private MailcapFile loadFile(String name) { MailcapFile mtf = null; try { mtf = new MailcapFile(name); } catch (IOException e) { // e.printStackTrace(); } return mtf; } /** * Constructor that allows the caller to specify the path * of a <i>mailcap</i> file. * * @param fileName The name of the <i>mailcap</i> file to open * @exception IOException if the file can't be accessed */ public MailcapCommandMap(String fileName) throws IOException { this(); if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: load PROG from " + fileName); if (DB[PROG] == null) { DB[PROG] = new MailcapFile(fileName); } } /** * Constructor that allows the caller to specify an <i>InputStream</i> * containing a mailcap file. * * @param is InputStream of the <i>mailcap</i> file to open */ public MailcapCommandMap(InputStream is) { this(); LogSupport.log("MailcapCommandMap: load PROG"); if (DB[PROG] == null) { try { DB[PROG] = new MailcapFile(is); } catch (IOException ex) { // XXX - should throw it } } } /** * Get the preferred command list for a MIME Type. The MailcapCommandMap * searches the mailcap files as described above under * <i>Mailcap file search order</i>.<p> * * The result of the search is a proper subset of available * commands in all mailcap files known to this instance of * MailcapCommandMap. The first entry for a particular command * is considered the preferred command. * * @param mimeType the MIME type * @return the CommandInfo objects representing the preferred commands. */ public synchronized CommandInfo[] getPreferredCommands(String mimeType) { List cmdList = new ArrayList(); if (mimeType != null) mimeType = mimeType.toLowerCase(Locale.ENGLISH); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapList(mimeType); if (cmdMap != null) appendPrefCmdsToList(cmdMap, cmdList); } // now add the fallback commands for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapFallbackList(mimeType); if (cmdMap != null) appendPrefCmdsToList(cmdMap, cmdList); } CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()]; cmdInfos = (CommandInfo[]) cmdList.toArray(cmdInfos); return cmdInfos; } /** * Put the commands that are in the hash table, into the list. */ private void appendPrefCmdsToList(Map cmdHash, List cmdList) { Iterator verb_enum = cmdHash.keySet().iterator(); while (verb_enum.hasNext()) { String verb = (String) verb_enum.next(); if (!checkForVerb(cmdList, verb)) { List cmdList2 = (List) cmdHash.get(verb); // get the list String className = (String) cmdList2.get(0); cmdList.add(new CommandInfo(verb, className)); } } } /** * Check the cmdList to see if this command exists, return * true if the verb is there. */ private boolean checkForVerb(List cmdList, String verb) { Iterator ee = cmdList.iterator(); while (ee.hasNext()) { String enum_verb = (String) ((CommandInfo) ee.next()).getCommandName(); if (enum_verb.equals(verb)) return true; } return false; } /** * Get all the available commands in all mailcap files known to * this instance of MailcapCommandMap for this MIME type. * * @param mimeType the MIME type * @return the CommandInfo objects representing all the commands. */ public synchronized CommandInfo[] getAllCommands(String mimeType) { List cmdList = new ArrayList(); if (mimeType != null) mimeType = mimeType.toLowerCase(Locale.ENGLISH); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapList(mimeType); if (cmdMap != null) appendCmdsToList(cmdMap, cmdList); } // now add the fallback commands for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapFallbackList(mimeType); if (cmdMap != null) appendCmdsToList(cmdMap, cmdList); } CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()]; cmdInfos = (CommandInfo[]) cmdList.toArray(cmdInfos); return cmdInfos; } /** * Put the commands that are in the hash table, into the list. */ private void appendCmdsToList(Map typeHash, List cmdList) { Iterator verb_enum = typeHash.keySet().iterator(); while (verb_enum.hasNext()) { String verb = (String) verb_enum.next(); List cmdList2 = (List) typeHash.get(verb); Iterator cmd_enum = ((List) cmdList2).iterator(); while (cmd_enum.hasNext()) { String cmd = (String) cmd_enum.next(); cmdList.add(new CommandInfo(verb, cmd)); // cmdList.add(0, new CommandInfo(verb, cmd)); } } } /** * Get the command corresponding to <code>cmdName</code> for the MIME type. * * @param mimeType the MIME type * @param cmdName the command name * @return the CommandInfo object corresponding to the command. */ public synchronized CommandInfo getCommand(String mimeType, String cmdName) { if (mimeType != null) mimeType = mimeType.toLowerCase(Locale.ENGLISH); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapList(mimeType); if (cmdMap != null) { // get the cmd list for the cmd List v = (List) cmdMap.get(cmdName); if (v != null) { String cmdClassName = (String) v.get(0); if (cmdClassName != null) return new CommandInfo(cmdName, cmdClassName); } } } // now try the fallback list for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; Map cmdMap = DB[i].getMailcapFallbackList(mimeType); if (cmdMap != null) { // get the cmd list for the cmd List v = (List) cmdMap.get(cmdName); if (v != null) { String cmdClassName = (String) v.get(0); if (cmdClassName != null) return new CommandInfo(cmdName, cmdClassName); } } } return null; } /** * Add entries to the registry. Programmatically * added entries are searched before other entries.<p> * * The string that is passed in should be in mailcap * format. * * @param mail_cap a correctly formatted mailcap string */ public synchronized void addMailcap(String mail_cap) { // check to see if one exists LogSupport.log("MailcapCommandMap: add to PROG"); if (DB[PROG] == null) DB[PROG] = new MailcapFile(); DB[PROG].appendToMailcap(mail_cap); } /** * Return the DataContentHandler for the specified MIME type. * * @param mimeType the MIME type * @return the DataContentHandler */ public synchronized DataContentHandler createDataContentHandler(String mimeType) { if (LogSupport.isLoggable()) LogSupport.log("MailcapCommandMap: createDataContentHandler for " + mimeType); if (mimeType != null) mimeType = mimeType.toLowerCase(Locale.ENGLISH); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; if (LogSupport.isLoggable()) LogSupport.log(" search DB #" + i); Map cmdMap = DB[i].getMailcapList(mimeType); if (cmdMap != null) { List v = (List) cmdMap.get("content-handler"); if (v != null) { String name = (String) v.get(0); DataContentHandler dch = getDataContentHandler(name); if (dch != null) return dch; } } } // now try the fallback entries for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; if (LogSupport.isLoggable()) LogSupport.log(" search fallback DB #" + i); Map cmdMap = DB[i].getMailcapFallbackList(mimeType); if (cmdMap != null) { List v = (List) cmdMap.get("content-handler"); if (v != null) { String name = (String) v.get(0); DataContentHandler dch = getDataContentHandler(name); if (dch != null) return dch; } } } return null; } private DataContentHandler getDataContentHandler(String name) { if (LogSupport.isLoggable()) LogSupport.log(" got content-handler"); if (LogSupport.isLoggable()) LogSupport.log(" class " + name); try { ClassLoader cld = null; // First try the "application's" class loader. cld = SecuritySupport.getContextClassLoader(); if (cld == null) cld = this.getClass().getClassLoader(); Class cl = null; try { cl = cld.loadClass(name); } catch (Exception ex) { // if anything goes wrong, do it the old way cl = Class.forName(name); } if (cl != null) // XXX - always true? return (DataContentHandler) cl.newInstance(); } catch (IllegalAccessException e) { if (LogSupport.isLoggable()) LogSupport.log("Can't load DCH " + name, e); } catch (ClassNotFoundException e) { if (LogSupport.isLoggable()) LogSupport.log("Can't load DCH " + name, e); } catch (InstantiationException e) { if (LogSupport.isLoggable()) LogSupport.log("Can't load DCH " + name, e); } return null; } /** * Get all the MIME types known to this command map. * * @return array of MIME types as strings * @since JAF 1.1 */ public synchronized String[] getMimeTypes() { List mtList = new ArrayList(); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; String[] ts = DB[i].getMimeTypes(); if (ts != null) { for (int j = 0; j < ts.length; j++) { // eliminate duplicates if (!mtList.contains(ts[j])) mtList.add(ts[j]); } } } String[] mts = new String[mtList.size()]; mts = (String[]) mtList.toArray(mts); return mts; } /** * Get the native commands for the given MIME type. * Returns an array of strings where each string is * an entire mailcap file entry. The application * will need to parse the entry to extract the actual * command as well as any attributes it needs. See * <A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A> * for details of the mailcap entry syntax. Only mailcap * entries that specify a view command for the specified * MIME type are returned. * * @param mimeType the MIME type * @return array of native command entries * @since JAF 1.1 */ public synchronized String[] getNativeCommands(String mimeType) { List cmdList = new ArrayList(); if (mimeType != null) mimeType = mimeType.toLowerCase(Locale.ENGLISH); for (int i = 0; i < DB.length; i++) { if (DB[i] == null) continue; String[] cmds = DB[i].getNativeCommands(mimeType); if (cmds != null) { for (int j = 0; j < cmds.length; j++) { // eliminate duplicates if (!cmdList.contains(cmds[j])) cmdList.add(cmds[j]); } } } String[] cmds = new String[cmdList.size()]; cmds = (String[]) cmdList.toArray(cmds); return cmds; } /** * for debugging... * public static void main(String[] argv) throws Exception { MailcapCommandMap map = new MailcapCommandMap(); CommandInfo[] cmdInfo; cmdInfo = map.getPreferredCommands(argv[0]); System.out.println("Preferred Commands:"); for (int i = 0; i < cmdInfo.length; i++) System.out.println("Command " + cmdInfo[i].getCommandName() + " [" + cmdInfo[i].getCommandClass() + "]"); cmdInfo = map.getAllCommands(argv[0]); System.out.println(); System.out.println("All Commands:"); for (int i = 0; i < cmdInfo.length; i++) System.out.println("Command " + cmdInfo[i].getCommandName() + " [" + cmdInfo[i].getCommandClass() + "]"); DataContentHandler dch = map.createDataContentHandler(argv[0]); if (dch != null) System.out.println("DataContentHandler " + dch.getClass().toString()); System.exit(0); } */ }