Home | History | Annotate | Download | only in core
      1 // Copyright 2014 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 "components/dom_distiller/core/distilled_content_store.h"
      6 
      7 #include "base/message_loop/message_loop.h"
      8 
      9 namespace dom_distiller {
     10 
     11 InMemoryContentStore::InMemoryContentStore(const int max_num_entries)
     12     : cache_(max_num_entries, CacheDeletor(this)) {
     13 }
     14 
     15 InMemoryContentStore::~InMemoryContentStore() {
     16   // Clear the cache before destruction to ensure the CacheDeletor is not called
     17   // after InMemoryContentStore has been destroyed.
     18   cache_.Clear();
     19 }
     20 
     21 void InMemoryContentStore::SaveContent(
     22     const ArticleEntry& entry,
     23     const DistilledArticleProto& proto,
     24     InMemoryContentStore::SaveCallback callback) {
     25   InjectContent(entry, proto);
     26   if (!callback.is_null()) {
     27     base::MessageLoop::current()->PostTask(FROM_HERE,
     28                                            base::Bind(callback, true));
     29   }
     30 }
     31 
     32 void InMemoryContentStore::LoadContent(
     33     const ArticleEntry& entry,
     34     InMemoryContentStore::LoadCallback callback) {
     35   if (callback.is_null())
     36     return;
     37 
     38   ContentMap::const_iterator it = cache_.Get(entry.entry_id());
     39   bool success = it != cache_.end();
     40   if (!success) {
     41     // Could not find article by entry ID, so try looking it up by URL.
     42     for (int i = 0; i < entry.pages_size(); ++i) {
     43       UrlMap::const_iterator url_it = url_to_id_.find(entry.pages(i).url());
     44       if (url_it != url_to_id_.end()) {
     45         it = cache_.Get(url_it->second);
     46         success = it != cache_.end();
     47         if (success) {
     48           break;
     49         }
     50       }
     51     }
     52   }
     53   scoped_ptr<DistilledArticleProto> distilled_article;
     54   if (success) {
     55     distilled_article.reset(new DistilledArticleProto(it->second));
     56   } else {
     57     distilled_article.reset(new DistilledArticleProto());
     58   }
     59   base::MessageLoop::current()->PostTask(
     60       FROM_HERE,
     61       base::Bind(callback, success, base::Passed(&distilled_article)));
     62 }
     63 
     64 void InMemoryContentStore::InjectContent(const ArticleEntry& entry,
     65                                          const DistilledArticleProto& proto) {
     66   cache_.Put(entry.entry_id(), proto);
     67   AddUrlToIdMapping(entry, proto);
     68 }
     69 
     70 void InMemoryContentStore::AddUrlToIdMapping(
     71     const ArticleEntry& entry,
     72     const DistilledArticleProto& proto) {
     73   for (int i = 0; i < proto.pages_size(); i++) {
     74     const DistilledPageProto& page = proto.pages(i);
     75     if (page.has_url()) {
     76       url_to_id_[page.url()] = entry.entry_id();
     77     }
     78   }
     79 }
     80 
     81 void InMemoryContentStore::EraseUrlToIdMapping(
     82     const DistilledArticleProto& proto) {
     83   for (int i = 0; i < proto.pages_size(); i++) {
     84     const DistilledPageProto& page = proto.pages(i);
     85     if (page.has_url()) {
     86       url_to_id_.erase(page.url());
     87     }
     88   }
     89 }
     90 
     91 InMemoryContentStore::CacheDeletor::CacheDeletor(InMemoryContentStore* store)
     92     : store_(store) {
     93 }
     94 
     95 InMemoryContentStore::CacheDeletor::~CacheDeletor() {
     96 }
     97 
     98 void InMemoryContentStore::CacheDeletor::operator()(
     99     const DistilledArticleProto& proto) {
    100   // When InMemoryContentStore is deleted, the |store_| pointer becomes invalid,
    101   // but since the ContentMap is cleared in the InMemoryContentStore destructor,
    102   // this should never be called after the destructor.
    103   store_->EraseUrlToIdMapping(proto);
    104 }
    105 
    106 }  // namespace dom_distiller
    107