blob: b5731d88b98fea1cfa972dfc10a081bde3d06747 [file] [log] [blame]
// Copyright (c) 2012 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.
#ifndef CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_
#define CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_
#include <list>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
#include "chrome/service/cloud_print/job_status_updater.h"
#include "chrome/service/cloud_print/printer_job_queue_handler.h"
#include "net/url_request/url_request_status.h"
#include "printing/backend/print_backend.h"
#include "url/gurl.h"
class URLFetcher;
// A class that handles cloud print jobs for a particular printer. This class
// imlements a state machine that transitions from Start to various states. The
// various states are shown in the below diagram.
// the status on the server.
// Start --> No pending tasks --> Done
// |
// |
// | Have Pending tasks
// |
// |
// | ---Update Pending----->
// | |
// | |
// | |
// | Update Printer info on server
// | Go to Stop
// |
// | Job Available
// |
// |
// Fetch Next Job Metadata
// Fetch Print Ticket
// Fetch Print Data
// Spool Print Job
// Create Job StatusUpdater for job
// Mark job as "in progress" on server
// (On any unrecoverable error in any of the above steps go to Stop)
// Go to Stop
// |
// |
// |
// |
// |
// |
// |
// Stop
// (If there are pending tasks go back to Start)
namespace cloud_print {
class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
public CloudPrintURLFetcherDelegate,
public JobStatusUpdaterDelegate,
public PrintSystem::PrinterWatcher::Delegate,
public PrintSystem::JobSpooler::Delegate {
public:
class Delegate {
public:
// Notify delegate about authentication error.
virtual void OnAuthError() = 0;
// Notify delegate that printer has been deleted.
virtual void OnPrinterDeleted(const std::string& printer_name) = 0;
protected:
virtual ~Delegate() {}
};
struct PrinterInfoFromCloud {
std::string printer_id;
std::string caps_hash;
std::string tags_hash;
int current_xmpp_timeout;
int pending_xmpp_timeout;
PrinterInfoFromCloud();
};
// Begin public interface
PrinterJobHandler(const printing::PrinterBasicInfo& printer_info,
const PrinterInfoFromCloud& printer_info_from_server,
const GURL& cloud_print_server_url,
PrintSystem* print_system,
Delegate* delegate);
bool Initialize();
std::string GetPrinterName() const;
// Requests a job check. |reason| is the reason for fetching the job. Used
// for logging and diagnostc purposes.
void CheckForJobs(const std::string& reason);
// Shutdown everything (the process is exiting).
void Shutdown();
base::TimeTicks last_job_fetch_time() const { return last_job_fetch_time_; }
// End public interface
// Begin Delegate implementations
// CloudPrintURLFetcher::Delegate implementation.
CloudPrintURLFetcher::ResponseAction HandleRawResponse(
const net::URLFetcher* source,
const GURL& url,
const net::URLRequestStatus& status,
int response_code,
const net::ResponseCookies& cookies,
const std::string& data) override;
CloudPrintURLFetcher::ResponseAction HandleRawData(
const net::URLFetcher* source,
const GURL& url,
const std::string& data) override;
CloudPrintURLFetcher::ResponseAction HandleJSONData(
const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded) override;
void OnRequestGiveUp() override;
CloudPrintURLFetcher::ResponseAction OnRequestAuthError() override;
std::string GetAuthHeader() override;
// JobStatusUpdater::Delegate implementation
bool OnJobCompleted(JobStatusUpdater* updater) override;
void OnAuthError() override;
// PrinterWatcherDelegate implementation
void OnPrinterDeleted() override;
void OnPrinterChanged() override;
void OnJobChanged() override;
// JobSpoolerDelegate implementation.
// Called on print_thread_.
void OnJobSpoolSucceeded(const PlatformJobId& job_id) override;
void OnJobSpoolFailed() override;
// End Delegate implementations
static void ReportsStats();
private:
friend class base::RefCountedThreadSafe<PrinterJobHandler>;
enum PrintJobError {
JOB_SUCCESS,
JOB_DOWNLOAD_FAILED,
JOB_VALIDATE_TICKET_FAILED,
JOB_FAILED,
JOB_MAX,
};
// Prototype for a JSON data handler.
typedef CloudPrintURLFetcher::ResponseAction
(PrinterJobHandler::*JSONDataHandler)(const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
// Prototype for a data handler.
typedef CloudPrintURLFetcher::ResponseAction
(PrinterJobHandler::*DataHandler)(const net::URLFetcher* source,
const GURL& url,
const std::string& data);
~PrinterJobHandler() override;
// Begin request handlers for each state in the state machine
CloudPrintURLFetcher::ResponseAction HandlePrinterUpdateResponse(
const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandlePrintTicketResponse(
const net::URLFetcher* source,
const GURL& url,
const std::string& data);
CloudPrintURLFetcher::ResponseAction HandlePrintDataResponse(
const net::URLFetcher* source,
const GURL& url,
const std::string& data);
CloudPrintURLFetcher::ResponseAction HandleInProgressStatusUpdateResponse(
const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleFailureStatusUpdateResponse(
const net::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
// End request handlers for each state in the state machine
// Start the state machine. Based on the flags set this could mean updating
// printer information, deleting the printer from the server or looking for
// new print jobs
void Start();
// End the state machine. If there are pending tasks, we will post a Start
// again.
void Stop();
void StartPrinting();
void Reset();
void UpdateJobStatus(PrintJobStatus status, PrintJobError error);
// Run a job check as the result of a scheduled check
void RunScheduledJobCheck();
// Sets the next response handler to the specified JSON data handler.
void SetNextJSONHandler(JSONDataHandler handler);
// Sets the next response handler to the specified data handler.
void SetNextDataHandler(DataHandler handler);
void JobFailed(PrintJobError error);
void JobSpooled(PlatformJobId local_job_id);
// Returns false if printer info is up to date and no updating is needed.
bool UpdatePrinterInfo();
bool HavePendingTasks();
void ValidatePrintTicketFailed();
// Callback that asynchronously receives printer caps and defaults.
void OnReceivePrinterCaps(
bool succeeded,
const std::string& printer_name,
const printing::PrinterCapsAndDefaults& caps_and_defaults);
// Called on print_thread_.
void DoPrint(const JobDetails& job_details,
const std::string& printer_name);
scoped_refptr<CloudPrintURLFetcher> request_;
scoped_refptr<PrintSystem> print_system_;
printing::PrinterBasicInfo printer_info_;
PrinterInfoFromCloud printer_info_cloud_;
GURL cloud_print_server_url_;
std::string print_data_url_;
JobDetails job_details_;
Delegate* delegate_;
// Once the job has been spooled to the local spooler, this specifies the
// job id of the job on the local spooler.
PlatformJobId local_job_id_;
// The next response handler can either be a JSONDataHandler or a
// DataHandler (depending on the current request being made).
JSONDataHandler next_json_data_handler_;
DataHandler next_data_handler_;
// The number of consecutive times that connecting to the server failed.
int server_error_count_;
// The thread on which the actual print operation happens
base::Thread print_thread_;
// The Job spooler object. This is only non-NULL during a print operation.
// It lives and dies on |print_thread_|
scoped_refptr<PrintSystem::JobSpooler> job_spooler_;
// The message loop proxy representing the thread on which this object
// was created. Used by the print thread.
scoped_refptr<base::MessageLoopProxy> job_handler_message_loop_proxy_;
// There may be pending tasks in the message queue when Shutdown is called.
// We set this flag so as to do nothing in those tasks.
bool shutting_down_;
// A string indicating the reason we are fetching jobs from the server
// (used to specify the reason in the fetch URL).
std::string job_fetch_reason_;
// Flags that specify various pending server updates
bool job_check_pending_;
bool printer_update_pending_;
// Number of seconds between XMPP pings (for server registration)
int xmpp_ping_interval_;
// Some task in the state machine is in progress.
bool task_in_progress_;
scoped_refptr<PrintSystem::PrinterWatcher> printer_watcher_;
typedef std::list< scoped_refptr<JobStatusUpdater> > JobStatusUpdaterList;
JobStatusUpdaterList job_status_updater_list_;
// Manages parsing the job queue
PrinterJobQueueHandler job_queue_handler_;
base::TimeTicks last_job_fetch_time_;
base::Time job_start_time_;
base::Time spooling_start_time_;
base::Time last_caps_update_time_;
base::WeakPtrFactory<PrinterJobHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PrinterJobHandler);
};
// This typedef is to workaround the issue with certain versions of
// Visual Studio where it gets confused between multiple Delegate
// classes and gives a C2500 error. (I saw this error on the try bots -
// the workaround was not needed for my machine).
typedef PrinterJobHandler::Delegate PrinterJobHandlerDelegate;
} // namespace cloud_print
#endif // CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_