@Override
  public ExtRepositoryFileEntry updateExtRepositoryFileEntry(
      String extRepositoryFileEntryKey, String mimeType, InputStream inputStream)
      throws PortalException {

    try {
      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      File file = getFile(drive, extRepositoryFileEntryKey);

      InputStreamContent inputStreamContent = new InputStreamContent(mimeType, inputStream);

      Drive.Files.Update driveFilesUpdate =
          driveFiles.update(extRepositoryFileEntryKey, file, inputStreamContent);

      file = driveFilesUpdate.execute();

      return new GoogleDriveFileEntry(file);
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  @Override
  public <T extends ExtRepositoryObject> T getExtRepositoryObject(
      ExtRepositoryObjectType<T> extRepositoryObjectType,
      String extRepositoryFolderKey,
      String title)
      throws PortalException {

    try {
      StringBundler sb = new StringBundler();

      sb.append("'");
      sb.append(extRepositoryFolderKey);
      sb.append("' in parents and title contains '");
      sb.append(title);
      sb.append(" and mimeType ");

      if (extRepositoryObjectType.equals(ExtRepositoryObjectType.FOLDER)) {

        sb.append("= ");
      } else {
        sb.append("!= ");
      }

      sb.append(_FOLDER_MIME_TYPE);

      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      Drive.Files.List driveFilesList = driveFiles.list();

      driveFilesList.setQ(sb.toString());

      FileList fileList = driveFilesList.execute();

      List<File> files = fileList.getItems();

      if (files.isEmpty()) {
        if (extRepositoryObjectType == ExtRepositoryObjectType.FOLDER) {
          throw new NoSuchFolderException(title);
        }

        throw new NoSuchFileEntryException(title);
      }

      if (extRepositoryObjectType.equals(ExtRepositoryObjectType.FOLDER)) {

        return (T) new GoogleDriveFolder(files.get(0), getRootFolderKey());
      }

      return (T) new GoogleDriveFileEntry(files.get(0));
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  @Override
  public List<ExtRepositorySearchResult<?>> search(
      SearchContext searchContext, Query query, ExtRepositoryQueryMapper extRepositoryQueryMapper)
      throws PortalException {

    try {
      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      Drive.Files.List driveFilesList = driveFiles.list();

      String searchQuery =
          getSearchQuery(
              searchContext.getKeywords(), searchContext.getFolderIds(), extRepositoryQueryMapper);

      driveFilesList.setQ(searchQuery);

      FileList fileList = driveFilesList.execute();

      List<File> files = fileList.getItems();

      List<ExtRepositorySearchResult<?>> extRepositorySearchResults = new ArrayList<>(files.size());

      for (File file : files) {
        if (_FOLDER_MIME_TYPE.equals(file.getMimeType())) {
          GoogleDriveFolder googleDriveFolder = new GoogleDriveFolder(file, getRootFolderKey());

          ExtRepositorySearchResult<GoogleDriveFolder> extRepositorySearchResult =
              new ExtRepositorySearchResult<>(googleDriveFolder, 1.0f, StringPool.BLANK);

          extRepositorySearchResults.add(extRepositorySearchResult);
        } else {
          GoogleDriveFileEntry googleDriveFileEntry = new GoogleDriveFileEntry(file);

          ExtRepositorySearchResult<GoogleDriveFileEntry> extRepositorySearchResult =
              new ExtRepositorySearchResult<>(googleDriveFileEntry, 1.0f, StringPool.BLANK);

          extRepositorySearchResults.add(extRepositorySearchResult);
        }
      }

      return extRepositorySearchResults;
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  protected File addFile(
      String extRepositoryParentFolderKey,
      String mimeType,
      String title,
      String description,
      InputStream inputStream)
      throws PortalException {

    try {
      File file = new File();

      file.setDescription(description);
      file.setMimeType(mimeType);

      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      File extRepositoryParentFolderFile = getFile(drive, extRepositoryParentFolderKey);

      ParentReference parentReference = new ParentReference();

      parentReference.setId(extRepositoryParentFolderFile.getId());

      file.setParents(Arrays.asList(parentReference));

      file.setTitle(title);

      if (inputStream != null) {
        InputStreamContent inputStreamContent = new InputStreamContent(mimeType, inputStream);

        Drive.Files.Insert driveFilesInsert = driveFiles.insert(file, inputStreamContent);

        return driveFilesInsert.execute();
      } else {
        Drive.Files.Insert driveFilesInsert = driveFiles.insert(file);

        return driveFilesInsert.execute();
      }
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  protected File getFile(Drive drive, String extRepositoryObjectKey) throws IOException {

    GoogleDriveCache googleDriveCache = GoogleDriveCache.getInstance();

    File file = googleDriveCache.get(extRepositoryObjectKey);

    if (file == null) {
      Drive.Files driveFiles = drive.files();

      Drive.Files.Get driveFilesGet = driveFiles.get(extRepositoryObjectKey);

      file = driveFilesGet.execute();

      googleDriveCache.put(file);
    }

    return file;
  }
  @Override
  public <T extends ExtRepositoryObject> T copyExtRepositoryObject(
      ExtRepositoryObjectType<T> extRepositoryObjectType,
      String extRepositoryFileEntryKey,
      String newExtRepositoryFolderKey,
      String newTitle)
      throws PortalException {

    try {
      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      File newFile = new File();

      ParentReference parentReference = new ParentReference();

      parentReference.setId(newExtRepositoryFolderKey);

      newFile.setParents(Arrays.asList(parentReference));

      Drive.Files.Copy driveFilesCopy = driveFiles.copy(extRepositoryFileEntryKey, newFile);

      driveFilesCopy.execute();

      T extRepositoryObject = null;

      if (extRepositoryObjectType.equals(ExtRepositoryObjectType.FOLDER)) {

        extRepositoryObject = (T) new GoogleDriveFolder(newFile, getRootFolderKey());
      } else {
        extRepositoryObject = (T) new GoogleDriveFileEntry(newFile);
      }

      return extRepositoryObject;
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  @Override
  public void deleteExtRepositoryObject(
      ExtRepositoryObjectType<? extends ExtRepositoryObject> extRepositoryObjectType,
      String extRepositoryObjectKey)
      throws PortalException {

    try {
      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      Drive.Files.Delete driveFilesDelete = driveFiles.delete(extRepositoryObjectKey);

      driveFilesDelete.execute();

      GoogleDriveCache googleDriveCache = GoogleDriveCache.getInstance();

      googleDriveCache.remove(extRepositoryObjectKey);
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }
  @Override
  public <T extends ExtRepositoryObject> List<T> getExtRepositoryObjects(
      ExtRepositoryObjectType<T> extRepositoryObjectType, String extRepositoryFolderKey)
      throws PortalException {

    try {
      Drive drive = getDrive();

      Drive.Files driveFiles = drive.files();

      Drive.Files.List driveFilesList = driveFiles.list();

      StringBundler sb = new StringBundler();

      if (extRepositoryFolderKey != null) {
        sb.append("'");
        sb.append(extRepositoryFolderKey);
        sb.append("' in parents and ");
      }

      if (!extRepositoryObjectType.equals(ExtRepositoryObjectType.OBJECT)) {

        sb.append("mimeType");

        if (extRepositoryObjectType.equals(ExtRepositoryObjectType.FILE)) {

          sb.append(" != '");
        } else {
          sb.append(" = '");
        }

        sb.append(_FOLDER_MIME_TYPE);
        sb.append("' and ");
      }

      sb.append("trashed = false");

      driveFilesList.setQ(sb.toString());

      FileList fileList = driveFilesList.execute();

      List<File> files = fileList.getItems();

      List<T> extRepositoryObjects = new ArrayList<>();

      GoogleDriveCache googleDriveCache = GoogleDriveCache.getInstance();

      for (File file : files) {
        if (_FOLDER_MIME_TYPE.equals(file.getMimeType())) {
          extRepositoryObjects.add((T) new GoogleDriveFolder(file, getRootFolderKey()));
        } else {
          extRepositoryObjects.add((T) new GoogleDriveFileEntry(file));
        }

        googleDriveCache.put(file);
      }

      return extRepositoryObjects;
    } catch (IOException ioe) {
      _log.error(ioe, ioe);

      throw new SystemException(ioe);
    }
  }