Advertisement
ujiajah1

adapter_modifying.cc / master

May 28th, 2016
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.52 KB | None | 0 0
  1. #include "sample.h"
  2. #include <iostream>
  3. #include <libecap/common/registry.h>
  4. #include <libecap/common/errors.h>
  5. #include <libecap/common/message.h>
  6. #include <libecap/common/header.h>
  7. #include <libecap/common/names.h>
  8. #include <libecap/common/named_values.h>
  9. #include <libecap/host/host.h>
  10. #include <libecap/adapter/service.h>
  11. #include <libecap/adapter/xaction.h>
  12. #include <libecap/host/xaction.h>
  13.  
  14. namespace Adapter { // not required, but adds clarity
  15.  
  16. using libecap::size_type;
  17.  
  18. class Service: public libecap::adapter::Service {
  19.     public:
  20.         // About
  21.         virtual std::string uri() const; // unique across all vendors
  22.         virtual std::string tag() const; // changes with version and config
  23.         virtual void describe(std::ostream &os) const; // free-format info
  24.  
  25.         // Configuration
  26.         virtual void configure(const libecap::Options &cfg);
  27.         virtual void reconfigure(const libecap::Options &cfg);
  28.         void setOne(const libecap::Name &name, const libecap::Area &valArea);
  29.  
  30.         // Lifecycle
  31.         virtual void start(); // expect makeXaction() calls
  32.         virtual void stop(); // no more makeXaction() calls until start()
  33.         virtual void retire(); // no more makeXaction() calls
  34.  
  35.         // Scope (XXX: this may be changed to look at the whole header)
  36.         virtual bool wantsUrl(const char *url) const;
  37.  
  38.         // Work
  39.         virtual libecap::adapter::Xaction *makeXaction(libecap::host::Xaction *hostx);
  40.  
  41.     public:
  42.         // Configuration storage
  43.         std::string victim; // the text we want to replace
  44.         std::string replacement; // what the replace the victim with
  45.  
  46.     protected:
  47.         void setVictim(const std::string &value);
  48. };
  49.  
  50.  
  51. // Calls Service::setOne() for each host-provided configuration option.
  52. // See Service::configure().
  53. class Cfgtor: public libecap::NamedValueVisitor {
  54.     public:
  55.         Cfgtor(Service &aSvc): svc(aSvc) {}
  56.         virtual void visit(const libecap::Name &name, const libecap::Area &value) {
  57.             svc.setOne(name, value);
  58.         }
  59.         Service &svc;
  60. };
  61.  
  62.  
  63. class Xaction: public libecap::adapter::Xaction {
  64.     public:
  65.         Xaction(libecap::shared_ptr<Service> s, libecap::host::Xaction *x);
  66.         virtual ~Xaction();
  67.  
  68.         // meta-information for the host transaction
  69.         virtual const libecap::Area option(const libecap::Name &name) const;
  70.         virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const;
  71.  
  72.         // lifecycle
  73.         virtual void start();
  74.         virtual void stop();
  75.  
  76.         // adapted body transmission control
  77.         virtual void abDiscard();
  78.         virtual void abMake();
  79.         virtual void abMakeMore();
  80.         virtual void abStopMaking();
  81.  
  82.         // adapted body content extraction and consumption
  83.         virtual libecap::Area abContent(size_type offset, size_type size);
  84.         virtual void abContentShift(size_type size);
  85.  
  86.         // virgin body state notification
  87.         virtual void noteVbContentDone(bool atEnd);
  88.         virtual void noteVbContentAvailable();
  89.  
  90.         // libecap::Callable API, via libecap::host::Xaction
  91.         virtual bool callable() const;
  92.  
  93.     protected:
  94.         void adaptContent(std::string &chunk) const; // converts vb to ab
  95.         void stopVb(); // stops receiving vb (if we are receiving it)
  96.         libecap::host::Xaction *lastHostCall(); // clears hostx
  97.  
  98.     private:
  99.         libecap::shared_ptr<const Service> service; // configuration access
  100.         libecap::host::Xaction *hostx; // Host transaction rep
  101.  
  102.         std::string buffer; // for content adaptation
  103.  
  104.         typedef enum { opUndecided, opOn, opComplete, opNever } OperationState;
  105.         OperationState receivingVb;
  106.         OperationState sendingAb;
  107. };
  108.  
  109. static const std::string CfgErrorPrefix =
  110.     "Modifying Adapter: configuration error: ";
  111.  
  112. } // namespace Adapter
  113.  
  114. std::string Adapter::Service::uri() const {
  115.     return "ecap://e-cap.org/ecap/services/sample/modifying";
  116. }
  117.  
  118. std::string Adapter::Service::tag() const {
  119.     return PACKAGE_VERSION;
  120. }
  121.  
  122. void Adapter::Service::describe(std::ostream &os) const {
  123.     os << "A modifying adapter from " << PACKAGE_NAME << " v" << PACKAGE_VERSION;
  124. }
  125.  
  126. void Adapter::Service::configure(const libecap::Options &cfg) {
  127.     Cfgtor cfgtor(*this);
  128.     cfg.visitEachOption(cfgtor);
  129.  
  130.     // check for post-configuration errors and inconsistencies
  131.  
  132.     if (victim.empty()) {
  133.         throw libecap::TextException(CfgErrorPrefix +
  134.             "victim value is not set");
  135.     }
  136. }
  137.  
  138. void Adapter::Service::reconfigure(const libecap::Options &cfg) {
  139.     victim.clear();
  140.     replacement.clear();
  141.     configure(cfg);
  142. }
  143.  
  144. void Adapter::Service::setOne(const libecap::Name &name, const libecap::Area &valArea) {
  145.     const std::string value = valArea.toString();
  146.     if (name == "victim")
  147.         setVictim(value);
  148.     else
  149.     if (name == "replacement")
  150.         replacement = value; // no checks needed, even an empty value is OK
  151.     else
  152.     if (name.assignedHostId())
  153.         ; // skip host-standard options we do not know or care about
  154.     else
  155.         throw libecap::TextException(CfgErrorPrefix +
  156.             "unsupported configuration parameter: " + name.image());
  157. }
  158.  
  159. void Adapter::Service::setVictim(const std::string &value) {
  160.     if (value.empty()) {
  161.         throw libecap::TextException(CfgErrorPrefix +
  162.             "empty victim value is not allowed");
  163.     }
  164.     victim = value;
  165. }
  166.  
  167. void Adapter::Service::start() {
  168.     libecap::adapter::Service::start();
  169.     // custom code would go here, but this service does not have one
  170. }
  171.  
  172. void Adapter::Service::stop() {
  173.     // custom code would go here, but this service does not have one
  174.     libecap::adapter::Service::stop();
  175. }
  176.  
  177. void Adapter::Service::retire() {
  178.     // custom code would go here, but this service does not have one
  179.     libecap::adapter::Service::stop();
  180. }
  181.  
  182. bool Adapter::Service::wantsUrl(const char *url) const {
  183.     return true; // no-op is applied to all messages
  184. }
  185.  
  186. libecap::adapter::Xaction *Adapter::Service::makeXaction(libecap::host::Xaction *hostx) {
  187.     return new Adapter::Xaction(std::tr1::static_pointer_cast<Service>(self),
  188.         hostx);
  189. }
  190.  
  191.  
  192. Adapter::Xaction::Xaction(libecap::shared_ptr<Service> aService,
  193.     libecap::host::Xaction *x):
  194.     service(aService),
  195.     hostx(x),
  196.     receivingVb(opUndecided), sendingAb(opUndecided) {
  197. }
  198.  
  199. Adapter::Xaction::~Xaction() {
  200.     if (libecap::host::Xaction *x = hostx) {
  201.         hostx = 0;
  202.         x->adaptationAborted();
  203.     }
  204. }
  205.  
  206. const libecap::Area Adapter::Xaction::option(const libecap::Name &) const {
  207.     return libecap::Area(); // this transaction has no meta-information
  208. }
  209.  
  210. void Adapter::Xaction::visitEachOption(libecap::NamedValueVisitor &) const {
  211.     // this transaction has no meta-information to pass to the visitor
  212. }
  213.  
  214. void Adapter::Xaction::start() {
  215.     Must(hostx);
  216.     if (hostx->virgin().body()) {
  217.         receivingVb = opOn;
  218.         hostx->vbMake(); // ask host to supply virgin body
  219.     } else {
  220.         // we are not interested in vb if there is not one
  221.         receivingVb = opNever;
  222.     }
  223.  
  224.     /* adapt message header */
  225.  
  226.     libecap::shared_ptr<libecap::Message> adapted = hostx->virgin().clone();
  227.     Must(adapted != 0);
  228.  
  229.     // delete ContentLength header because we may change the length
  230.     // unknown length may have performance implications for the host
  231.     adapted->header().removeAny(libecap::headerContentLength);
  232.  
  233.     // add a custom header
  234.     static const libecap::Name name("X-Ecap");
  235.     const libecap::Header::Value value =
  236.         libecap::Area::FromTempString(libecap::MyHost().uri());
  237.     adapted->header().add(name, value);
  238.  
  239.     if (!adapted->body()) {
  240.         sendingAb = opNever; // there is nothing to send
  241.         lastHostCall()->useAdapted(adapted);
  242.     } else {
  243.         hostx->useAdapted(adapted);
  244.     }
  245. }
  246.  
  247. void Adapter::Xaction::stop() {
  248.     hostx = 0;
  249.     // the caller will delete
  250. }
  251.  
  252. void Adapter::Xaction::abDiscard()
  253. {
  254.     Must(sendingAb == opUndecided); // have not started yet
  255.     sendingAb = opNever;
  256.     // we do not need more vb if the host is not interested in ab
  257.     stopVb();
  258. }
  259.  
  260. void Adapter::Xaction::abMake()
  261. {
  262.     Must(sendingAb == opUndecided); // have not yet started or decided not to send
  263.     Must(hostx->virgin().body()); // that is our only source of ab content
  264.  
  265.     // we are or were receiving vb
  266.     Must(receivingVb == opOn || receivingVb == opComplete);
  267.    
  268.     sendingAb = opOn;
  269.     if (!buffer.empty())
  270.         hostx->noteAbContentAvailable();
  271. }
  272.  
  273. void Adapter::Xaction::abMakeMore()
  274. {
  275.     Must(receivingVb == opOn); // a precondition for receiving more vb
  276.     hostx->vbMakeMore();
  277. }
  278.  
  279. void Adapter::Xaction::abStopMaking()
  280. {
  281.     sendingAb = opComplete;
  282.     // we do not need more vb if the host is not interested in more ab
  283.     stopVb();
  284. }
  285.  
  286.  
  287. libecap::Area Adapter::Xaction::abContent(size_type offset, size_type size) {
  288.     Must(sendingAb == opOn || sendingAb == opComplete);
  289.     return libecap::Area::FromTempString(buffer.substr(offset, size));
  290. }
  291.  
  292. void Adapter::Xaction::abContentShift(size_type size) {
  293.     Must(sendingAb == opOn || sendingAb == opComplete);
  294.     buffer.erase(0, size);
  295. }
  296.  
  297. void Adapter::Xaction::noteVbContentDone(bool atEnd)
  298. {
  299.     Must(receivingVb == opOn);
  300.     receivingVb = opComplete;
  301.     if (sendingAb == opOn) {
  302.         hostx->noteAbContentDone(atEnd);
  303.         sendingAb = opComplete;
  304.     }
  305. }
  306.  
  307. void Adapter::Xaction::noteVbContentAvailable()
  308. {
  309.     Must(receivingVb == opOn);
  310.  
  311.     const libecap::Area vb = hostx->vbContent(0, libecap::nsize); // get all vb
  312.     std::string chunk = vb.toString(); // expensive, but simple
  313.     hostx->vbContentShift(vb.size); // we have a copy; do not need vb any more
  314.     adaptContent(chunk);
  315.     buffer += chunk; // buffer what we got
  316.  
  317.     if (sendingAb == opOn)
  318.         hostx->noteAbContentAvailable();
  319. }
  320.  
  321. void Adapter::Xaction::adaptContent(std::string &chunk) const {
  322.     // this is oversimplified; production code should worry about arbitrary
  323.     // chunk boundaries, content encodings, service reconfigurations, etc.
  324.  
  325.     const std::string &victim = service->victim;
  326.     const std::string &replacement = service->replacement;
  327.  
  328.     std::string::size_type pos = 0;
  329.     while ((pos = chunk.find(victim, pos)) != std::string::npos) {
  330.         chunk.replace(pos, victim.length(), replacement);
  331.         pos += replacement.size();
  332.     }
  333. }
  334.  
  335. bool Adapter::Xaction::callable() const {
  336.     return hostx != 0; // no point to call us if we are done
  337. }
  338.  
  339. // tells the host that we are not interested in [more] vb
  340. // if the host does not know that already
  341. void Adapter::Xaction::stopVb() {
  342.     if (receivingVb == opOn) {
  343.         hostx->vbStopMaking();
  344.         receivingVb = opComplete;
  345.     } else {
  346.         // we already got the entire body or refused it earlier
  347.         Must(receivingVb != opUndecided);
  348.     }
  349. }
  350.  
  351. // this method is used to make the last call to hostx transaction
  352. // last call may delete adapter transaction if the host no longer needs it
  353. // TODO: replace with hostx-independent "done" method
  354. libecap::host::Xaction *Adapter::Xaction::lastHostCall() {
  355.     libecap::host::Xaction *x = hostx;
  356.     Must(x);
  357.     hostx = 0;
  358.     return x;
  359. }
  360.  
  361. // create the adapter and register with libecap to reach the host application
  362. static const bool Registered = (libecap::RegisterService(new Adapter::Service), true);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement