- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / service / cloud_print / printer_job_queue_handler.cc
1 // Copyright (c) 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/service/cloud_print/printer_job_queue_handler.h"
6
7 #include <math.h>
8
9 #include <algorithm>
10
11 #include "base/values.h"
12
13 namespace cloud_print {
14
15 class TimeProviderImpl : public PrinterJobQueueHandler::TimeProvider {
16  public:
17     virtual base::Time GetNow() OVERRIDE;
18 };
19
20 base::Time TimeProviderImpl::GetNow() {
21   return base::Time::Now();
22 }
23
24 JobDetails::JobDetails() {}
25
26 JobDetails::~JobDetails() {}
27
28 void JobDetails::Clear() {
29   job_id_.clear();
30   job_title_.clear();
31   print_ticket_.clear();
32   print_data_mime_type_.clear();
33   print_data_file_path_ = base::FilePath();
34   print_data_url_.clear();
35   print_ticket_url_.clear();
36   tags_.clear();
37   time_remaining_ = base::TimeDelta();
38 }
39
40 // static
41 bool JobDetails::ordering(const JobDetails& first, const JobDetails& second) {
42   return first.time_remaining_ < second.time_remaining_;
43 }
44
45 PrinterJobQueueHandler::PrinterJobQueueHandler(TimeProvider* time_provider)
46     : time_provider_(time_provider) {}
47
48 PrinterJobQueueHandler::PrinterJobQueueHandler()
49     : time_provider_(new TimeProviderImpl()) {}
50
51 PrinterJobQueueHandler::~PrinterJobQueueHandler() {}
52
53 void PrinterJobQueueHandler::ConstructJobDetailsFromJson(
54     const DictionaryValue* job_data,
55     JobDetails* job_details) {
56   job_details->Clear();
57
58   job_data->GetString(kIdValue, &job_details->job_id_);
59   job_data->GetString(kTitleValue, &job_details->job_title_);
60
61   job_data->GetString(kTicketUrlValue, &job_details->print_ticket_url_);
62   job_data->GetString(kFileUrlValue, &job_details->print_data_url_);
63
64   // Get tags for print job.
65   const ListValue* tags = NULL;
66   if (job_data->GetList(kTagsValue, &tags)) {
67     for (size_t i = 0; i < tags->GetSize(); i++) {
68       std::string value;
69       if (tags->GetString(i, &value))
70         job_details->tags_.push_back(value);
71     }
72   }
73 }
74
75 base::TimeDelta PrinterJobQueueHandler::ComputeBackoffTime(
76     const std::string& job_id) {
77   FailedJobMap::const_iterator job_location = failed_job_map_.find(job_id);
78   if (job_location == failed_job_map_.end()) {
79     return base::TimeDelta();
80   }
81
82   base::TimeDelta backoff_time =
83       base::TimeDelta::FromSeconds(kJobFirstWaitTimeSecs);
84   backoff_time *=
85       // casting argument to double and result to uint64 to avoid compilation
86       // issues
87       static_cast<int64>(pow(
88           static_cast<long double>(kJobWaitTimeExponentialMultiplier),
89           job_location->second.retries_) + 0.5);
90   base::Time scheduled_retry =
91       job_location->second.last_retry_ + backoff_time;
92   base::Time now = time_provider_->GetNow();
93   base::TimeDelta time_remaining;
94
95   if (scheduled_retry < now) {
96     return base::TimeDelta();
97   }
98   return scheduled_retry - now;
99 }
100
101 void PrinterJobQueueHandler::GetJobsFromQueue(const DictionaryValue* json_data,
102                                               std::vector<JobDetails>* jobs) {
103   std::vector<JobDetails> jobs_with_timeouts;
104
105   jobs->clear();
106
107   const ListValue* job_list = NULL;
108   if (!json_data->GetList(kJobListValue, &job_list)) {
109     return;
110   }
111
112   size_t list_size = job_list->GetSize();
113   for (size_t cur_job = 0; cur_job < list_size; cur_job++) {
114     const DictionaryValue* job_data = NULL;
115     if (job_list->GetDictionary(cur_job, &job_data)) {
116       JobDetails job_details_current;
117       ConstructJobDetailsFromJson(job_data, &job_details_current);
118
119       job_details_current.time_remaining_ =
120           ComputeBackoffTime(job_details_current.job_id_);
121
122       if (job_details_current.time_remaining_ == base::TimeDelta()) {
123         jobs->push_back(job_details_current);
124       } else {
125         jobs_with_timeouts.push_back(job_details_current);
126       }
127     }
128   }
129
130   sort(jobs_with_timeouts.begin(), jobs_with_timeouts.end(),
131        &JobDetails::ordering);
132   jobs->insert(jobs->end(), jobs_with_timeouts.begin(),
133                jobs_with_timeouts.end());
134 }
135
136 void PrinterJobQueueHandler::JobDone(const std::string& job_id) {
137   failed_job_map_.erase(job_id);
138 }
139
140 bool PrinterJobQueueHandler::JobFetchFailed(const std::string& job_id) {
141   FailedJobMetadata metadata;
142   metadata.retries_ = 0;
143   metadata.last_retry_ = time_provider_->GetNow();
144
145   std::pair<FailedJobMap::iterator, bool> job_found =
146       failed_job_map_.insert(FailedJobPair(job_id, metadata));
147
148   // If the job has already failed once, increment the number of retries.
149   // If it has failed too many times, remove it from the map and tell the caller
150   // to report a failure.
151   if (!job_found.second) {
152     if (job_found.first->second.retries_ >= kNumRetriesBeforeAbandonJob) {
153       failed_job_map_.erase(job_found.first);
154       return false;
155     }
156
157     job_found.first->second.retries_ += 1;
158     job_found.first->second.last_retry_ = time_provider_->GetNow();
159   }
160
161   return true;
162 }
163
164 }  // namespace cloud_print
165