Home | History | Annotate | Download | only in drive
      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 GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_
      6 #define GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_
      7 
      8 #include <string>
      9 #include <utility>
     10 #include <vector>
     11 
     12 #include "base/compiler_specific.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/memory/scoped_vector.h"
     15 #include "base/strings/string_piece.h"
     16 #include "base/time/time.h"
     17 #include "url/gurl.h"
     18 
     19 namespace base {
     20 class FilePath;
     21 class DictionaryValue;
     22 class Value;
     23 
     24 template <class StructType>
     25 class JSONValueConverter;
     26 
     27 namespace internal {
     28 template <class NestedType>
     29 class RepeatedMessageConverter;
     30 }  // namespace internal
     31 
     32 }  // namespace base
     33 
     34 // Defines data elements of Google Documents API as described in
     35 // http://code.google.com/apis/documents/.
     36 namespace google_apis {
     37 
     38 // Defines link (URL) of an entity (document, file, feed...). Each entity could
     39 // have more than one link representing it.
     40 class Link {
     41  public:
     42   enum LinkType {
     43     LINK_UNKNOWN,
     44     LINK_SELF,
     45     LINK_NEXT,
     46     LINK_PARENT,
     47     LINK_ALTERNATE,
     48     LINK_EDIT,
     49     LINK_EDIT_MEDIA,
     50     LINK_ALT_EDIT_MEDIA,
     51     LINK_ALT_POST,
     52     LINK_FEED,
     53     LINK_POST,
     54     LINK_BATCH,
     55     LINK_RESUMABLE_EDIT_MEDIA,
     56     LINK_RESUMABLE_CREATE_MEDIA,
     57     LINK_TABLES_FEED,
     58     LINK_WORKSHEET_FEED,
     59     LINK_THUMBNAIL,
     60     LINK_EMBED,
     61     LINK_PRODUCT,
     62     LINK_ICON,
     63     LINK_OPEN_WITH,
     64     LINK_SHARE,
     65   };
     66   Link();
     67   ~Link();
     68 
     69   // Registers the mapping between JSON field names and the members in
     70   // this class.
     71   static void RegisterJSONConverter(base::JSONValueConverter<Link>* converter);
     72 
     73   // Type of the link.
     74   LinkType type() const { return type_; }
     75 
     76   // URL of the link.
     77   const GURL& href() const { return href_; }
     78 
     79   // Title of the link.
     80   const std::string& title() const { return title_; }
     81 
     82   // For OPEN_WITH links, this contains the application ID. For all other link
     83   // types, it is the empty string.
     84   const std::string& app_id() const { return app_id_; }
     85 
     86   // Link MIME type.
     87   const std::string& mime_type() const { return mime_type_; }
     88 
     89   void set_type(LinkType type) { type_ = type; }
     90   void set_href(const GURL& href) { href_ = href; }
     91   void set_title(const std::string& title) { title_ = title; }
     92   void set_app_id(const std::string& app_id) { app_id_ = app_id; }
     93   void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; }
     94 
     95  private:
     96   friend class ResourceEntry;
     97   // Converts value of link.rel into LinkType. Outputs to |type| and returns
     98   // true when |rel| has a valid value. Otherwise does nothing and returns
     99   // false.
    100   static bool GetLinkType(const base::StringPiece& rel, LinkType* type);
    101 
    102   // Converts value of link.rel to application ID, if there is one embedded in
    103   // the link.rel field. Outputs to |app_id| and returns true when |rel| has a
    104   // valid value. Otherwise does nothing and returns false.
    105   static bool GetAppID(const base::StringPiece& rel, std::string* app_id);
    106 
    107   LinkType type_;
    108   GURL href_;
    109   std::string title_;
    110   std::string app_id_;
    111   std::string mime_type_;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(Link);
    114 };
    115 
    116 // Feed links define links (URLs) to special list of entries (i.e. list of
    117 // previous document revisions).
    118 class ResourceLink {
    119  public:
    120   enum ResourceLinkType {
    121     FEED_LINK_UNKNOWN,
    122     FEED_LINK_ACL,
    123     FEED_LINK_REVISIONS,
    124   };
    125   ResourceLink();
    126 
    127   // Registers the mapping between JSON field names and the members in
    128   // this class.
    129   static void RegisterJSONConverter(
    130       base::JSONValueConverter<ResourceLink>* converter);
    131 
    132   // MIME type of the feed.
    133   ResourceLinkType type() const { return type_; }
    134 
    135   // URL of the feed.
    136   const GURL& href() const { return href_; }
    137 
    138   void set_type(ResourceLinkType type) { type_ = type; }
    139   void set_href(const GURL& href) { href_ = href; }
    140 
    141  private:
    142   friend class ResourceEntry;
    143   // Converts value of gd$feedLink.rel into ResourceLinkType enum.
    144   // Outputs to |result| and returns true when |rel| has a valid
    145   // value.  Otherwise does nothing and returns false.
    146   static bool GetFeedLinkType(
    147       const base::StringPiece& rel, ResourceLinkType* result);
    148 
    149   ResourceLinkType type_;
    150   GURL href_;
    151 
    152   DISALLOW_COPY_AND_ASSIGN(ResourceLink);
    153 };
    154 
    155 // Author represents an author of an entity.
    156 class Author {
    157  public:
    158   Author();
    159 
    160   // Registers the mapping between JSON field names and the members in
    161   // this class.
    162   static void RegisterJSONConverter(
    163       base::JSONValueConverter<Author>* converter);
    164 
    165   // Getters.
    166   const std::string& name() const { return name_; }
    167   const std::string& email() const { return email_; }
    168 
    169   void set_name(const std::string& name) { name_ = name; }
    170   void set_email(const std::string& email) { email_ = email; }
    171 
    172  private:
    173   friend class ResourceEntry;
    174 
    175   std::string name_;
    176   std::string email_;
    177 
    178   DISALLOW_COPY_AND_ASSIGN(Author);
    179 };
    180 
    181 // Entry category.
    182 class Category {
    183  public:
    184   enum CategoryType {
    185     CATEGORY_UNKNOWN,
    186     CATEGORY_ITEM,
    187     CATEGORY_KIND,
    188     CATEGORY_LABEL,
    189   };
    190 
    191   Category();
    192 
    193   // Registers the mapping between JSON field names and the members in
    194   // this class.
    195   static void RegisterJSONConverter(
    196       base::JSONValueConverter<Category>* converter);
    197 
    198   // Category label.
    199   const std::string& label() const { return label_; }
    200 
    201   // Category type.
    202   CategoryType type() const { return type_; }
    203 
    204   // Category term.
    205   const std::string& term() const { return term_; }
    206 
    207   void set_label(const std::string& label) { label_ = label; }
    208   void set_type(CategoryType type) { type_ = type; }
    209   void set_term(const std::string& term) { term_ = term; }
    210 
    211  private:
    212   friend class ResourceEntry;
    213   // Converts category scheme into CategoryType enum. For example,
    214   // http://schemas.google.com/g/2005#kind => Category::CATEGORY_KIND
    215   // Returns false and does not change |result| when |scheme| has an
    216   // unrecognizable value.
    217   static bool GetCategoryTypeFromScheme(
    218       const base::StringPiece& scheme, CategoryType* result);
    219 
    220   std::string label_;
    221   CategoryType type_;
    222   std::string term_;
    223 
    224   DISALLOW_COPY_AND_ASSIGN(Category);
    225 };
    226 
    227 // Content details of a resource: mime-type, url, and so on.
    228 class Content {
    229  public:
    230   Content();
    231 
    232   // Registers the mapping between JSON field names and the members in
    233   // this class.
    234   static void RegisterJSONConverter(
    235       base::JSONValueConverter<Content>* converter);
    236 
    237   // The URL to download the file content.
    238   // Note that the url can expire, so we'll fetch the latest resource
    239   // entry before starting a download to get the download URL.
    240   const GURL& url() const { return url_; }
    241   const std::string& mime_type() const { return mime_type_; }
    242 
    243   void set_url(const GURL& url) { url_ = url; }
    244   void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; }
    245 
    246  private:
    247   friend class ResourceEntry;
    248 
    249   GURL url_;
    250   std::string mime_type_;
    251 };
    252 
    253 // Base class for feed entries. This class defines fields commonly used by
    254 // various feeds.
    255 class CommonMetadata {
    256  public:
    257   CommonMetadata();
    258   virtual ~CommonMetadata();
    259 
    260   // Returns a link of a given |type| for this entry. If not found, it returns
    261   // NULL.
    262   const Link* GetLinkByType(Link::LinkType type) const;
    263 
    264   // Entry update time.
    265   base::Time updated_time() const { return updated_time_; }
    266 
    267   // Entry ETag.
    268   const std::string& etag() const { return etag_; }
    269 
    270   // List of entry authors.
    271   const ScopedVector<Author>& authors() const { return authors_; }
    272 
    273   // List of entry links.
    274   const ScopedVector<Link>& links() const { return links_; }
    275   ScopedVector<Link>* mutable_links() { return &links_; }
    276 
    277   // List of entry categories.
    278   const ScopedVector<Category>& categories() const { return categories_; }
    279 
    280   void set_etag(const std::string& etag) { etag_ = etag; }
    281   void set_authors(ScopedVector<Author> authors) {
    282     authors_ = authors.Pass();
    283   }
    284   void set_links(ScopedVector<Link> links) {
    285     links_ = links.Pass();
    286   }
    287   void set_categories(ScopedVector<Category> categories) {
    288     categories_ = categories.Pass();
    289   }
    290   void set_updated_time(const base::Time& updated_time) {
    291     updated_time_ = updated_time;
    292   }
    293 
    294  protected:
    295   // Registers the mapping between JSON field names and the members in
    296   // this class.
    297   template<typename CommonMetadataDescendant>
    298   static void RegisterJSONConverter(
    299       base::JSONValueConverter<CommonMetadataDescendant>* converter);
    300 
    301   std::string etag_;
    302   ScopedVector<Author> authors_;
    303   ScopedVector<Link> links_;
    304   ScopedVector<Category> categories_;
    305   base::Time updated_time_;
    306 
    307   DISALLOW_COPY_AND_ASSIGN(CommonMetadata);
    308 };
    309 
    310 // This class represents a resource entry. A resource is a generic term which
    311 // refers to a file and a directory.
    312 class ResourceEntry : public CommonMetadata {
    313  public:
    314   enum ResourceEntryKind {
    315     ENTRY_KIND_UNKNOWN,
    316     ENTRY_KIND_FOLDER,
    317     ENTRY_KIND_FILE
    318   };
    319   ResourceEntry();
    320   virtual ~ResourceEntry();
    321 
    322   // Extracts "entry" dictionary from the JSON value, and parse the contents,
    323   // using CreateFrom(). Returns NULL on failure. The input JSON data, coming
    324   // from the gdata server, looks like:
    325   //
    326   // {
    327   //   "encoding": "UTF-8",
    328   //   "entry": { ... },   // This function will extract this and parse.
    329   //   "version": "1.0"
    330   // }
    331   //
    332   // The caller should delete the returned object.
    333   static scoped_ptr<ResourceEntry> ExtractAndParse(const base::Value& value);
    334 
    335   // Creates resource entry from parsed JSON Value.  You should call
    336   // this instead of instantiating JSONValueConverter by yourself
    337   // because this method does some post-process for some fields.  See
    338   // FillRemainingFields comment and implementation for the details.
    339   static scoped_ptr<ResourceEntry> CreateFrom(const base::Value& value);
    340 
    341   // Returns name of entry node.
    342   static std::string GetEntryNodeName();
    343 
    344   // Registers the mapping between JSON field names and the members in
    345   // this class.
    346   static void RegisterJSONConverter(
    347       base::JSONValueConverter<ResourceEntry>* converter);
    348 
    349   // Sets true to |result| if the field exists.
    350   // Always returns true even when the field does not exist.
    351   static bool HasFieldPresent(const base::Value* value, bool* result);
    352 
    353   // Parses |value| as int64 and sets it to |result|. If the field does not
    354   // exist, sets 0 to |result| as default value.
    355   // Returns true if |value| is NULL or it is parsed as int64 successfully.
    356   static bool ParseChangestamp(const base::Value* value, int64* result);
    357 
    358   // The resource ID is used to identify a resource, which looks like:
    359   // file:d41d8cd98f00b204e9800998ecf8
    360   const std::string& resource_id() const { return resource_id_; }
    361 
    362   // This is a URL looks like:
    363   // https://docs.google.com/feeds/id/file%3Ad41d8cd98f00b204e9800998ecf8.
    364   // The URL is currently not used.
    365   const std::string& id() const { return id_; }
    366 
    367   ResourceEntryKind kind() const { return kind_; }
    368   const std::string& title() const { return title_; }
    369   base::Time published_time() const { return published_time_; }
    370   base::Time last_viewed_time() const { return last_viewed_time_; }
    371   const std::vector<std::string>& labels() const { return labels_; }
    372 
    373   // The URL to download a file content.
    374   // Search for 'download_url' in gdata_wapi_requests.h for details.
    375   const GURL& download_url() const { return content_.url(); }
    376 
    377   const std::string& content_mime_type() const { return content_.mime_type(); }
    378 
    379   // The resource links contain extra links for revisions and access control,
    380   // etc.  Note that links() contain more basic links like edit URL,
    381   // alternative URL, etc.
    382   const ScopedVector<ResourceLink>& resource_links() const {
    383     return resource_links_;
    384   }
    385 
    386   // File name (exists only for kinds FILE and PDF).
    387   const std::string& filename() const { return filename_; }
    388 
    389   // Suggested file name (exists only for kinds FILE and PDF).
    390   const std::string& suggested_filename() const { return suggested_filename_; }
    391 
    392   // File content MD5 (exists only for kinds FILE and PDF).
    393   const std::string& file_md5() const { return file_md5_; }
    394 
    395   // File size (exists only for kinds FILE and PDF).
    396   int64 file_size() const { return file_size_; }
    397 
    398   // True if the file or directory is deleted (applicable to change list only).
    399   bool deleted() const { return deleted_ || removed_; }
    400 
    401   // Changestamp (exists only for change query results).
    402   // If not exists, defaults to 0.
    403   int64 changestamp() const { return changestamp_; }
    404 
    405   // Image width (exists only for images).
    406   // If doesn't exist, then equals -1.
    407   int64 image_width() const { return image_width_; }
    408 
    409   // Image height (exists only for images).
    410   // If doesn't exist, then equals -1.
    411   int64 image_height() const { return image_height_; }
    412 
    413   // Image rotation in clockwise degrees (exists only for images).
    414   // If doesn't exist, then equals -1.
    415   int64 image_rotation() const { return image_rotation_; }
    416 
    417   // The time of this modification.
    418   // Note: This property is filled only when converted from ChangeResource.
    419   const base::Time& modification_date() const { return modification_date_; }
    420 
    421   // Text version of resource entry kind. Returns an empty string for
    422   // unknown entry kind.
    423   std::string GetEntryKindText() const;
    424 
    425   // True if resource entry is a folder (collection).
    426   bool is_folder() const {
    427     return kind_ == ENTRY_KIND_FOLDER;
    428   }
    429   // True if resource entry is regular file.
    430   bool is_file() const {
    431     return kind_ == ENTRY_KIND_FILE;
    432   }
    433 
    434   void set_resource_id(const std::string& resource_id) {
    435     resource_id_ = resource_id;
    436   }
    437   void set_id(const std::string& id) { id_ = id; }
    438   void set_kind(ResourceEntryKind kind) { kind_ = kind; }
    439   void set_title(const std::string& title) { title_ = title; }
    440   void set_published_time(const base::Time& published_time) {
    441     published_time_ = published_time;
    442   }
    443   void set_last_viewed_time(const base::Time& last_viewed_time) {
    444     last_viewed_time_ = last_viewed_time;
    445   }
    446   void set_labels(const std::vector<std::string>& labels) {
    447     labels_ = labels;
    448   }
    449   void set_content(const Content& content) {
    450     content_ = content;
    451   }
    452   void set_resource_links(ScopedVector<ResourceLink> resource_links) {
    453     resource_links_ = resource_links.Pass();
    454   }
    455   void set_filename(const std::string& filename) { filename_ = filename; }
    456   void set_suggested_filename(const std::string& suggested_filename) {
    457     suggested_filename_ = suggested_filename;
    458   }
    459   void set_file_md5(const std::string& file_md5) { file_md5_ = file_md5; }
    460   void set_file_size(int64 file_size) { file_size_ = file_size; }
    461   void set_deleted(bool deleted) { deleted_ = deleted; }
    462   void set_removed(bool removed) { removed_ = removed; }
    463   void set_changestamp(int64 changestamp) { changestamp_ = changestamp; }
    464   void set_image_width(int64 image_width) { image_width_ = image_width; }
    465   void set_image_height(int64 image_height) { image_height_ = image_height; }
    466   void set_image_rotation(int64 image_rotation) {
    467     image_rotation_ = image_rotation;
    468   }
    469   void set_modification_date(const base::Time& modification_date) {
    470     modification_date_ = modification_date;
    471   }
    472 
    473   // Fills the remaining fields where JSONValueConverter cannot catch.
    474   // Currently, sets |kind_| and |labels_| based on the |categories_| in the
    475   // class.
    476   void FillRemainingFields();
    477 
    478  private:
    479   friend class base::internal::RepeatedMessageConverter<ResourceEntry>;
    480   friend class ResourceList;
    481   friend class ResumeUploadRequest;
    482 
    483   // Converts categories.term into ResourceEntryKind enum.
    484   static ResourceEntryKind GetEntryKindFromTerm(const std::string& term);
    485 
    486   std::string resource_id_;
    487   std::string id_;
    488   ResourceEntryKind kind_;
    489   std::string title_;
    490   base::Time published_time_;
    491   // Last viewed value may be unreliable. See: crbug.com/152628.
    492   base::Time last_viewed_time_;
    493   std::vector<std::string> labels_;
    494   Content content_;
    495   ScopedVector<ResourceLink> resource_links_;
    496   // Optional fields for files only.
    497   std::string filename_;
    498   std::string suggested_filename_;
    499   std::string file_md5_;
    500   int64 file_size_;
    501   bool deleted_;
    502   bool removed_;
    503   int64 changestamp_;
    504   int64 image_width_;
    505   int64 image_height_;
    506   int64 image_rotation_;
    507 
    508   base::Time modification_date_;
    509 
    510   DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
    511 };
    512 
    513 // This class represents a list of resource entries with some extra metadata
    514 // such as the root upload URL. The feed is paginated and the rest of the
    515 // feed can be fetched by retrieving the remaining parts of the feed from
    516 // URLs provided by GetNextFeedURL() method.
    517 class ResourceList : public CommonMetadata {
    518  public:
    519   ResourceList();
    520   virtual ~ResourceList();
    521 
    522   // Extracts "feed" dictionary from the JSON value, and parse the contents,
    523   // using CreateFrom(). Returns NULL on failure. The input JSON data, coming
    524   // from the gdata server, looks like:
    525   //
    526   // {
    527   //   "encoding": "UTF-8",
    528   //   "feed": { ... },   // This function will extract this and parse.
    529   //   "version": "1.0"
    530   // }
    531   static scoped_ptr<ResourceList> ExtractAndParse(const base::Value& value);
    532 
    533   // Creates feed from parsed JSON Value.  You should call this
    534   // instead of instantiating JSONValueConverter by yourself because
    535   // this method does some post-process for some fields.  See
    536   // FillRemainingFields comment and implementation in ResourceEntry
    537   // class for the details.
    538   static scoped_ptr<ResourceList> CreateFrom(const base::Value& value);
    539 
    540   // Registers the mapping between JSON field names and the members in
    541   // this class.
    542   static void RegisterJSONConverter(
    543       base::JSONValueConverter<ResourceList>* converter);
    544 
    545   // Returns true and passes|url| of the next feed if the current entry list
    546   // does not completed this feed.
    547   bool GetNextFeedURL(GURL* url) const;
    548 
    549   // List of resource entries.
    550   const ScopedVector<ResourceEntry>& entries() const { return entries_; }
    551   ScopedVector<ResourceEntry>* mutable_entries() { return &entries_; }
    552 
    553   // Releases entries_ into |entries|. This is a transfer of ownership, so the
    554   // caller is responsible for deleting the elements of |entries|.
    555   void ReleaseEntries(std::vector<ResourceEntry*>* entries);
    556 
    557   // Start index of the resource entry list.
    558   int start_index() const { return start_index_; }
    559 
    560   // Number of items per feed of the resource entry list.
    561   int items_per_page() const { return items_per_page_; }
    562 
    563   // The largest changestamp. Next time the resource list should be fetched
    564   // from this changestamp.
    565   int64 largest_changestamp() const { return largest_changestamp_; }
    566 
    567   // Resource entry list title.
    568   const std::string& title() { return title_; }
    569 
    570   void set_entries(ScopedVector<ResourceEntry> entries) {
    571     entries_ = entries.Pass();
    572   }
    573   void set_start_index(int start_index) {
    574     start_index_ = start_index;
    575   }
    576   void set_items_per_page(int items_per_page) {
    577     items_per_page_ = items_per_page;
    578   }
    579   void set_title(const std::string& title) {
    580     title_ = title;
    581   }
    582   void set_largest_changestamp(int64 largest_changestamp) {
    583     largest_changestamp_ = largest_changestamp;
    584   }
    585 
    586  private:
    587   // Parses and initializes data members from content of |value|.
    588   // Return false if parsing fails.
    589   bool Parse(const base::Value& value);
    590 
    591   ScopedVector<ResourceEntry> entries_;
    592   int start_index_;
    593   int items_per_page_;
    594   std::string title_;
    595   int64 largest_changestamp_;
    596 
    597   DISALLOW_COPY_AND_ASSIGN(ResourceList);
    598 };
    599 
    600 }  // namespace google_apis
    601 
    602 #endif  // GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_
    603