#ifndef OCTOPUS_CLASS #define OCTOPUS_CLASS /*****************************************************************************\ * * * Name : octopus * * Author : Chris Koeritz * * * ******************************************************************************* * Copyright (c) 2001-$now By Author. This program is free software; you can * * redistribute it and/or modify it under the terms of the GNU General Public * * License as published by the Free Software Foundation; either version 2 of * * the License or (at your option) any later version. This is online at: * * http://www.fsf.org/copyleft/gpl.html * * Please send any updates to: fred@gruntose.com * \*****************************************************************************/ #include #include #include #include #include namespace octopi { // forward. class entity_data_bin; class filter_list; class infoton; class modula_oblongata; class octopus_entity; class octopus_request_id; class tentacle; //! Octopus is a design pattern for generalized request processing systems. /*! Octopus is a plug-in module manager that can serve as the base for highly extensible program architectures. Each module is called a tentacle, following the conceit of the naming conventions, and it services one type of request. The requests come in the form of infoton objects, where the tentacle that handles each class of infotons is uniquely identifiable. Note that the outcomes returned here are from the tentacle's set of outcomes. */ class octopus : public virtual basis::root_object { public: octopus(const basis::astring &name, int max_size_per_entity); //!< constructs an octopus named "name". /*!< the "name" string identifies the arena where this octopus is running. this could be a network host or other identification string. the "max_size_per_entity" is the largest that we allow one entity's bin of pending data to be. this should be quite large if massive transactions need to be processed. */ virtual ~octopus(); DEFINE_CLASS_NAME("octopus"); const basis::astring &name() const; //!< returns the name that the octopus was constructed with. // tentacle management functions... basis::outcome add_tentacle(tentacle *to_add, bool filter = false); //!< hooks a tentacle in to provide processing of one type of infoton. /*!< lists the tentacle "to_add" as being responsible for handling requests for the tentacle's group(). note that the octopus takes over control of the "to_add" pointer; do not destroy that pointer independently, and do not use the tentacle after adding it to the octopus unless the tentacle is thread-safe. the add will replace an existing tentacle if it was already registered under the same group name. if the "filter" flag is enabled, then this tentacle is considered a filter; it will be consulted on all infotons before they are processed. filters will be invoked in the order that they are added. */ basis::outcome remove_tentacle(const structures::string_array &group_name, tentacle * &free_me); //!< removes the tentacle listed for the "group_name", if any. /*!< "free_me" provides the means for getting back what was originally registered. NOTE: remember to destroy "free_me" if that's appropriate (i.e. it was dynamically allocated, has no other users and no other entity has responsibility for it). */ basis::outcome zap_tentacle(const structures::string_array &group_name); //!< similar to remove_tentacle(), but destroys the tentacle. // entity management methods... octopus_entity issue_identity(); //!< creates an entity identifier that is unique for this octopus. /*!< this provides a unique identity using the "name" specified in the constructor and the current process id. the sequence number and random add_in are generated by this class also. */ void expunge(const octopus_entity &to_remove); //!< invokes every tentacle's expunge() method on the id "to_remove". /*!< this indicates that the entity is no longer extant and resources held for it can be destroyed. */ entity_data_bin &responses(); //!< allows external access to our set of results. /*!< this should not be used unless you know what you're doing. */ // main functionality: restoring infotons, evaluating requests and // locating responses. basis::outcome restore(const structures::string_array &classifier, basis::byte_array &packed_form, infoton * &reformed); //!< regenerates a packed infoton given its classifier. /*!< locates the appropriate type of infoton with the "classifier" and consumes the bytes in "packed_form" to return a new version of the original data in "reformed", if possible. */ basis::outcome evaluate(infoton *request, const octopus_request_id &item_id, bool now = false); //!< tries to process the "request" using the current set of tentacles. /*!< if there is no group handler for the "request", then NO_HANDLER will be returned. the classifier for "request" specifies the group name for processing. NOTE: the octopus assumes all responsibility for the "request", even if the outcome denotes failure; do not touch the "request" after this call. if the "request" will be processed further by lower level octopi, then the classifier can be patched as appropriate. the "item_id" must be maintained with the request in order to identify the entity making the request and the sequence number of this particular request. the "now" parameter specifies whether the processing must occur immediately; if false, the processing will occur later when the tentacle get around to it. if "now" is true, there is more load on the octopus itself. note that "now" is ignored if the tentacle does not support backgrounding; true is always assumed for that case. */ infoton *acquire_result(const octopus_entity &requester, octopus_request_id &original_id); //!< acquires responses to previous requests if there are any waiting. /*!< it returns an infoton for the "requester", if any are available. call this function repeatedly to ensure that all responses have been provided. the "original_id" is a copy of the "item_id" that was originally passed to evaluate_request(). the returned object must eventually be destroyed if non-null. */ infoton *acquire_specific_result(const octopus_request_id &original_id); //!< supports seeking the result for a specific request. /*!< either the infoton that is a response to "original_id" will be returned or NULL_POINTER. */ ////////////// // tentacle accessors: careful with these--you must always unlock after // you have locked. tentacle *lock_tentacle(const structures::string_array &tentacle_name); //!< locates the tentacle with the "tentacle_name" and returns it. /*!< the octopus will stay locked until the unlock_tentacle() method is invoked. */ void unlock_tentacle(tentacle *to_unlock); //!< unlocks the octopus when given a previously locked tentacle. /*!< this must be the same object that was obtained via the lock_tentacle() method. */ void lock_tentacles(); //!< locks the tentacle list for use with locked_get_tentacle. // the following are only valid if the tentacle list is locked. int locked_tentacle_count(); //!< number of tentacles. tentacle *locked_get_tentacle(int indy); //!< access indy'th tentacle. void unlock_tentacles(); //!< unlocks the list. ////////////// // used internally; don't mess with externally. void periodic_cleaning(); //!< flushes any abandoned data from the response bin. private: basis::astring *_name; //!< our name as passed to the constructor. modula_oblongata *_tentacles; //!< the list of tentacles. basis::mutex *_molock; //!< the synchronizer for our tentacle list. entity_data_bin *_responses; //!< data awaiting pickup by requester. int _disallow_removals; //!< simplifies locking behavior for immediate requests. /*!< we set this flag and don't need to lock the whole octopus. if it's non-zero, then no tentacles can be removed yet. */ timely::time_stamp *_next_cleaning; //!< when we'll next flush old items. basis::mutex *_clean_lock; //!< used only to protect the time stamp above. filter_list *_filters; //!< the filters that must vet infotons. processes::safe_roller *_sequencer; //!< identity issue; this is the next entity id. mathematics::chaos *_rando; //!< randomizer for providing extra uniquification. // not accessible. octopus(const octopus &); octopus &operator =(const octopus &); }; } //namespace. #endif