rt/emul/compact/src/main/java/java/net/URLConnection.java
changeset 1398 9926996eca2d
parent 1396 1c64f76edaa7
     1.1 --- a/rt/emul/compact/src/main/java/java/net/URLConnection.java	Thu Oct 31 10:50:19 2013 +0100
     1.2 +++ b/rt/emul/compact/src/main/java/java/net/URLConnection.java	Thu Oct 31 11:23:54 2013 +0100
     1.3 @@ -28,16 +28,17 @@
     1.4  import java.io.IOException;
     1.5  import java.io.InputStream;
     1.6  import java.io.OutputStream;
     1.7 -import java.util.Hashtable;
     1.8 +import java.io.PrintStream;
     1.9 +import java.util.ArrayList;
    1.10  import java.util.Date;
    1.11  import java.util.StringTokenizer;
    1.12  import java.util.Collections;
    1.13 +import java.util.HashMap;
    1.14 +import java.util.Hashtable;
    1.15 +import java.util.Iterator;
    1.16  import java.util.Map;
    1.17  import java.util.List;
    1.18 -import java.security.Permission;
    1.19 -import java.security.AccessController;
    1.20 -import sun.security.util.SecurityConstants;
    1.21 -import sun.net.www.MessageHeader;
    1.22 +import java.util.NoSuchElementException;
    1.23  
    1.24  /**
    1.25   * The abstract class <code>URLConnection</code> is the superclass
    1.26 @@ -314,7 +315,12 @@
    1.27       */
    1.28      public static synchronized FileNameMap getFileNameMap() {
    1.29          if ((fileNameMap == null) && !fileNameMapLoaded) {
    1.30 -            fileNameMap = sun.net.www.MimeTable.loadTable();
    1.31 +            fileNameMap = new FileNameMap() {
    1.32 +                @Override
    1.33 +                public String getContentTypeFor(String fileName) {
    1.34 +                    return "text/plain";
    1.35 +                }
    1.36 +            };
    1.37              fileNameMapLoaded = true;
    1.38          }
    1.39  
    1.40 @@ -342,9 +348,7 @@
    1.41       * @since 1.2
    1.42       */
    1.43      public static void setFileNameMap(FileNameMap map) {
    1.44 -        SecurityManager sm = System.getSecurityManager();
    1.45 -        if (sm != null) sm.checkSetFactory();
    1.46 -        fileNameMap = map;
    1.47 +        throw new SecurityException();
    1.48      }
    1.49  
    1.50      /**
    1.51 @@ -816,9 +820,9 @@
    1.52       * requires network or file I/O and an exception occurs while
    1.53       * computing it.
    1.54       */
    1.55 -    public Permission getPermission() throws IOException {
    1.56 -        return SecurityConstants.ALL_PERMISSION;
    1.57 -    }
    1.58 +//    public Permission getPermission() throws IOException {
    1.59 +//        return SecurityConstants.ALL_PERMISSION;
    1.60 +//    }
    1.61  
    1.62      /**
    1.63       * Returns an input stream that reads from this open connection.
    1.64 @@ -1226,14 +1230,7 @@
    1.65       * @see        SecurityManager#checkSetFactory
    1.66       */
    1.67      public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
    1.68 -        if (factory != null) {
    1.69 -            throw new Error("factory already defined");
    1.70 -        }
    1.71 -        SecurityManager security = System.getSecurityManager();
    1.72 -        if (security != null) {
    1.73 -            security.checkSetFactory();
    1.74 -        }
    1.75 -        factory = fac;
    1.76 +        throw new SecurityException();
    1.77      }
    1.78  
    1.79      private static Hashtable handlers = new Hashtable();
    1.80 @@ -1370,9 +1367,8 @@
    1.81       * the last one on the returned package list.
    1.82       */
    1.83      private String getContentHandlerPkgPrefixes() {
    1.84 -        String packagePrefixList = AccessController.doPrivileged(
    1.85 -            new sun.security.action.GetPropertyAction(contentPathProp, ""));
    1.86 -
    1.87 +        String packagePrefixList = "";
    1.88 +        
    1.89          if (packagePrefixList != "") {
    1.90              packagePrefixList += "|";
    1.91          }
    1.92 @@ -1795,3 +1791,524 @@
    1.93          return uc.getInputStream();
    1.94      }
    1.95  }
    1.96 +
    1.97 +/** An RFC 844 or MIME message header.  Includes methods
    1.98 +    for parsing headers from incoming streams, fetching
    1.99 +    values, setting values, and printing headers.
   1.100 +    Key values of null are legal: they indicate lines in
   1.101 +    the header that don't have a valid key, but do have
   1.102 +    a value (this isn't legal according to the standard,
   1.103 +    but lines like this are everywhere). */
   1.104 +class MessageHeader {
   1.105 +    private String keys[];
   1.106 +    private String values[];
   1.107 +    private int nkeys;
   1.108 +
   1.109 +    public MessageHeader () {
   1.110 +        grow();
   1.111 +    }
   1.112 +
   1.113 +    public MessageHeader (InputStream is) throws java.io.IOException {
   1.114 +        parseHeader(is);
   1.115 +    }
   1.116 +
   1.117 +    /**
   1.118 +     * Reset a message header (all key/values removed)
   1.119 +     */
   1.120 +    public synchronized void reset() {
   1.121 +        keys = null;
   1.122 +        values = null;
   1.123 +        nkeys = 0;
   1.124 +        grow();
   1.125 +    }
   1.126 +
   1.127 +    /**
   1.128 +     * Find the value that corresponds to this key.
   1.129 +     * It finds only the first occurrence of the key.
   1.130 +     * @param k the key to find.
   1.131 +     * @return null if not found.
   1.132 +     */
   1.133 +    public synchronized String findValue(String k) {
   1.134 +        if (k == null) {
   1.135 +            for (int i = nkeys; --i >= 0;)
   1.136 +                if (keys[i] == null)
   1.137 +                    return values[i];
   1.138 +        } else
   1.139 +            for (int i = nkeys; --i >= 0;) {
   1.140 +                if (k.equalsIgnoreCase(keys[i]))
   1.141 +                    return values[i];
   1.142 +            }
   1.143 +        return null;
   1.144 +    }
   1.145 +
   1.146 +    // return the location of the key
   1.147 +    public synchronized int getKey(String k) {
   1.148 +        for (int i = nkeys; --i >= 0;)
   1.149 +            if ((keys[i] == k) ||
   1.150 +                (k != null && k.equalsIgnoreCase(keys[i])))
   1.151 +                return i;
   1.152 +        return -1;
   1.153 +    }
   1.154 +
   1.155 +    public synchronized String getKey(int n) {
   1.156 +        if (n < 0 || n >= nkeys) return null;
   1.157 +        return keys[n];
   1.158 +    }
   1.159 +
   1.160 +    public synchronized String getValue(int n) {
   1.161 +        if (n < 0 || n >= nkeys) return null;
   1.162 +        return values[n];
   1.163 +    }
   1.164 +
   1.165 +    /** Deprecated: Use multiValueIterator() instead.
   1.166 +     *
   1.167 +     *  Find the next value that corresponds to this key.
   1.168 +     *  It finds the first value that follows v. To iterate
   1.169 +     *  over all the values of a key use:
   1.170 +     *  <pre>
   1.171 +     *          for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
   1.172 +     *              ...
   1.173 +     *          }
   1.174 +     *  </pre>
   1.175 +     */
   1.176 +    public synchronized String findNextValue(String k, String v) {
   1.177 +        boolean foundV = false;
   1.178 +        if (k == null) {
   1.179 +            for (int i = nkeys; --i >= 0;)
   1.180 +                if (keys[i] == null)
   1.181 +                    if (foundV)
   1.182 +                        return values[i];
   1.183 +                    else if (values[i] == v)
   1.184 +                        foundV = true;
   1.185 +        } else
   1.186 +            for (int i = nkeys; --i >= 0;)
   1.187 +                if (k.equalsIgnoreCase(keys[i]))
   1.188 +                    if (foundV)
   1.189 +                        return values[i];
   1.190 +                    else if (values[i] == v)
   1.191 +                        foundV = true;
   1.192 +        return null;
   1.193 +    }
   1.194 +
   1.195 +    class HeaderIterator implements Iterator<String> {
   1.196 +        int index = 0;
   1.197 +        int next = -1;
   1.198 +        String key;
   1.199 +        boolean haveNext = false;
   1.200 +        Object lock;
   1.201 +
   1.202 +        public HeaderIterator (String k, Object lock) {
   1.203 +            key = k;
   1.204 +            this.lock = lock;
   1.205 +        }
   1.206 +        public boolean hasNext () {
   1.207 +            synchronized (lock) {
   1.208 +                if (haveNext) {
   1.209 +                    return true;
   1.210 +                }
   1.211 +                while (index < nkeys) {
   1.212 +                    if (key.equalsIgnoreCase (keys[index])) {
   1.213 +                        haveNext = true;
   1.214 +                        next = index++;
   1.215 +                        return true;
   1.216 +                    }
   1.217 +                    index ++;
   1.218 +                }
   1.219 +                return false;
   1.220 +            }
   1.221 +        }
   1.222 +        public String next() {
   1.223 +            synchronized (lock) {
   1.224 +                if (haveNext) {
   1.225 +                    haveNext = false;
   1.226 +                    return values [next];
   1.227 +                }
   1.228 +                if (hasNext()) {
   1.229 +                    return next();
   1.230 +                } else {
   1.231 +                    throw new NoSuchElementException ("No more elements");
   1.232 +                }
   1.233 +            }
   1.234 +        }
   1.235 +        public void remove () {
   1.236 +            throw new UnsupportedOperationException ("remove not allowed");
   1.237 +        }
   1.238 +    }
   1.239 +
   1.240 +    /**
   1.241 +     * return an Iterator that returns all values of a particular
   1.242 +     * key in sequence
   1.243 +     */
   1.244 +    public Iterator<String> multiValueIterator (String k) {
   1.245 +        return new HeaderIterator (k, this);
   1.246 +    }
   1.247 +
   1.248 +    public synchronized Map<String, List<String>> getHeaders() {
   1.249 +        return getHeaders(null);
   1.250 +    }
   1.251 +
   1.252 +    public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
   1.253 +        return filterAndAddHeaders(excludeList, null);
   1.254 +    }
   1.255 +
   1.256 +    public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>>  include) {
   1.257 +        boolean skipIt = false;
   1.258 +        Map<String, List<String>> m = new HashMap<String, List<String>>();
   1.259 +        for (int i = nkeys; --i >= 0;) {
   1.260 +            if (excludeList != null) {
   1.261 +                // check if the key is in the excludeList.
   1.262 +                // if so, don't include it in the Map.
   1.263 +                for (int j = 0; j < excludeList.length; j++) {
   1.264 +                    if ((excludeList[j] != null) &&
   1.265 +                        (excludeList[j].equalsIgnoreCase(keys[i]))) {
   1.266 +                        skipIt = true;
   1.267 +                        break;
   1.268 +                    }
   1.269 +                }
   1.270 +            }
   1.271 +            if (!skipIt) {
   1.272 +                List<String> l = m.get(keys[i]);
   1.273 +                if (l == null) {
   1.274 +                    l = new ArrayList<String>();
   1.275 +                    m.put(keys[i], l);
   1.276 +                }
   1.277 +                l.add(values[i]);
   1.278 +            } else {
   1.279 +                // reset the flag
   1.280 +                skipIt = false;
   1.281 +            }
   1.282 +        }
   1.283 +
   1.284 +        if (include != null) {
   1.285 +            Iterator entries = include.entrySet().iterator();
   1.286 +            while (entries.hasNext()) {
   1.287 +                Map.Entry entry = (Map.Entry)entries.next();
   1.288 +                List l = (List)m.get(entry.getKey());
   1.289 +                if (l == null) {
   1.290 +                    l = new ArrayList();
   1.291 +                    m.put((String)entry.getKey(), l);
   1.292 +                }
   1.293 +                l.add(entry.getValue());
   1.294 +            }
   1.295 +        }
   1.296 +
   1.297 +        for (String key : m.keySet()) {
   1.298 +            m.put(key, Collections.unmodifiableList(m.get(key)));
   1.299 +        }
   1.300 +
   1.301 +        return Collections.unmodifiableMap(m);
   1.302 +    }
   1.303 +
   1.304 +    /** Prints the key-value pairs represented by this
   1.305 +        header.  Also prints the RFC required blank line
   1.306 +        at the end. Omits pairs with a null key. */
   1.307 +    public synchronized void print(PrintStream p) {
   1.308 +        for (int i = 0; i < nkeys; i++)
   1.309 +            if (keys[i] != null) {
   1.310 +                p.print(keys[i] +
   1.311 +                    (values[i] != null ? ": "+values[i]: "") + "\r\n");
   1.312 +            }
   1.313 +        p.print("\r\n");
   1.314 +        p.flush();
   1.315 +    }
   1.316 +
   1.317 +    /** Adds a key value pair to the end of the
   1.318 +        header.  Duplicates are allowed */
   1.319 +    public synchronized void add(String k, String v) {
   1.320 +        grow();
   1.321 +        keys[nkeys] = k;
   1.322 +        values[nkeys] = v;
   1.323 +        nkeys++;
   1.324 +    }
   1.325 +
   1.326 +    /** Prepends a key value pair to the beginning of the
   1.327 +        header.  Duplicates are allowed */
   1.328 +    public synchronized void prepend(String k, String v) {
   1.329 +        grow();
   1.330 +        for (int i = nkeys; i > 0; i--) {
   1.331 +            keys[i] = keys[i-1];
   1.332 +            values[i] = values[i-1];
   1.333 +        }
   1.334 +        keys[0] = k;
   1.335 +        values[0] = v;
   1.336 +        nkeys++;
   1.337 +    }
   1.338 +
   1.339 +    /** Overwrite the previous key/val pair at location 'i'
   1.340 +     * with the new k/v.  If the index didn't exist before
   1.341 +     * the key/val is simply tacked onto the end.
   1.342 +     */
   1.343 +
   1.344 +    public synchronized void set(int i, String k, String v) {
   1.345 +        grow();
   1.346 +        if (i < 0) {
   1.347 +            return;
   1.348 +        } else if (i >= nkeys) {
   1.349 +            add(k, v);
   1.350 +        } else {
   1.351 +            keys[i] = k;
   1.352 +            values[i] = v;
   1.353 +        }
   1.354 +    }
   1.355 +
   1.356 +
   1.357 +    /** grow the key/value arrays as needed */
   1.358 +
   1.359 +    private void grow() {
   1.360 +        if (keys == null || nkeys >= keys.length) {
   1.361 +            String[] nk = new String[nkeys + 4];
   1.362 +            String[] nv = new String[nkeys + 4];
   1.363 +            if (keys != null)
   1.364 +                System.arraycopy(keys, 0, nk, 0, nkeys);
   1.365 +            if (values != null)
   1.366 +                System.arraycopy(values, 0, nv, 0, nkeys);
   1.367 +            keys = nk;
   1.368 +            values = nv;
   1.369 +        }
   1.370 +    }
   1.371 +
   1.372 +    /**
   1.373 +     * Remove the key from the header. If there are multiple values under
   1.374 +     * the same key, they are all removed.
   1.375 +     * Nothing is done if the key doesn't exist.
   1.376 +     * After a remove, the other pairs' order are not changed.
   1.377 +     * @param k the key to remove
   1.378 +     */
   1.379 +    public synchronized void remove(String k) {
   1.380 +        if(k == null) {
   1.381 +            for (int i = 0; i < nkeys; i++) {
   1.382 +                while (keys[i] == null && i < nkeys) {
   1.383 +                    for(int j=i; j<nkeys-1; j++) {
   1.384 +                        keys[j] = keys[j+1];
   1.385 +                        values[j] = values[j+1];
   1.386 +                    }
   1.387 +                    nkeys--;
   1.388 +                }
   1.389 +            }
   1.390 +        } else {
   1.391 +            for (int i = 0; i < nkeys; i++) {
   1.392 +                while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
   1.393 +                    for(int j=i; j<nkeys-1; j++) {
   1.394 +                        keys[j] = keys[j+1];
   1.395 +                        values[j] = values[j+1];
   1.396 +                    }
   1.397 +                    nkeys--;
   1.398 +                }
   1.399 +            }
   1.400 +        }
   1.401 +    }
   1.402 +
   1.403 +    /** Sets the value of a key.  If the key already
   1.404 +        exists in the header, it's value will be
   1.405 +        changed.  Otherwise a new key/value pair will
   1.406 +        be added to the end of the header. */
   1.407 +    public synchronized void set(String k, String v) {
   1.408 +        for (int i = nkeys; --i >= 0;)
   1.409 +            if (k.equalsIgnoreCase(keys[i])) {
   1.410 +                values[i] = v;
   1.411 +                return;
   1.412 +            }
   1.413 +        add(k, v);
   1.414 +    }
   1.415 +
   1.416 +    /** Set's the value of a key only if there is no
   1.417 +     *  key with that value already.
   1.418 +     */
   1.419 +
   1.420 +    public synchronized void setIfNotSet(String k, String v) {
   1.421 +        if (findValue(k) == null) {
   1.422 +            add(k, v);
   1.423 +        }
   1.424 +    }
   1.425 +
   1.426 +    /** Convert a message-id string to canonical form (strips off
   1.427 +        leading and trailing <>s) */
   1.428 +    public static String canonicalID(String id) {
   1.429 +        if (id == null)
   1.430 +            return "";
   1.431 +        int st = 0;
   1.432 +        int len = id.length();
   1.433 +        boolean substr = false;
   1.434 +        int c;
   1.435 +        while (st < len && ((c = id.charAt(st)) == '<' ||
   1.436 +                            c <= ' ')) {
   1.437 +            st++;
   1.438 +            substr = true;
   1.439 +        }
   1.440 +        while (st < len && ((c = id.charAt(len - 1)) == '>' ||
   1.441 +                            c <= ' ')) {
   1.442 +            len--;
   1.443 +            substr = true;
   1.444 +        }
   1.445 +        return substr ? id.substring(st, len) : id;
   1.446 +    }
   1.447 +
   1.448 +    /** Parse a MIME header from an input stream. */
   1.449 +    public void parseHeader(InputStream is) throws java.io.IOException {
   1.450 +        synchronized (this) {
   1.451 +            nkeys = 0;
   1.452 +        }
   1.453 +        mergeHeader(is);
   1.454 +    }
   1.455 +
   1.456 +    /** Parse and merge a MIME header from an input stream. */
   1.457 +    public void mergeHeader(InputStream is) throws java.io.IOException {
   1.458 +        if (is == null)
   1.459 +            return;
   1.460 +        char s[] = new char[10];
   1.461 +        int firstc = is.read();
   1.462 +        while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
   1.463 +            int len = 0;
   1.464 +            int keyend = -1;
   1.465 +            int c;
   1.466 +            boolean inKey = firstc > ' ';
   1.467 +            s[len++] = (char) firstc;
   1.468 +    parseloop:{
   1.469 +                while ((c = is.read()) >= 0) {
   1.470 +                    switch (c) {
   1.471 +                      case ':':
   1.472 +                        if (inKey && len > 0)
   1.473 +                            keyend = len;
   1.474 +                        inKey = false;
   1.475 +                        break;
   1.476 +                      case '\t':
   1.477 +                        c = ' ';
   1.478 +                      case ' ':
   1.479 +                        inKey = false;
   1.480 +                        break;
   1.481 +                      case '\r':
   1.482 +                      case '\n':
   1.483 +                        firstc = is.read();
   1.484 +                        if (c == '\r' && firstc == '\n') {
   1.485 +                            firstc = is.read();
   1.486 +                            if (firstc == '\r')
   1.487 +                                firstc = is.read();
   1.488 +                        }
   1.489 +                        if (firstc == '\n' || firstc == '\r' || firstc > ' ')
   1.490 +                            break parseloop;
   1.491 +                        /* continuation */
   1.492 +                        c = ' ';
   1.493 +                        break;
   1.494 +                    }
   1.495 +                    if (len >= s.length) {
   1.496 +                        char ns[] = new char[s.length * 2];
   1.497 +                        System.arraycopy(s, 0, ns, 0, len);
   1.498 +                        s = ns;
   1.499 +                    }
   1.500 +                    s[len++] = (char) c;
   1.501 +                }
   1.502 +                firstc = -1;
   1.503 +            }
   1.504 +            while (len > 0 && s[len - 1] <= ' ')
   1.505 +                len--;
   1.506 +            String k;
   1.507 +            if (keyend <= 0) {
   1.508 +                k = null;
   1.509 +                keyend = 0;
   1.510 +            } else {
   1.511 +                k = String.copyValueOf(s, 0, keyend);
   1.512 +                if (keyend < len && s[keyend] == ':')
   1.513 +                    keyend++;
   1.514 +                while (keyend < len && s[keyend] <= ' ')
   1.515 +                    keyend++;
   1.516 +            }
   1.517 +            String v;
   1.518 +            if (keyend >= len)
   1.519 +                v = new String();
   1.520 +            else
   1.521 +                v = String.copyValueOf(s, keyend, len - keyend);
   1.522 +            add(k, v);
   1.523 +        }
   1.524 +    }
   1.525 +
   1.526 +    public synchronized String toString() {
   1.527 +        String result = super.toString() + nkeys + " pairs: ";
   1.528 +        for (int i = 0; i < keys.length && i < nkeys; i++) {
   1.529 +            result += "{"+keys[i]+": "+values[i]+"}";
   1.530 +        }
   1.531 +        return result;
   1.532 +    }
   1.533 +}
   1.534 +
   1.535 +interface ContentHandlerFactory {
   1.536 +
   1.537 +    public ContentHandler createContentHandler(String contentType);
   1.538 +}
   1.539 +
   1.540 +abstract class ContentHandler {
   1.541 +    /**
   1.542 +     * Given a URL connect stream positioned at the beginning of the
   1.543 +     * representation of an object, this method reads that stream and
   1.544 +     * creates an object from it.
   1.545 +     *
   1.546 +     * @param      urlc   a URL connection.
   1.547 +     * @return     the object read by the <code>ContentHandler</code>.
   1.548 +     * @exception  IOException  if an I/O error occurs while reading the object.
   1.549 +     */
   1.550 +    abstract public Object getContent(URLConnection urlc) throws IOException;
   1.551 +
   1.552 +    /**
   1.553 +     * Given a URL connect stream positioned at the beginning of the
   1.554 +     * representation of an object, this method reads that stream and
   1.555 +     * creates an object that matches one of the types specified.
   1.556 +     *
   1.557 +     * The default implementation of this method should call getContent()
   1.558 +     * and screen the return type for a match of the suggested types.
   1.559 +     *
   1.560 +     * @param      urlc   a URL connection.
   1.561 +     * @param      classes      an array of types requested
   1.562 +     * @return     the object read by the <code>ContentHandler</code> that is
   1.563 +     *                 the first match of the suggested types.
   1.564 +     *                 null if none of the requested  are supported.
   1.565 +     * @exception  IOException  if an I/O error occurs while reading the object.
   1.566 +     * @since 1.3
   1.567 +     */
   1.568 +    public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
   1.569 +        Object obj = getContent(urlc);
   1.570 +
   1.571 +        for (int i = 0; i < classes.length; i++) {
   1.572 +          if (classes[i].isInstance(obj)) {
   1.573 +                return obj;
   1.574 +          }
   1.575 +        }
   1.576 +        return null;
   1.577 +    }
   1.578 +
   1.579 +}
   1.580 +class UnknownServiceException extends IOException {
   1.581 +    private static final long serialVersionUID = -4169033248853639508L;
   1.582 +
   1.583 +    /**
   1.584 +     * Constructs a new <code>UnknownServiceException</code> with no
   1.585 +     * detail message.
   1.586 +     */
   1.587 +    public UnknownServiceException() {
   1.588 +    }
   1.589 +
   1.590 +    /**
   1.591 +     * Constructs a new <code>UnknownServiceException</code> with the
   1.592 +     * specified detail message.
   1.593 +     *
   1.594 +     * @param   msg   the detail message.
   1.595 +     */
   1.596 +    public UnknownServiceException(String msg) {
   1.597 +        super(msg);
   1.598 +    }
   1.599 +}
   1.600 +/**
   1.601 + * A simple interface which provides a mechanism to map
   1.602 + * between a file name and a MIME type string.
   1.603 + *
   1.604 + * @author  Steven B. Byrne
   1.605 + * @since   JDK1.1
   1.606 + */
   1.607 +interface FileNameMap {
   1.608 +
   1.609 +    /**
   1.610 +     * Gets the MIME type for the specified file name.
   1.611 +     * @param fileName the specified file name
   1.612 +     * @return a <code>String</code> indicating the MIME
   1.613 +     * type for the specified file name.
   1.614 +     */
   1.615 +    public String getContentTypeFor(String fileName);
   1.616 +}