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.
5 #include "chrome/browser/chromeos/drive/file_system/search_operation.h"
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/change_list_loader.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/drive/job_scheduler.h"
17 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
18 #include "chrome/browser/chromeos/drive/resource_metadata.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "google_apis/drive/gdata_wapi_parser.h"
23 using content::BrowserThread;
26 namespace file_system {
29 // Computes the path of each item in |resource_list| returned from the server
30 // and stores to |result|, by using |resource_metadata|. If the metadata is not
31 // up-to-date and did not contain an item, adds the item to "drive/other" for
32 // temporally assigning a path.
33 FileError ResolveSearchResultOnBlockingPool(
34 internal::ResourceMetadata* resource_metadata,
35 scoped_ptr<google_apis::ResourceList> resource_list,
36 std::vector<SearchResultInfo>* result) {
37 DCHECK(resource_metadata);
40 const ScopedVector<google_apis::ResourceEntry>& entries =
41 resource_list->entries();
42 result->reserve(entries.size());
43 for (size_t i = 0; i < entries.size(); ++i) {
45 FileError error = resource_metadata->GetIdByResourceId(
46 entries[i]->resource_id(), &local_id);
49 if (error == FILE_ERROR_OK)
50 error = resource_metadata->GetResourceEntryById(local_id, &entry);
52 if (error == FILE_ERROR_NOT_FOUND) {
53 std::string original_parent_id;
54 if (!ConvertToResourceEntry(*entries[i], &entry, &original_parent_id))
55 continue; // Skip non-file entries.
57 // The result is absent in local resource metadata. This can happen if
58 // the metadata is not synced to the latest server state yet. In that
59 // case, we temporarily add the file to the special "drive/other"
60 // directory in order to assign a path, which is needed to access the
61 // file through FileSystem API.
63 // It will be moved to the right place when the metadata gets synced
64 // in normal loading process in ChangeListProcessor.
65 entry.set_parent_local_id(util::kDriveOtherDirLocalId);
66 error = resource_metadata->AddEntry(entry, &local_id);
68 if (error != FILE_ERROR_OK)
71 SearchResultInfo(resource_metadata->GetFilePath(local_id),
72 entry.file_info().is_directory()));
80 SearchOperation::SearchOperation(
81 base::SequencedTaskRunner* blocking_task_runner,
82 JobScheduler* scheduler,
83 internal::ResourceMetadata* metadata,
84 internal::LoaderController* loader_controller)
85 : blocking_task_runner_(blocking_task_runner),
86 scheduler_(scheduler),
88 loader_controller_(loader_controller),
89 weak_ptr_factory_(this) {
92 SearchOperation::~SearchOperation() {
95 void SearchOperation::Search(const std::string& search_query,
96 const GURL& next_link,
97 const SearchCallback& callback) {
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
99 DCHECK(!callback.is_null());
101 if (next_link.is_empty()) {
102 // This is first request for the |search_query|.
105 base::Bind(&SearchOperation::SearchAfterGetResourceList,
106 weak_ptr_factory_.GetWeakPtr(), callback));
108 // There is the remaining result so fetch it.
109 scheduler_->GetRemainingFileList(
111 base::Bind(&SearchOperation::SearchAfterGetResourceList,
112 weak_ptr_factory_.GetWeakPtr(), callback));
116 void SearchOperation::SearchAfterGetResourceList(
117 const SearchCallback& callback,
118 google_apis::GDataErrorCode gdata_error,
119 scoped_ptr<google_apis::ResourceList> resource_list) {
120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
121 DCHECK(!callback.is_null());
123 FileError error = GDataToFileError(gdata_error);
124 if (error != FILE_ERROR_OK) {
125 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >());
129 DCHECK(resource_list);
132 resource_list->GetNextFeedURL(&next_url);
134 scoped_ptr<std::vector<SearchResultInfo> > result(
135 new std::vector<SearchResultInfo>);
136 if (resource_list->entries().empty()) {
137 // Short cut. If the resource entry is empty, we don't need to refresh
138 // the resource metadata.
139 callback.Run(FILE_ERROR_OK, next_url, result.Pass());
143 // ResolveSearchResultOnBlockingPool() may add entries newly created on the
144 // server to the local metadata.
145 // This may race with sync tasks so we should ask LoaderController here.
146 std::vector<SearchResultInfo>* result_ptr = result.get();
147 loader_controller_->ScheduleRun(base::Bind(
149 &base::PostTaskAndReplyWithResult<FileError, FileError>),
150 blocking_task_runner_,
152 base::Bind(&ResolveSearchResultOnBlockingPool,
154 base::Passed(&resource_list),
156 base::Bind(&SearchOperation::SearchAfterResolveSearchResult,
157 weak_ptr_factory_.GetWeakPtr(),
160 base::Passed(&result))));
163 void SearchOperation::SearchAfterResolveSearchResult(
164 const SearchCallback& callback,
165 const GURL& next_link,
166 scoped_ptr<std::vector<SearchResultInfo> > result,
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169 DCHECK(!callback.is_null());
172 if (error != FILE_ERROR_OK) {
173 callback.Run(error, GURL(), scoped_ptr<std::vector<SearchResultInfo> >());
177 callback.Run(error, next_link, result.Pass());
180 } // namespace file_system