/**
  * Determines the {@link MediaType} for the given filename.
  *
  * <p>The default implementation will check the {@linkplain #setMediaTypes(Map) media types}
  * property first for a defined mapping. If not present, and if the Java Activation Framework can
  * be found on the classpath, it will call {@link FileTypeMap#getContentType(String)}
  *
  * <p>This method can be overridden to provide a different algorithm.
  *
  * @param filename the current request file name (i.e. {@code hotels.html})
  * @return the media type, if any
  */
 protected MediaType getMediaTypeFromFilename(String filename) {
   String extension = StringUtils.getFilenameExtension(filename);
   if (!StringUtils.hasText(extension)) {
     return null;
   }
   extension = extension.toLowerCase(Locale.ENGLISH);
   MediaType mediaType = this.mediaTypes.get(extension);
   if (mediaType == null) {
     String mimeType = getServletContext().getMimeType(filename);
     if (StringUtils.hasText(mimeType)) {
       mediaType = MediaType.parseMediaType(mimeType);
     }
     if (this.useJaf
         && (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType))) {
       MediaType jafMediaType = ActivationMediaTypeFactory.getMediaType(filename);
       if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) {
         mediaType = jafMediaType;
       }
     }
     if (mediaType != null) {
       this.mediaTypes.putIfAbsent(extension, mediaType);
     }
   }
   return mediaType;
 }
 /**
  * Extends the base class {@link PathExtensionContentNegotiationStrategy#getMediaTypeForResource}
  * with the ability to also look up through the ServletContext.
  *
  * @param resource the resource to look up
  * @return the MediaType for the extension or {@code null}.
  * @since 4.3
  */
 public MediaType getMediaTypeForResource(Resource resource) {
   MediaType mediaType = super.getMediaTypeForResource(resource);
   if (mediaType == null) {
     String mimeType = this.servletContext.getMimeType(resource.getFilename());
     if (StringUtils.hasText(mimeType)) {
       mediaType = MediaType.parseMediaType(mimeType);
     }
   }
   if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
     mediaType = null;
   }
   return mediaType;
 }
  @Override
  protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)
      throws HttpMediaTypeNotAcceptableException {

    if (this.useJaf && JAF_PRESENT) {
      MediaType mediaType = JafMediaTypeFactory.getMediaType("file." + extension);
      if (mediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
        return mediaType;
      }
    }
    if (this.ignoreUnknownExtensions) {
      return null;
    }
    throw new HttpMediaTypeNotAcceptableException(getAllMediaTypes());
  }
 /**
  * A public method exposing the knowledge of the path extension strategy to resolve file
  * extensions to a MediaType in this case for a given {@link Resource}. The method first looks up
  * any explicitly registered file extensions first and then falls back on JAF if available.
  *
  * @param resource the resource to look up
  * @return the MediaType for the extension or {@code null}.
  * @since 4.3
  */
 public MediaType getMediaTypeForResource(Resource resource) {
   Assert.notNull(resource);
   MediaType mediaType = null;
   String filename = resource.getFilename();
   String extension = StringUtils.getFilenameExtension(filename);
   if (extension != null) {
     mediaType = lookupMediaType(extension);
   }
   if (mediaType == null && JAF_PRESENT) {
     mediaType = JafMediaTypeFactory.getMediaType(filename);
   }
   if (MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
     mediaType = null;
   }
   return mediaType;
 }
  /**
   * Resolve file extension via {@link ServletContext#getMimeType(String)} and also delegate to base
   * class for a potential JAF lookup.
   */
  @Override
  protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension)
      throws HttpMediaTypeNotAcceptableException {

    MediaType mediaType = null;
    if (this.servletContext != null) {
      String mimeType = this.servletContext.getMimeType("file." + extension);
      if (StringUtils.hasText(mimeType)) {
        mediaType = MediaType.parseMediaType(mimeType);
      }
    }
    if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) {
      MediaType superMediaType = super.handleNoMatch(webRequest, extension);
      if (superMediaType != null) {
        mediaType = superMediaType;
      }
    }
    return mediaType;
  }
 /**
  * Add default headers to the output message.
  *
  * <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content type
  * was not provided, calls {@link #getContentLength}, and sets the corresponding headers
  *
  * @since 4.2
  */
 protected void addDefaultHeaders(HttpHeaders headers, T t, MediaType contentType)
     throws IOException {
   if (headers.getContentType() == null) {
     MediaType contentTypeToUse = contentType;
     if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
       contentTypeToUse = getDefaultContentType(t);
     } else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
       MediaType mediaType = getDefaultContentType(t);
       contentTypeToUse = (mediaType != null ? mediaType : contentTypeToUse);
     }
     if (contentTypeToUse != null) {
       headers.setContentType(contentTypeToUse);
     }
   }
   if (headers.getContentLength() == -1) {
     Long contentLength = getContentLength(t, headers.getContentType());
     if (contentLength != null) {
       headers.setContentLength(contentLength);
     }
   }
 }