root/chrome/browser/chromeos/drive/file_system/search_operation.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ResolveSearchResultOnBlockingPool
  2. weak_ptr_factory_
  3. SearchAfterGetResourceList
  4. SearchAfterResolveSearchResult

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/drive/file_system/search_operation.h"

#include <string>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/change_list_loader.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/gdata_wapi_parser.h"
#include "url/gurl.h"

using content::BrowserThread;

namespace drive {
namespace file_system {
namespace {

// Computes the path of each item in |resource_list| returned from the server
// and stores to |result|, by using |resource_metadata|. If the metadata is not
// up-to-date and did not contain an item, adds the item to "drive/other" for
// temporally assigning a path.
FileError ResolveSearchResultOnBlockingPool(
    internal::ResourceMetadata* resource_metadata,
    scoped_ptr<google_apis::ResourceList> resource_list,
    std::vector<SearchResultInfo>* result) {
  DCHECK(resource_metadata);
  DCHECK(result);

  const ScopedVector<google_apis::ResourceEntry>& entries =
      resource_list->entries();
  result->reserve(entries.size());
  for (size_t i = 0; i < entries.size(); ++i) {
    std::string local_id;
    FileError error = resource_metadata->GetIdByResourceId(
        entries[i]->resource_id(), &local_id);

    ResourceEntry entry;
    if (error == FILE_ERROR_OK)
      error = resource_metadata->GetResourceEntryById(local_id, &entry);

    if (error == FILE_ERROR_NOT_FOUND) {
      std::string original_parent_id;
      if (!ConvertToResourceEntry(*entries[i], &entry, &original_parent_id))
        continue;  // Skip non-file entries.

      // The result is absent in local resource metadata. This can happen if
      // the metadata is not synced to the latest server state yet. In that
      // case, we temporarily add the file to the special "drive/other"
      // directory in order to assign a path, which is needed to access the
      // file through FileSystem API.
      //
      // It will be moved to the right place when the metadata gets synced
      // in normal loading process in ChangeListProcessor.
      entry.set_parent_local_id(util::kDriveOtherDirLocalId);
      error = resource_metadata->AddEntry(entry, &local_id);
    }
    if (error != FILE_ERROR_OK)
      return error;
    result->push_back(
        SearchResultInfo(resource_metadata->GetFilePath(local_id),
                         entry.file_info().is_directory()));
  }

  return FILE_ERROR_OK;
}

}  // namespace

SearchOperation::SearchOperation(
    base::SequencedTaskRunner* blocking_task_runner,
    JobScheduler* scheduler,
    internal::ResourceMetadata* metadata,
    internal::LoaderController* loader_controller)
    : blocking_task_runner_(blocking_task_runner),
      scheduler_(scheduler),
      metadata_(metadata),
      loader_controller_(loader_controller),
      weak_ptr_factory_(this) {
}

SearchOperation::~SearchOperation() {
}

void SearchOperation::Search(const std::string& search_query,
                             const GURL& next_link,
                             const SearchCallback& callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(!callback.is_null());

  if (next_link.is_empty()) {
    // This is first request for the |search_query|.
    scheduler_->Search(
        search_query,
        base::Bind(&SearchOperation::SearchAfterGetResourceList,
                   weak_ptr_factory_.GetWeakPtr(), callback));
  } else {
    // There is the remaining result so fetch it.
    scheduler_->GetRemainingFileList(
        next_link,
        base::Bind(&SearchOperation::SearchAfterGetResourceList,
                   weak_ptr_factory_.GetWeakPtr(), callback));
  }
}

void SearchOperation::SearchAfterGetResourceList(
    const SearchCallback& callback,
    google_apis::GDataErrorCode gdata_error,
    scoped_ptr<google_apis::ResourceList> resource_list) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(!callback.is_null());

  FileError error = GDataToFileError(gdata_error);
  if (error != FILE_ERROR_OK) {
    callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >());
    return;
  }

  DCHECK(resource_list);

  GURL next_url;
  resource_list->GetNextFeedURL(&next_url);

  scoped_ptr<std::vector<SearchResultInfo> > result(
      new std::vector<SearchResultInfo>);
  if (resource_list->entries().empty()) {
    // Short cut. If the resource entry is empty, we don't need to refresh
    // the resource metadata.
    callback.Run(FILE_ERROR_OK, next_url, result.Pass());
    return;
  }

  // ResolveSearchResultOnBlockingPool() may add entries newly created on the
  // server to the local metadata.
  // This may race with sync tasks so we should ask LoaderController here.
  std::vector<SearchResultInfo>* result_ptr = result.get();
  loader_controller_->ScheduleRun(base::Bind(
      base::IgnoreResult(
          &base::PostTaskAndReplyWithResult<FileError, FileError>),
      blocking_task_runner_,
      FROM_HERE,
      base::Bind(&ResolveSearchResultOnBlockingPool,
                 metadata_,
                 base::Passed(&resource_list),
                 result_ptr),
      base::Bind(&SearchOperation::SearchAfterResolveSearchResult,
                 weak_ptr_factory_.GetWeakPtr(),
                 callback,
                 next_url,
                 base::Passed(&result))));
}

void SearchOperation::SearchAfterResolveSearchResult(
    const SearchCallback& callback,
    const GURL& next_link,
    scoped_ptr<std::vector<SearchResultInfo> > result,
    FileError error) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(!callback.is_null());
  DCHECK(result);

  if (error != FILE_ERROR_OK) {
    callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >());
    return;
  }

  callback.Run(error, next_link, result.Pass());
}

}  // namespace file_system
}  // namespace drive

/* [<][>][^][v][top][bottom][index][help] */