1// Copyright (c) 2012 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#ifndef CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_
6#define CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_
7
8#include <list>
9#include <string>
10#include <vector>
11
12#include "base/files/file_path.h"
13#include "base/memory/ref_counted.h"
14#include "base/memory/weak_ptr.h"
15#include "base/message_loop/message_loop_proxy.h"
16#include "base/threading/thread.h"
17#include "base/time/time.h"
18#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
19#include "chrome/service/cloud_print/job_status_updater.h"
20#include "chrome/service/cloud_print/printer_job_queue_handler.h"
21#include "net/url_request/url_request_status.h"
22#include "printing/backend/print_backend.h"
23#include "url/gurl.h"
24
25class URLFetcher;
26// A class that handles cloud print jobs for a particular printer. This class
27// imlements a state machine that transitions from Start to various states. The
28// various states are shown in the below diagram.
29// the status on the server.
30
31//                            Start --> No pending tasks --> Done
32//                              |
33//                              |
34//                              | Have Pending tasks
35//                              |
36//                              |
37//                              | ---Update Pending----->
38//                              |                       |
39//                              |                       |
40//                              |                       |
41//                              |                 Update Printer info on server
42//                              |                      Go to Stop
43//                              |
44//                              | Job Available
45//                              |
46//                              |
47//                        Fetch Next Job Metadata
48//                        Fetch Print Ticket
49//                        Fetch Print Data
50//                        Spool Print Job
51//                        Create Job StatusUpdater for job
52//                        Mark job as "in progress" on server
53//     (On any unrecoverable error in any of the above steps go to Stop)
54//                        Go to Stop
55//                              |
56//                              |
57//                              |
58//                              |
59//                              |
60//                              |
61//                              |
62//                             Stop
63//               (If there are pending tasks go back to Start)
64
65namespace cloud_print {
66
67class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
68                          public CloudPrintURLFetcherDelegate,
69                          public JobStatusUpdaterDelegate,
70                          public PrintSystem::PrinterWatcher::Delegate,
71                          public PrintSystem::JobSpooler::Delegate {
72 public:
73  class Delegate {
74   public:
75     // Notify delegate about authentication error.
76     virtual void OnAuthError() = 0;
77     // Notify delegate that printer has been deleted.
78     virtual void OnPrinterDeleted(const std::string& printer_name) = 0;
79
80   protected:
81     virtual ~Delegate() {}
82  };
83
84  struct PrinterInfoFromCloud {
85    std::string printer_id;
86    std::string caps_hash;
87    std::string tags_hash;
88    int current_xmpp_timeout;
89    int pending_xmpp_timeout;
90
91    PrinterInfoFromCloud();
92  };
93
94  // Begin public interface
95  PrinterJobHandler(const printing::PrinterBasicInfo& printer_info,
96                    const PrinterInfoFromCloud& printer_info_from_server,
97                    const GURL& cloud_print_server_url,
98                    PrintSystem* print_system,
99                    Delegate* delegate);
100
101  bool Initialize();
102
103  std::string GetPrinterName() const;
104
105  // Requests a job check. |reason| is the reason for fetching the job. Used
106  // for logging and diagnostc purposes.
107  void CheckForJobs(const std::string& reason);
108
109  // Shutdown everything (the process is exiting).
110  void Shutdown();
111
112  base::TimeTicks last_job_fetch_time() const { return last_job_fetch_time_; }
113  // End public interface
114
115  // Begin Delegate implementations
116
117  // CloudPrintURLFetcher::Delegate implementation.
118  virtual CloudPrintURLFetcher::ResponseAction HandleRawResponse(
119      const net::URLFetcher* source,
120      const GURL& url,
121      const net::URLRequestStatus& status,
122      int response_code,
123      const net::ResponseCookies& cookies,
124      const std::string& data) OVERRIDE;
125  virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
126      const net::URLFetcher* source,
127      const GURL& url,
128      const std::string& data) OVERRIDE;
129  virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
130      const net::URLFetcher* source,
131      const GURL& url,
132      base::DictionaryValue* json_data,
133      bool succeeded) OVERRIDE;
134  virtual void OnRequestGiveUp() OVERRIDE;
135  virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError() OVERRIDE;
136  virtual std::string GetAuthHeader() OVERRIDE;
137
138  // JobStatusUpdater::Delegate implementation
139  virtual bool OnJobCompleted(JobStatusUpdater* updater) OVERRIDE;
140  virtual void OnAuthError() OVERRIDE;
141
142  // PrinterWatcherDelegate implementation
143  virtual void OnPrinterDeleted() OVERRIDE;
144  virtual void OnPrinterChanged() OVERRIDE;
145  virtual void OnJobChanged() OVERRIDE;
146
147  // JobSpoolerDelegate implementation.
148  // Called on print_thread_.
149  virtual void OnJobSpoolSucceeded(const PlatformJobId& job_id) OVERRIDE;
150  virtual void OnJobSpoolFailed() OVERRIDE;
151
152  // End Delegate implementations
153
154  static void ReportsStats();
155
156 private:
157  friend class base::RefCountedThreadSafe<PrinterJobHandler>;
158
159  enum PrintJobError {
160    JOB_SUCCESS,
161    JOB_DOWNLOAD_FAILED,
162    JOB_VALIDATE_TICKET_FAILED,
163    JOB_FAILED,
164    JOB_MAX,
165  };
166
167  // Prototype for a JSON data handler.
168  typedef CloudPrintURLFetcher::ResponseAction
169      (PrinterJobHandler::*JSONDataHandler)(const net::URLFetcher* source,
170                                            const GURL& url,
171                                            base::DictionaryValue* json_data,
172                                            bool succeeded);
173  // Prototype for a data handler.
174  typedef CloudPrintURLFetcher::ResponseAction
175      (PrinterJobHandler::*DataHandler)(const net::URLFetcher* source,
176                                        const GURL& url,
177                                        const std::string& data);
178
179  virtual ~PrinterJobHandler();
180
181  // Begin request handlers for each state in the state machine
182  CloudPrintURLFetcher::ResponseAction HandlePrinterUpdateResponse(
183      const net::URLFetcher* source,
184      const GURL& url,
185      base::DictionaryValue* json_data,
186      bool succeeded);
187
188  CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
189      const net::URLFetcher* source,
190      const GURL& url,
191      base::DictionaryValue* json_data,
192      bool succeeded);
193
194  CloudPrintURLFetcher::ResponseAction HandlePrintTicketResponse(
195      const net::URLFetcher* source,
196      const GURL& url,
197      const std::string& data);
198
199  CloudPrintURLFetcher::ResponseAction HandlePrintDataResponse(
200      const net::URLFetcher* source,
201      const GURL& url,
202      const std::string& data);
203
204  CloudPrintURLFetcher::ResponseAction HandleInProgressStatusUpdateResponse(
205      const net::URLFetcher* source,
206      const GURL& url,
207      base::DictionaryValue* json_data,
208      bool succeeded);
209
210  CloudPrintURLFetcher::ResponseAction HandleFailureStatusUpdateResponse(
211      const net::URLFetcher* source,
212      const GURL& url,
213      base::DictionaryValue* json_data,
214      bool succeeded);
215  // End request handlers for each state in the state machine
216
217  // Start the state machine. Based on the flags set this could mean updating
218  // printer information, deleting the printer from the server or looking for
219  // new print jobs
220  void Start();
221
222  // End the state machine. If there are pending tasks, we will post a Start
223  // again.
224  void Stop();
225
226  void StartPrinting();
227  void Reset();
228  void UpdateJobStatus(PrintJobStatus status, PrintJobError error);
229
230  // Run a job check as the result of a scheduled check
231  void RunScheduledJobCheck();
232
233  // Sets the next response handler to the specified JSON data handler.
234  void SetNextJSONHandler(JSONDataHandler handler);
235  // Sets the next response handler to the specified data handler.
236  void SetNextDataHandler(DataHandler handler);
237
238  void JobFailed(PrintJobError error);
239  void JobSpooled(PlatformJobId local_job_id);
240  // Returns false if printer info is up to date and no updating is needed.
241  bool UpdatePrinterInfo();
242  bool HavePendingTasks();
243  void ValidatePrintTicketFailed();
244
245  // Callback that asynchronously receives printer caps and defaults.
246  void OnReceivePrinterCaps(
247    bool succeeded,
248    const std::string& printer_name,
249    const printing::PrinterCapsAndDefaults& caps_and_defaults);
250
251  // Called on print_thread_.
252  void DoPrint(const JobDetails& job_details,
253               const std::string& printer_name);
254
255  scoped_refptr<CloudPrintURLFetcher> request_;
256  scoped_refptr<PrintSystem> print_system_;
257  printing::PrinterBasicInfo printer_info_;
258  PrinterInfoFromCloud printer_info_cloud_;
259  GURL cloud_print_server_url_;
260  std::string print_data_url_;
261  JobDetails job_details_;
262  Delegate* delegate_;
263  // Once the job has been spooled to the local spooler, this specifies the
264  // job id of the job on the local spooler.
265  PlatformJobId local_job_id_;
266
267  // The next response handler can either be a JSONDataHandler or a
268  // DataHandler (depending on the current request being made).
269  JSONDataHandler next_json_data_handler_;
270  DataHandler next_data_handler_;
271  // The number of consecutive times that connecting to the server failed.
272  int server_error_count_;
273  // The thread on which the actual print operation happens
274  base::Thread print_thread_;
275  // The Job spooler object. This is only non-NULL during a print operation.
276  // It lives and dies on |print_thread_|
277  scoped_refptr<PrintSystem::JobSpooler> job_spooler_;
278  // The message loop proxy representing the thread on which this object
279  // was created. Used by the print thread.
280  scoped_refptr<base::MessageLoopProxy> job_handler_message_loop_proxy_;
281
282  // There may be pending tasks in the message queue when Shutdown is called.
283  // We set this flag so as to do nothing in those tasks.
284  bool shutting_down_;
285
286  // A string indicating the reason we are fetching jobs from the server
287  // (used to specify the reason in the fetch URL).
288  std::string job_fetch_reason_;
289  // Flags that specify various pending server updates
290  bool job_check_pending_;
291  bool printer_update_pending_;
292
293  // Number of seconds between XMPP pings (for server registration)
294  int xmpp_ping_interval_;
295
296  // Some task in the state machine is in progress.
297  bool task_in_progress_;
298  scoped_refptr<PrintSystem::PrinterWatcher> printer_watcher_;
299  typedef std::list< scoped_refptr<JobStatusUpdater> > JobStatusUpdaterList;
300  JobStatusUpdaterList job_status_updater_list_;
301
302  // Manages parsing the job queue
303  PrinterJobQueueHandler job_queue_handler_;
304
305  base::TimeTicks last_job_fetch_time_;
306
307  base::Time job_start_time_;
308  base::Time spooling_start_time_;
309  base::Time last_caps_update_time_;
310
311  base::WeakPtrFactory<PrinterJobHandler> weak_ptr_factory_;
312
313  DISALLOW_COPY_AND_ASSIGN(PrinterJobHandler);
314};
315
316// This typedef is to workaround the issue with certain versions of
317// Visual Studio where it gets confused between multiple Delegate
318// classes and gives a C2500 error. (I saw this error on the try bots -
319// the workaround was not needed for my machine).
320typedef PrinterJobHandler::Delegate PrinterJobHandlerDelegate;
321
322}  // namespace cloud_print
323
324#endif  // CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_
325