search_operation.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/drive/file_system/search_operation.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/callback.h" 13#include "base/task_runner_util.h" 14#include "chrome/browser/chromeos/drive/file_system_util.h" 15#include "chrome/browser/chromeos/drive/job_scheduler.h" 16#include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 17#include "chrome/browser/chromeos/drive/resource_metadata.h" 18#include "chrome/browser/google_apis/gdata_wapi_parser.h" 19#include "content/public/browser/browser_thread.h" 20#include "url/gurl.h" 21 22using content::BrowserThread; 23 24namespace drive { 25namespace file_system { 26namespace { 27 28// Refreshes entries of |resource_metadata| based on |resource_list|, and 29// returns the result. Refreshed entries will be stored into |result|. 30FileError RefreshEntriesOnBlockingPool( 31 internal::ResourceMetadata* resource_metadata, 32 scoped_ptr<google_apis::ResourceList> resource_list, 33 std::vector<SearchResultInfo>* result) { 34 DCHECK(resource_metadata); 35 DCHECK(result); 36 37 const ScopedVector<google_apis::ResourceEntry>& entries = 38 resource_list->entries(); 39 result->reserve(entries.size()); 40 for (size_t i = 0; i < entries.size(); ++i) { 41 ResourceEntry entry; 42 if (!ConvertToResourceEntry(*entries[i], &entry)) 43 continue; // Skip non-file entries. 44 45 const std::string id = entry.resource_id(); 46 FileError error = resource_metadata->RefreshEntry(id, entry); 47 if (error == FILE_ERROR_NOT_FOUND) { 48 // The result is absent in local resource metadata. This can happen if 49 // the metadata is not synced to the latest server state yet. In that 50 // case, we temporarily add the file to the special "drive/other" 51 // directory in order to assign a path, which is needed to access the 52 // file through FileSystem API. 53 // 54 // It will be moved to the right place when the metadata gets synced 55 // in normal loading process in ChangeListProcessor. 56 entry.set_parent_local_id(util::kDriveOtherDirSpecialResourceId); 57 error = resource_metadata->AddEntry(entry); 58 59 // FILE_ERROR_EXISTS may happen if we have already added the entry to 60 // "drive/other" once before. That's not an error. 61 if (error == FILE_ERROR_EXISTS) 62 error = FILE_ERROR_OK; 63 } 64 if (error == FILE_ERROR_OK) 65 error = resource_metadata->GetResourceEntryById(id, &entry); 66 if (error != FILE_ERROR_OK) 67 return error; 68 result->push_back(SearchResultInfo(resource_metadata->GetFilePath(id), 69 entry)); 70 } 71 72 return FILE_ERROR_OK; 73} 74 75} // namespace 76 77SearchOperation::SearchOperation( 78 base::SequencedTaskRunner* blocking_task_runner, 79 JobScheduler* scheduler, 80 internal::ResourceMetadata* metadata) 81 : blocking_task_runner_(blocking_task_runner), 82 scheduler_(scheduler), 83 metadata_(metadata), 84 weak_ptr_factory_(this) { 85} 86 87SearchOperation::~SearchOperation() { 88} 89 90void SearchOperation::Search(const std::string& search_query, 91 const GURL& next_url, 92 const SearchCallback& callback) { 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 94 DCHECK(!callback.is_null()); 95 96 if (next_url.is_empty()) { 97 // This is first request for the |search_query|. 98 scheduler_->Search( 99 search_query, 100 base::Bind(&SearchOperation::SearchAfterGetResourceList, 101 weak_ptr_factory_.GetWeakPtr(), callback)); 102 } else { 103 // There is the remaining result so fetch it. 104 scheduler_->ContinueGetResourceList( 105 next_url, 106 base::Bind(&SearchOperation::SearchAfterGetResourceList, 107 weak_ptr_factory_.GetWeakPtr(), callback)); 108 } 109} 110 111void SearchOperation::SearchAfterGetResourceList( 112 const SearchCallback& callback, 113 google_apis::GDataErrorCode gdata_error, 114 scoped_ptr<google_apis::ResourceList> resource_list) { 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 116 DCHECK(!callback.is_null()); 117 118 FileError error = GDataToFileError(gdata_error); 119 if (error != FILE_ERROR_OK) { 120 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >()); 121 return; 122 } 123 124 DCHECK(resource_list); 125 126 GURL next_url; 127 resource_list->GetNextFeedURL(&next_url); 128 129 // The search results will be returned using virtual directory. 130 // The directory is not really part of the file system, so it has no parent or 131 // root. 132 scoped_ptr<std::vector<SearchResultInfo> > result( 133 new std::vector<SearchResultInfo>); 134 if (resource_list->entries().empty()) { 135 // Short cut. If the resource entry is empty, we don't need to refresh 136 // the resource metadata. 137 callback.Run(FILE_ERROR_OK, next_url, result.Pass()); 138 return; 139 } 140 141 std::vector<SearchResultInfo>* result_ptr = result.get(); 142 base::PostTaskAndReplyWithResult( 143 blocking_task_runner_.get(), 144 FROM_HERE, 145 base::Bind(&RefreshEntriesOnBlockingPool, 146 metadata_, 147 base::Passed(&resource_list), 148 result_ptr), 149 base::Bind(&SearchOperation::SearchAfterRefreshEntry, 150 weak_ptr_factory_.GetWeakPtr(), 151 callback, 152 next_url, 153 base::Passed(&result))); 154} 155 156void SearchOperation::SearchAfterRefreshEntry( 157 const SearchCallback& callback, 158 const GURL& next_url, 159 scoped_ptr<std::vector<SearchResultInfo> > result, 160 FileError error) { 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 162 DCHECK(!callback.is_null()); 163 DCHECK(result); 164 165 if (error != FILE_ERROR_OK) { 166 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >()); 167 return; 168 } 169 170 callback.Run(error, next_url, result.Pass()); 171} 172 173} // namespace file_system 174} // namespace drive 175