text: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *    http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.gobblin.type;
  
  import java.util.List;
  import java.util.concurrent.ConcurrentHashMap;
  
  import lombok.extern.slf4j.Slf4j;
  
  import org.apache.gobblin.metadata.types.Metadata;
  
  
  /**
   * Utilities to work with MIME content-types
   */
  @Slf4j
  public class ContentTypeUtils {
    private static final ContentTypeUtils INSTANCE = new ContentTypeUtils();
  
    public static ContentTypeUtils getInstance() {
      return INSTANCE;
    }
  
    private ConcurrentHashMap<String, String> knownCharsets;
  
    /**
     * Check which character set a given content-type corresponds to.
     * @param contentType Content-type to check
     * @return Charset the mimetype represents. "BINARY" if binary data.
     */
    public String getCharset(String contentType) {
      String charSet = knownCharsets.get(contentType);
      if (charSet != null) {
        return charSet;
      }
  
      // Special cases
      if (contentType.startsWith("text/") || contentType.endsWith("+json") || contentType.endsWith("+xml")) {
        return "UTF-8";
      }
  
      return "BINARY";
    }
  
    /**
     * Heuristic to infer if content is printable from metadata.
     */
    public boolean inferPrintableFromMetadata(Metadata md) {
      String inferredCharset = "BINARY";
      List<String> transferEncoding = md.getGlobalMetadata().getTransferEncoding();
  
      if (transferEncoding != null) {
        inferredCharset = getCharset(transferEncoding.get(transferEncoding.size() - 1));
      } else if (md.getGlobalMetadata().getContentType() != null) {
        inferredCharset = getCharset(md.getGlobalMetadata().getContentType());
      }
  
      return inferredCharset.equals("UTF-8");
    }
  
    /**
     * Register a new contentType to charSet mapping.
     * @param contentType Content-type to register
     * @param charSet charSet associated with the content-type
     */
    public void registerCharsetMapping(String contentType, String charSet) {
      if (knownCharsets.contains(contentType)) {
        log.warn("{} is already registered; re-registering");
      }
  
      knownCharsets.put(contentType, charSet);
    }
  
    private ContentTypeUtils() {
      knownCharsets = new ConcurrentHashMap<>();
      knownCharsets.put("base64", "UTF-8");
      knownCharsets.put("aes_rotating", "UTF-8");
      knownCharsets.put("gzip", "BINARY");
      knownCharsets.put("application/xml", "UTF-8");
      knownCharsets.put("application/json", "UTF-8");
    }
  }
  