blob: 03b50f7ad4762051ebf942d0a40615504965dd34 [file] [log] [blame]
// Copyright (c) 2011 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_
#pragma once
#include <list>
#include <string>
#include <vector>
#include "base/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop_proxy.h"
#include "base/threading/thread.h"
#include "base/time.h"
#include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
#include "chrome/service/cloud_print/job_status_updater.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_status.h"
#include "printing/backend/print_backend.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)
class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>,
public CloudPrintURLFetcherDelegate,
public JobStatusUpdaterDelegate,
public cloud_print::PrinterWatcherDelegate,
public cloud_print::JobSpoolerDelegate {
enum PrintJobError {
SUCCESS,
JOB_DOWNLOAD_FAILED,
INVALID_JOB_DATA,
PRINT_FAILED,
};
struct JobDetails {
JobDetails();
~JobDetails();
void Clear();
std::string job_id_;
std::string job_title_;
std::string print_ticket_;
FilePath print_data_file_path_;
std::string print_data_mime_type_;
std::vector<std::string> tags_;
};
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;
};
// Begin public interface
PrinterJobHandler(const printing::PrinterBasicInfo& printer_info,
const PrinterInfoFromCloud& printer_info_from_server,
const GURL& cloud_print_server_url,
cloud_print::PrintSystem* print_system,
Delegate* delegate);
virtual ~PrinterJobHandler();
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.
virtual CloudPrintURLFetcher::ResponseAction HandleRawResponse(
const content::URLFetcher* source,
const GURL& url,
const net::URLRequestStatus& status,
int response_code,
const net::ResponseCookies& cookies,
const std::string& data);
virtual CloudPrintURLFetcher::ResponseAction HandleRawData(
const content::URLFetcher* source,
const GURL& url,
const std::string& data);
virtual CloudPrintURLFetcher::ResponseAction HandleJSONData(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
virtual void OnRequestGiveUp();
virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError();
virtual std::string GetAuthHeader();
// JobStatusUpdater::Delegate implementation
virtual bool OnJobCompleted(JobStatusUpdater* updater);
virtual void OnAuthError();
// cloud_print::PrinterWatcherDelegate implementation
virtual void OnPrinterDeleted();
virtual void OnPrinterChanged();
virtual void OnJobChanged();
// cloud_print::JobSpoolerDelegate implementation.
// Called on print_thread_.
virtual void OnJobSpoolSucceeded(const cloud_print::PlatformJobId& job_id);
virtual void OnJobSpoolFailed();
// End Delegate implementations
private:
// Prototype for a JSON data handler.
typedef CloudPrintURLFetcher::ResponseAction
(PrinterJobHandler::*JSONDataHandler)(const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
// Prototype for a data handler.
typedef CloudPrintURLFetcher::ResponseAction
(PrinterJobHandler::*DataHandler)(const content::URLFetcher* source,
const GURL& url,
const std::string& data);
// Begin request handlers for each state in the state machine
CloudPrintURLFetcher::ResponseAction HandlePrinterUpdateResponse(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleJobMetadataResponse(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandlePrintTicketResponse(
const content::URLFetcher* source,
const GURL& url,
const std::string& data);
CloudPrintURLFetcher::ResponseAction HandlePrintDataResponse(
const content::URLFetcher* source,
const GURL& url,
const std::string& data);
CloudPrintURLFetcher::ResponseAction HandleSuccessStatusUpdateResponse(
const content::URLFetcher* source,
const GURL& url,
base::DictionaryValue* json_data,
bool succeeded);
CloudPrintURLFetcher::ResponseAction HandleFailureStatusUpdateResponse(
const content::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 HandleServerError(const GURL& url);
void Reset();
void UpdateJobStatus(cloud_print::PrintJobStatus status, PrintJobError error);
// Sets the next response handler to the specifed JSON data handler.
void SetNextJSONHandler(JSONDataHandler handler);
// Sets the next response handler to the specifed data handler.
void SetNextDataHandler(DataHandler handler);
void JobFailed(PrintJobError error);
void JobSpooled(cloud_print::PlatformJobId local_job_id);
// Returns false if printer info is up to date and no updating is needed.
bool UpdatePrinterInfo();
bool HavePendingTasks();
void FailedFetchingJobData();
// 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<cloud_print::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.
cloud_print::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<cloud_print::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_;
// Some task in the state machine is in progress.
bool task_in_progress_;
scoped_refptr<cloud_print::PrintSystem::PrinterWatcher> printer_watcher_;
typedef std::list< scoped_refptr<JobStatusUpdater> > JobStatusUpdaterList;
JobStatusUpdaterList job_status_updater_list_;
base::TimeTicks last_job_fetch_time_;
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;
#endif // CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_