Parcourir la source

[2974] Created CalloutManager

The LibraryHandleCollection, as a result of comments, has morphed
into the general class for handling callouts.  This commit reflects
that change.
Stephen Morris il y a 12 ans
Parent
commit
71376fdfd9

+ 2 - 2
src/lib/util/Makefile.am

@@ -37,8 +37,8 @@ libb10_util_la_SOURCES += encode/base32hex_from_binary.h
 libb10_util_la_SOURCES += encode/base_n.cc encode/hex.h
 libb10_util_la_SOURCES += encode/binary_from_base32hex.h
 libb10_util_la_SOURCES += encode/binary_from_base16.h
-libb10_util_la_SOURCES += hooks/callout_handle.h hooks/callout_handle.cc
-libb10_util_la_SOURCES += hooks/library_handle.h hooks/library_handle.cc
+libb10_util_la_SOURCES += hooks/callout_manager.h hooks/callout_manager.cc
+# libb10_util_la_SOURCES += hooks/callout_handle.h hooks/callout_handle.cc
 libb10_util_la_SOURCES += hooks/server_hooks.h hooks/server_hooks.cc
 libb10_util_la_SOURCES += random/qid_gen.h random/qid_gen.cc
 libb10_util_la_SOURCES += random/random_number_generator.h

+ 6 - 7
src/lib/util/hooks/callout_handle.h

@@ -73,8 +73,8 @@ public:
 
 // Forward declaration of the library handle and related collection classes.
 
+class CalloutManager;
 class LibraryHandle;
-class LibraryHandleCollection;
 
 /// @brief Per-packet callout handle
 ///
@@ -135,13 +135,13 @@ public:
     /// Creates the object and calls the callouts on the "context_create"
     /// hook.
     ///
-    /// @param manager Pointer to the collection of library handles.
-    CalloutHandle(boost::shared_ptr<LibraryHandleCollection>& collection);
+    /// @param manager Pointer to the callout manager object.
+    CalloutHandle(boost::shared_ptr<CalloutManager>& /* manager */) {}
 
     /// @brief Destructor
     ///
     /// Calls the context_destroy callback to release any per-packet context.
-    ~CalloutHandle();
+    ~CalloutHandle() {}
 
     /// @brief Set argument
     ///
@@ -364,9 +364,8 @@ private:
     /// Context collection - there is one entry per library context.
     ContextCollection context_collection_;
 
-    /// Library handle collection, used to obtain the correct library handle
-    /// during a call to a callout.
-    boost::shared_ptr<LibraryHandleCollection> library_collection_;
+    /// Callout manager.
+    boost::shared_ptr<CalloutManager> manager_;
 
     /// "Skip" flag, indicating if the caller should bypass remaining callouts.
     bool skip_;

+ 195 - 0
src/lib/util/hooks/callout_manager.cc

@@ -0,0 +1,195 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <util/hooks/callout_handle.h>
+#include <util/hooks/callout_manager.h>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+using namespace std;
+using namespace isc::util;
+
+namespace isc {
+namespace util {
+
+// Callout manipulation - all deferred to the CalloutManager.
+
+void
+LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
+    callout_manager_->registerCallout(library_index_, name, callout);
+}
+
+bool
+LibraryHandle::deregisterCallout(const std::string& name, CalloutPtr callout) {
+    return (callout_manager_->deregisterCallout(library_index_, name, callout));
+}
+
+bool
+LibraryHandle::deregisterAllCallouts(const std::string& name) {
+    return (callout_manager_->deregisterAllCallouts(library_index_, name));
+}
+
+// Register a callout for a particular library.
+
+void
+CalloutManager::registerCallout(int libindex, const std::string& name,
+                                CalloutPtr callout) {
+    // Get the index associated with this hook (validating the name in the
+    // process).
+    int hook_index = hooks_->getIndex(name);
+
+    // Iterate through the callout vector for the hook from start to end,
+    // looking for the first entry where the library index is greater than
+    // the present index.
+    for (CalloutVector::iterator i = hook_vector_[hook_index].begin();
+         i != hook_vector_[hook_index].end(); ++i) {
+        if (i->first > libindex) {
+            // Found an element whose library number is greater than ours,
+            // so insert the new element ahead of this one.
+            hook_vector_[hook_index].insert(i,
+                                            std::make_pair(libindex, callout));
+            return;
+        }
+    }
+
+    // Reach the end of the vector, so no element in the (possibly empty)
+    // set of callouts with a library index greater that the one related to
+    // this callout, insert at the end.
+    hook_vector_[hook_index].push_back(std::make_pair(libindex, callout));
+}
+
+
+// Check if callouts are present for a given hook index.
+
+bool
+CalloutManager::calloutsPresent(int hook_index) const {
+    // Validate the hook index.
+    checkHookIndex(hook_index);
+
+    // Valid, so are there any callouts associated with that hook?
+    return (!hook_vector_[hook_index].empty());
+}
+
+// Call all the callouts for a given hook.
+
+int
+CalloutManager::callCallouts(int hook_index, CalloutHandle& callout_handle) {
+    // Validate the hook index.
+    checkHookIndex(hook_index);
+
+    // Clear the "skip" flag so we don't carry state from a previous
+    // call.
+    callout_handle.setSkip(false);
+
+    // Call all the callouts, stopping if the "skip" flag is set or if a
+    // non-zero status is returned.
+    int status = 0;
+    for (CalloutVector::const_iterator i = hook_vector_[hook_index].begin();
+         i != hook_vector_[hook_index].end() && (status == 0); ++i) {
+        status = (*i->second)(callout_handle);
+    }
+
+    return (status);
+}
+
+// Deregister a callout registered by a library on a particular hook.
+
+bool
+CalloutManager::deregisterCallout(int library_index, const std::string& name,
+                                  CalloutPtr callout) {
+
+    // Get the index associated with this hook (validating the name in the
+    // process).
+    int hook_index = hooks_->getIndex(name);
+
+    /// Construct a CalloutEntry matching the specified library and the callout
+    /// we want to remove.
+    CalloutEntry target(library_index, callout);
+
+    /// To decide if any entries were removed, we'll record the initial size
+    /// of the callout vector for the hook, and compare it with the size after
+    /// the removal.
+    size_t initial_size = hook_vector_[hook_index].size();
+
+    // The next bit is standard STL (see "Item 33" in "Effective STL" by
+    // Scott Meyers).
+    //
+    // remove_if reorders the hook vector so that all items not matching
+    // the predicate are at the start of the vector and returns a pointer
+    // to the next element. (In this case, the predicate is that the item
+    // is equal to the value of the passed callout.)  The erase() call
+    // removes everything from that element to the end of the vector, i.e.
+    // all the matching elements.
+    hook_vector_[hook_index].erase(remove_if(hook_vector_[hook_index].begin(),
+                                             hook_vector_[hook_index].end(),
+                                             bind1st(equal_to<CalloutEntry>(),
+                                                     target)),
+                                   hook_vector_[hook_index].end());
+
+    // Return an indication of whether anything was removed.
+    return (initial_size != hook_vector_[hook_index].size());
+}
+
+// Deregister all callouts on a given hook.
+
+bool
+CalloutManager::deregisterAllCallouts(int library_index,
+                                               const std::string& name) {
+
+    // Get the index associated with this hook (validating the name in the
+    // process).
+    int hook_index = hooks_->getIndex(name);
+
+    /// Construct a CalloutEntry matching the specified library we want to
+    /// remove (the callout pointer is NULL as we are not checking that).
+    CalloutEntry target(library_index, NULL);
+
+    /// To decide if any entries were removed, we'll record the initial size
+    /// of the callout vector for the hook, and compare it with the size after
+    /// the removal.
+    size_t initial_size = hook_vector_[hook_index].size();
+/*
+    // Remove all callouts matching this library.
+    hook_vector_[hook_index].erase(remove_if(hook_vector_[hook_index].begin(),
+                                             hook_vector_[hook_index].end(),
+                                             bind1st(CalloutLibraryEqual(),
+                                                     target)),
+                                   hook_vector_[hook_index].end());
+
+    // Return an indication of whether anything was removed. */
+    return (initial_size != hook_vector_[hook_index].size());
+}
+
+// CalloutManager methods.
+
+// Return pointer to the current library handle.
+
+boost::shared_ptr<LibraryHandle>
+CalloutManager::createHandle() {
+    // Index is equal to the size of the current collection of handles
+    // (guarantees that every handle has a unique index, and that index
+    // is a pointer to the handle in the collection of handles.)
+    boost::shared_ptr<LibraryHandle> handle(new LibraryHandle(handles_.size(),
+                                                              this));
+
+    // Add to the current collection of handles.
+    handles_.push_back(handle);
+
+    return (handle);
+}
+
+} // namespace util
+} // namespace isc

+ 315 - 0
src/lib/util/hooks/callout_manager.h

@@ -0,0 +1,315 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LIBRARY_HANDLE_H
+#define LIBRARY_HANDLE_H
+
+#include <exceptions/exceptions.h>
+#include <util/hooks/server_hooks.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <string>
+
+namespace isc {
+namespace util {
+
+/// @brief No Such Context
+///
+/// Thrown if an attempt is made to obtain context that has not been previously
+/// set.
+
+class NoSuchLibraryContext : public Exception {
+public:
+    NoSuchLibraryContext(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// @brief Invalid index
+///
+/// Thrown if an attempt is made to obtain a library handle but the current
+/// library handle index is invalid.  This will occur if the method
+/// CalloutManager::getHandleVector() is called outside of a callout.
+
+class InvalidIndex : public Exception {
+public:
+    InvalidIndex(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+// Forward declarations
+class CalloutHandle;
+class CalloutManager;
+
+/// Typedef for a callout pointer.  (Callouts must have "C" linkage.)
+extern "C" {
+    typedef int (*CalloutPtr)(CalloutHandle&);
+};
+
+
+
+
+/// @brief Library handle
+///
+/// This class is used to manage a loaded library.  It is used by the user
+/// library to register callouts.
+///
+/// The main processing is done by the CalloutManager class.  By
+/// presenting this object to the user-library callouts, they can manage the
+/// callout list for their own library, but cannot affect the callouts registered
+/// by other libraries.
+
+class LibraryHandle {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param hooks Library index.  A number (starting at 0) that represents
+    ///        the index of the library in the list of libraries loaded by the
+    ///        server.
+    /// @param collection Back pointer to the containing CalloutManager.
+    ///        This pointer is used to access appropriate methods in the collection
+    ///        object.
+    LibraryHandle(int library_index, CalloutManager* collection)
+        : library_index_(library_index), callout_manager_(collection)
+    {}
+
+    /// @brief Register a callout on a hook
+    ///
+    /// Registers a callout function with a given hook.  The callout is added
+    /// to the end of the callouts for this library that are associated with
+    /// that hook.
+    ///
+    /// @param name Name of the hook to which the callout is added.
+    /// @param callout Pointer to the callout function to be registered.
+    ///
+    /// @throw NoSuchHook The hook name is unrecognised.
+    /// @throw Unexpected The hook name is valid but an internal data structure
+    ///        is of the wrong size.
+    void registerCallout(const std::string& name, CalloutPtr callout);
+
+    /// @brief De-Register a callout on a hook
+    ///
+    /// Searches through the functions registered by this library with the named
+    /// hook and removes all entries matching the callout.  It does not affect
+    /// callouts registered by other libraries.
+    ///
+    /// @param name Name of the hook from which the callout is removed.
+    /// @param callout Pointer to the callout function to be removed.
+    ///
+    /// @return true if a one or more callouts were deregistered.
+    ///
+    /// @throw NoSuchHook The hook name is unrecognised.
+    /// @throw Unexpected The hook name is valid but an internal data structure
+    ///        is of the wrong size.
+    bool deregisterCallout(const std::string& name, CalloutPtr callout);
+
+    /// @brief Removes all callouts on a hook
+    ///
+    /// Removes all callouts associated with a given hook that were registered.
+    /// by this library.  It does not affect callouts that were registered by
+    /// other libraries.
+    ///
+    /// @param name Name of the hook from which the callouts are removed.
+    ///
+    /// @return true if one or more callouts were deregistered.
+    ///
+    /// @throw NoSuchHook Thrown if the hook name is unrecognised.
+    bool deregisterAllCallouts(const std::string& name);
+
+    /// @brief Return handle index
+    ///
+    /// For test purposes only, this returns the index allocated to this
+    /// LibraryHandle.
+    ///
+    /// @return Handle index
+    int getIndex() const {
+        return (library_index_);
+    }
+
+private:
+    /// Index of this handle in the library handle list
+    int library_index_;
+
+    /// Back pointer to the collection object for the library
+    CalloutManager* callout_manager_;
+};
+
+
+/// @brief Callout Manager
+///
+/// This class manages the registration, deregistration and execution of the
+/// library callouts.
+///
+/// It is constructed using a @ref isc::util::ServerHooks object that holds the
+/// list of hooks registered for the server, which it uses to create the
+/// hook vector.  This is a vector represting the callouts for each hook. Each
+/// element is itself a vector of callouts registered by the loaded libraries.
+///
+/// The class also holds the collection of library handles, used to allow the
+/// libraries to manipulate their callout list.
+
+class CalloutManager {
+private:
+
+    // Private typedefs
+
+    /// Vector of library handles.
+    typedef std::vector<boost::shared_ptr<LibraryHandle> > HandleVector;
+
+    /// Element in the vector of callouts.  The elements in the pair are the
+    /// library index and the pointer to the callout.
+    typedef std::pair<int, CalloutPtr> CalloutEntry;
+
+    /// Entry in the list of callouts for an individual hook.
+    typedef std::vector<CalloutEntry> CalloutVector;
+
+public:
+
+    /// @brief Constructor
+    ///
+    /// Initializes member variables, in particular sizing the hook vector
+    /// (the vector of callouts) to the appropriate size.
+    ///
+    /// @param hook Collection of known hook names.
+    CalloutManager(const boost::shared_ptr<ServerHooks>& hooks) :
+        hooks_(hooks), handles_(), hook_vector_(hooks->getCount())
+    {}
+
+    /// @brief Register a callout on a hook
+    ///
+    /// Registers a callout function for a particular library with a given hook.
+    /// The callout is added to the end of the callouts for this library that
+    /// are associated with that hook.
+    ///
+    /// @param libindex Index of the library registering the callout
+    /// @param name Name of the hook to which the callout is added.
+    /// @param callout Pointer to the callout function to be registered.
+    ///
+    /// @throw NoSuchHook The hook name is unrecognised.
+    /// @throw Unexpected The hook name is valid but an internal data structure
+    ///        is of the wrong size.
+    void registerCallout(int libindex, const std::string& name,
+                         CalloutPtr callout);
+
+    /// @brief De-Register a callout on a hook
+    ///
+    /// Searches through the functions registered by the specified library with
+    /// the named hook and removes all entries matching the callout.
+    ///
+    /// @param libindex Index of the library deregistering the callout
+    /// @param name Name of the hook from which the callout is removed.
+    /// @param callout Pointer to the callout function to be removed.
+    ///
+    /// @return true if a one or more callouts were deregistered.
+    ///
+    /// @throw NoSuchHook The hook name is unrecognised.
+    /// @throw Unexpected The hook name is valid but an internal data structure
+    ///        is of the wrong size.
+    bool deregisterCallout(int libindex, const std::string& name,
+                           CalloutPtr callout);
+
+    /// @brief Removes all callouts on a hook
+    ///
+    /// Removes all callouts associated with a given hook that were registered
+    /// by the specified library.
+    ///
+    /// @param libindex Index of the library deregistering the callouts
+    /// @param name Name of the hook from which the callouts are removed.
+    ///
+    /// @return true if one or more callouts were deregistered.
+    ///
+    /// @throw NoSuchHook Thrown if the hook name is unrecognised.
+    bool deregisterAllCallouts(int libindex, const std::string& name);
+
+    /// @brief Checks if callouts are present on a hook
+    ///
+    /// Checks all loaded libraries and returns true if at least one callout
+    /// has been registered by any of them for the given hook.
+    ///
+    /// @param index Hook index for which callouts are checked.
+    ///
+    /// @return true if callouts are present, false if not.
+    ///
+    /// @throw NoSuchHook Given index does not correspond to a valid hook.
+    bool calloutsPresent(int index) const;
+
+    /// @brief Calls the callouts for a given hook
+    ///
+    /// Iterates through the libray handles and calls the callouts associated
+    /// with the given hook index.
+    ///
+    /// @param index Index of the hook to call.
+    /// @param callout_handle Reference to the CalloutHandle object for the
+    ///        current object being processed.
+    ///
+    /// @return Status return.
+    int callCallouts(int index, CalloutHandle& callout_handle);
+
+
+    /// @brief Create library handle
+    ///
+    /// Creates a library handle.  The handle is used when loading a library in
+    /// that the callouts are associated with the given library and when calling
+    /// a callout: the handle for the library can be obtained to allow dynamic
+    /// registration and de-registration.
+    boost::shared_ptr<LibraryHandle> createHandle();
+
+private:
+    /// @brief Check hook index
+    ///
+    /// Ensures that the passed hook index is valid.
+    ///
+    /// @param index Hook index to test
+    ///
+    /// @throw NoSuchHook
+    void checkHookIndex(int hook_index) const {
+        if ((hook_index < 0) || (hook_index >= hook_vector_.size())) {
+            isc_throw(NoSuchHook, "hook index " << hook_index <<
+                      " is not valid for the list of registered hooks");
+        }
+    }
+
+    /// @brief Compare two callout entries for library equality
+    ///
+    /// This is used in callout removal code.
+    ///
+    /// @param ent1 First callout entry to check
+    /// @param ent2 Second callout entry to check
+    ///
+    /// @return bool true if the library entries are the same
+    class CalloutLibraryEqual {
+    public:
+        bool operator()(const CalloutEntry& ent1, const CalloutEntry& ent2) {
+            return (ent1.first == ent2.first);
+        }
+    };
+
+    /// List of server hooks.  This is used 
+    boost::shared_ptr<ServerHooks>  hooks_;
+
+    /// Vector of pointers to library handles.
+    HandleVector handles_;
+
+    /// Vector of callout vectors.  There is one entry in this outer vector for
+    /// each hook.
+    std::vector<CalloutVector>  hook_vector_;
+
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // LIBRARY_HANDLE_H

+ 0 - 187
src/lib/util/hooks/library_handle.cc

@@ -1,187 +0,0 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <util/hooks/callout_handle.h>
-#include <util/hooks/library_handle.h>
-
-#include <algorithm>
-#include <functional>
-
-using namespace std;
-using namespace isc::util;
-
-namespace isc {
-namespace util {
-
-// Check that an index is valid for the hook vector.
-
-void
-LibraryHandle::checkHookIndex(int index) const {
-    if ((index < 0) || (index >= hook_vector_.size())) {
-        isc_throw(NoSuchHook, "hook index " << index << " is invalid for the "
-                  " size of the hook vector (" << hook_vector_.size() << ")");
-    }
-}
-
-// Register a callout for a hook, adding it to run after any previously
-// registered callouts on that hook.
-
-void
-LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
-
-    // Get index of hook in the hook vector, validating the hook name as we
-    // do so.
-    int index = hooks_->getIndex(name);
-
-    // Index valid, so add the callout to the end of the list of callouts.
-    hook_vector_[index].push_back(callout);
-}
-
-// Check if callouts are present for a given hook index.
-
-bool
-LibraryHandle::calloutsPresent(int index) const {
-    // Validate the hook index.
-    checkHookIndex(index);
-
-    // Valid, so are there any callouts associated with that hook?
-    return (!hook_vector_[index].empty());
-}
-
-// Call all the callouts for a given hook.
-
-int
-LibraryHandle::callCallouts(int index, CalloutHandle& callout_handle) {
-    // Validate the hook index.
-    checkHookIndex(index);
-
-    // Call all the callouts, stopping if the "skip" flag is set or if a
-    // non-zero status is returned.
-    int status = 0;
-    for (int i = 0;
-         (i < hook_vector_[index].size()) && !callout_handle.getSkip() &&
-         (status == 0);
-          ++i) {
-        status = (*hook_vector_[index][i])(callout_handle);
-    }
-
-    return (status);
-}
-
-// Deregister a callout on a given hook.
-
-void
-LibraryHandle::deregisterCallout(const std::string& name, CalloutPtr callout) {
-
-    // Get the index associated with this hook (validating the name in the
-    // process).
-    int index = hooks_->getIndex(name);
-
-    if (!hook_vector_[index].empty()) {
-        // The next bit is standard STL (see "Item 33" in "Effective STL" by
-        // Scott Meyers).
-        //
-        // remove_if reorders the hook vector so that all items not matching
-        // the predicate are at the start of the vector and returns a pointer
-        // to the next element. (In this case, the predicate is that the item
-        // is equal to the value of the passed callout.)  The erase() call
-        // removes everything from that element to the end of the vector, i.e.
-        // all the matching elements.
-        hook_vector_[index].erase(remove_if(hook_vector_[index].begin(),
-                                            hook_vector_[index].end(),
-                                            bind1st(equal_to<CalloutPtr>(),
-                                                    callout)),
-                                  hook_vector_[index].end());
-    }
-}
-
-// Deregister all callouts on a given hook.
-
-void
-LibraryHandle::deregisterAll(const std::string& name) {
-
-    // Get the index associated with this hook (validating the name in the
-    // process).
-    int index = hooks_->getIndex(name);
-
-    // Get rid of everything.
-    hook_vector_[index].clear();
-}
-
-// LibraryHandleCollection methods.
-
-// Return pointer to the current library handle.
-
-boost::shared_ptr<LibraryHandle>
-LibraryHandleCollection::getLibraryHandle() const {
-    if ((curidx_ < 0) || (curidx_ >= handles_.size())) {
-        isc_throw(InvalidIndex, "current library handle index of (" <<
-                  curidx_ << ") is not valid for the library handle vector "
-                  "(size = " << handles_.size() << ")");
-    }
-
-    return (handles_[curidx_]);
-}
-
-// Check if a any of the libraries have at least one callout present on a given
-// hook.
-
-bool
-LibraryHandleCollection::calloutsPresent(int index) const {
-
-    // Method returns false if no LibraryHandles are present.  Otherwise,
-    // the validity of the index is checked by the calloutsPresent() method
-    // on the first handle processed.
-    bool present = false;
-    for (int i = 0; (i < handles_.size()) && !present; ++i) {
-        present = handles_[i]->calloutsPresent(index);
-    }
-
-    return (present);
-}
-
-// Call all the callouts for a given hook.
-
-int
-LibraryHandleCollection::callCallouts(int index,
-                                      CalloutHandle& callout_handle) {
-
-    // Don't validate the hook index here as it is checked in the call to the
-    // callCallouts() method of the first library handle.
-
-    // Clear the skip flag before we start so that no state from a previous
-    // call of a hook accidentally leaks through.
-    callout_handle.setSkip(false);
-
-    // Call all the callouts, stopping if the "skip" flag is set or if a
-    // non-zero status is returned.  Note that we iterate using the current
-    // index as the counter to allow callout handle object to retrieve the
-    // current LibraryHandle.
-    int status = 0;
-    for (curidx_ = 0;
-         (curidx_ < handles_.size()) && !callout_handle.getSkip() &&
-         (status == 0);
-         ++curidx_) {
-        status = handles_[curidx_]->callCallouts(index, callout_handle);
-    }
-
-    // Reset current index to an invalid value as we are no longer calling
-    // the callouts.
-    curidx_ = -1;
-
-    return (status);
-}
-
-} // namespace util
-} // namespace isc

+ 0 - 264
src/lib/util/hooks/library_handle.h

@@ -1,264 +0,0 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef LIBRARY_HANDLE_H
-#define LIBRARY_HANDLE_H
-
-#include <exceptions/exceptions.h>
-#include <util/hooks/server_hooks.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <map>
-#include <string>
-
-namespace isc {
-namespace util {
-
-/// @brief No Such Context
-///
-/// Thrown if an attempt is made to obtain context that has not been previously
-/// set.
-
-class NoSuchLibraryContext : public Exception {
-public:
-    NoSuchLibraryContext(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-/// @brief Invalid index
-///
-/// Thrown if an attempt is made to obtain a library handle but the current
-/// library handle index is invalid.  This will occur if the method
-/// LibraryHandleCollection::getLibraryHandle() is called outside of a callout.
-
-class InvalidIndex : public Exception {
-public:
-    InvalidIndex(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-// Forward declaration for CalloutHandle
-class CalloutHandle;
-
-/// Typedef for a callout pointer.  (Callouts must have "C" linkage.)
-extern "C" {
-    typedef int (*CalloutPtr)(CalloutHandle&);
-};
-
-
-/// @brief Library handle
-///
-/// This class is used to manage a loaded library.  It is used by the user
-/// library to register callouts and by the HookManager to call them.
-///
-/// The functions related to loading and unloading the asssociated library are
-/// handled in the related LibraryManager class - there is a 1:1 correspondence
-/// between LibraryManager and LibraryHandle objects.  The separation prevents
-/// the user library callouts from tinkering around with the loading and
-/// unloading of libraries.
-
-class LibraryHandle {
-public:
-
-    /// @brief Constructor
-    ///
-    /// This is passed the ServerHooks object, which is used both to size the
-    /// internal hook vector and in the registration of callouts.
-    ///
-    /// @param hooks Pointer to the hooks registered by the server.
-    LibraryHandle(boost::shared_ptr<ServerHooks>& hooks)
-        : hooks_(hooks), hook_vector_(hooks->getCount())
-    {}
-
-    /// @brief Register a callout on a hook
-    ///
-    /// Registers a callout function with a given hook.  The callout is added
-    /// to the end of the callouts associated with the hook.
-    ///
-    /// @param name Name of the hook to which the callout is added.
-    /// @param callout Pointer to the callout function to be registered.
-    ///
-    /// @throw NoSuchHook The hook name is unrecognised.
-    /// @throw Unexpected The hook name is valid but an internal data structure
-    ///        is of the wrong size.
-    void registerCallout(const std::string& name, CalloutPtr callout);
-
-    /// @brief De-Register a callout on a hook
-    ///
-    /// Searches through the functions associated with the named hook and
-    /// removes all entries matching the callout.  If there are no matching
-    /// callouts, the result is a no-op.
-    ///
-    /// @param name Name of the hook from which the callout is removed.
-    /// @param callout Pointer to the callout function to be removed.
-    ///
-    /// @throw NoSuchHook The hook name is unrecognised.
-    /// @throw Unexpected The hook name is valid but an internal data structure
-    ///        is of the wrong size.
-    void deregisterCallout(const std::string& name, CalloutPtr callout);
-
-    /// @brief Removes all callouts on a hook
-    ///
-    /// Removes all callouts associated with a given hook.  This is a no-op
-    /// if there are no callouts associated with the hook.
-    ///
-    /// @param name Name of the hook from which the callouts are removed.
-    ///
-    /// @throw NoSuchHook Thrown if the hook name is unrecognised.
-    void deregisterAll(const std::string& name);
-
-    /// @brief Checks if callouts are present on a hook
-    ///
-    /// @param index Hook index for which callouts are checked.
-    ///
-    /// @return true if callouts are present, false if not.
-    ///
-    /// @throw NoSuchHook Thrown if the index is not valid.
-    bool calloutsPresent(int index) const;
-
-    /// @brief Calls the callouts for a given hook
-    ///
-    /// Calls the callouts associated with the given hook index.
-    ///
-    /// @param index Index of the hook to call.
-    /// @param callout_handle Reference to the CalloutHandle object for the
-    ///        current object being processed.
-    ///
-    /// @return Status return.
-    int callCallouts(int index, CalloutHandle& callout_handle);
-
-private:
-
-    /// @brief Check hook index
-    ///
-    /// Checks that the hook index is valid for the hook vector.  If not,
-    /// an exception is thrown.
-    ///
-    /// @param index Hooks index to check.
-    ///
-    /// @throw NoSuchHook The index is not valid for the hook vector (i.e.
-    ///        less than zero or equal to or greater than the size of the
-    ///        vector).
-    void checkHookIndex(int index) const;
-
-    // Member variables
-
-    /// Pointer to the list of hooks registered by the server
-    boost::shared_ptr<ServerHooks> hooks_;
-
-    /// Each element in the following vector corresponds to a single hook and
-    /// is an ordered list of callouts for that hook.
-    std::vector<std::vector<CalloutPtr> > hook_vector_;
-};
-
-
-/// @brief Collection of Library Handles
-///
-/// This simple class is a collection of handles for all libraries loaded.
-/// It is pointed to by the CalloutHandle object and is used by that object
-/// to locate the correct LibraryHandle should one be requested by a callout
-/// function.
-///
-/// To do this, the class contains an index indicating the "current" handle.
-/// This is updated during the calling of callouts: prior to calling a callout
-/// associated with a particular LibraryHandle, the index is updated to point to
-/// that handle.  If the callout requests access to the LibraryHandle, it is
-/// passed a reference to the correct one.
-
-class LibraryHandleCollection {
-private:
-
-    /// Private typedef to abbreviate statements in class methods.
-    typedef std::vector<boost::shared_ptr<LibraryHandle> > HandleVector;
-
-public:
-
-    /// @brief Constructor
-    ///
-    /// Initializes member variables, in particular setting the "current library
-    /// handle index" to an invalid value.
-    LibraryHandleCollection() : curidx_(-1), handles_()
-    {}
-
-    /// @brief Add library handle
-    ///
-    /// Adds a library handle to the collection.  The collection is ordered,
-    /// and this adds a library handle to the end of it.
-    ///
-    /// @param library_handle Pointer to the a library handle to be added.
-    void addLibraryHandle(const boost::shared_ptr<LibraryHandle>& handle) {
-        handles_.push_back(handle);
-    }
-
-    /// @brief Return current library index
-    ///
-    /// Returns the value of the "current library index".  Although a callout
-    /// callout can retrieve this information, it is of limited use: the
-    /// value is intended for use by the CalloutHandle object to access the
-    /// per-library context.
-    ///
-    /// @return Current library index value
-    int getLibraryIndex() const {
-        return (curidx_);
-    }
-
-    /// @brief Get current library handle
-    ///
-    /// Returns a pointer to the current library handle.  This method can
-    /// only be called while the code is iterating through the list of
-    /// library handles: calling it at any other time is meaningless and will
-    /// cause an exception to be thrown.
-    ///
-    /// @return Pointer to current library handle. This is the handle for the
-    ///         library on which the callout currently running is associated.
-    boost::shared_ptr<LibraryHandle> getLibraryHandle() const;
-
-    /// @brief Checks if callouts are present on a hook
-    ///
-    /// Checks all loaded libraries and returns true if at least one callout
-    /// has been registered by any of them for the given hook.
-    ///
-    /// @param index Hook index for which callouts are checked.
-    ///
-    /// @return true if callouts are present, false if not.
-    ///
-    /// @throw NoSuchHook Given index does not correspond to a valid hook.
-    bool calloutsPresent(int index) const;
-
-    /// @brief Calls the callouts for a given hook
-    ///
-    /// Iterates through the libray handles and calls the callouts associated
-    /// with the given hook index.
-    ///
-    /// @param index Index of the hook to call.
-    /// @param callout_handle Reference to the CalloutHandle object for the
-    ///        current object being processed.
-    ///
-    /// @return Status return.
-    int callCallouts(int index, CalloutHandle& callout_handle);
-
-private:
-    /// Index of the library handle on which the currently called callout is
-    /// registered.
-    int curidx_;
-
-    /// Vector of pointers to library handles.
-    HandleVector handles_;
-};
-
-} // namespace util
-} // namespace isc
-
-#endif // LIBRARY_HANDLE_H

+ 4 - 4
src/lib/util/tests/Makefile.am

@@ -25,15 +25,15 @@ run_unittests_SOURCES  = run_unittests.cc
 run_unittests_SOURCES += base32hex_unittest.cc
 run_unittests_SOURCES += base64_unittest.cc
 run_unittests_SOURCES += buffer_unittest.cc
-run_unittests_SOURCES += callout_handle_unittest.cc
+# run_unittests_SOURCES += callout_handle_unittest.cc
+run_unittests_SOURCES += callout_manager_unittest.cc
 run_unittests_SOURCES += fd_share_tests.cc
 run_unittests_SOURCES += fd_tests.cc
 run_unittests_SOURCES += filename_unittest.cc
 run_unittests_SOURCES += hex_unittest.cc
-run_unittests_SOURCES += handles_unittest.cc
+# run_unittests_SOURCES += handles_unittest.cc
 run_unittests_SOURCES += io_utilities_unittest.cc
-run_unittests_SOURCES += library_handle_unittest.cc
-run_unittests_SOURCES += library_handle_collection_unittest.cc
+# run_unittests_SOURCES += library_handle_unittest.cc
 run_unittests_SOURCES += lru_list_unittest.cc
 run_unittests_SOURCES += memory_segment_local_unittest.cc
 if USE_SHARED_MEMORY

+ 546 - 0
src/lib/util/tests/callout_manager_unittest.cc

@@ -0,0 +1,546 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+#include <util/hooks/callout_handle.h>
+#include <util/hooks/callout_manager.h>
+#include <util/hooks/server_hooks.h>
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+using namespace isc;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+class CalloutManagerTest : public ::testing::Test {
+public:
+    /// @brief Constructor
+    ///
+    /// Sets up a collection of three LibraryHandle objects to use in the test.
+    CalloutManagerTest() : hooks_(new ServerHooks()) {
+
+        // Set up the server hooks
+        one_index_ = hooks_->registerHook("one");
+        two_index_ = hooks_->registerHook("two");
+        three_index_ = hooks_->registerHook("three");
+        four_index_ = hooks_->registerHook("four");
+
+        // Set up the callout manager with these hooks
+        callout_manager_.reset(new CalloutManager(hooks_));
+
+        // Set up four library handles.
+        library_handle_.push_back(callout_manager_->createHandle());
+        library_handle_.push_back(callout_manager_->createHandle());
+        library_handle_.push_back(callout_manager_->createHandle());
+        library_handle_.push_back(callout_manager_->createHandle());
+
+        // Set up the callout handle.
+        callout_handle_.reset(new CalloutHandle(callout_manager_));
+    }
+
+    /// @brief Return the callout handle
+    CalloutHandle& getCalloutHandle() {
+        return (*callout_handle_);
+    }
+
+    /// @brief Return the callout manager
+    boost::shared_ptr<CalloutManager> getCalloutManager() {
+        return (callout_manager_);
+    }
+
+    /// Static variable used for accumulating information
+    static int callout_value_;
+
+    /// Hook indexes.  These are somewhat ubiquitous, so are made public for
+    /// ease of reference instead of being accessible by a function.
+    int one_index_;
+    int two_index_;
+    int three_index_;
+    int four_index_;
+
+private:
+    /// Callout manager used for the test
+    boost::shared_ptr<CalloutManager> callout_manager_;
+
+    /// Server hooks
+    boost::shared_ptr<ServerHooks> hooks_;
+
+    /// Set up three library handles.
+    std::vector<boost::shared_ptr<LibraryHandle> > library_handle_;
+
+    /// Callout handle used in calls
+    boost::shared_ptr<CalloutHandle> callout_handle_;
+
+};
+
+// Definition of the static variable.
+int CalloutManagerTest::callout_value_ = 0;
+
+// *** Callout Tests ***
+//
+// The next set of tests check that callouts can be called.
+
+// The callouts defined here are structured in such a way that it is possible
+// to determine the order in which they are called and whether they are called
+// at all. The method used is simple - after a sequence of callouts, the digits
+// in the value, reading left to right, determines the order of the callouts
+// called.  For example, callout one followed by two followed by three followed
+// by two followed by one results in a value of 12321.
+//
+// Functions return a zero to indicate success.
+
+extern "C" {
+int manager_general(int number) {
+    CalloutManagerTest::callout_value_ =
+        10 * CalloutManagerTest::callout_value_ + number;
+    return (0);
+}
+
+int manager_one(CalloutHandle&) {
+    return (manager_general(1));
+}
+
+int manager_two(CalloutHandle&) {
+    return (manager_general(2));
+}
+
+int manager_three(CalloutHandle&) {
+    return (manager_general(3));
+}
+
+int manager_four(CalloutHandle&) {
+    return (manager_general(4));
+}
+
+int manager_five(CalloutHandle&) {
+    return (manager_general(5));
+}
+
+int manager_six(CalloutHandle&) {
+    return (manager_general(6));
+}
+
+int manager_seven(CalloutHandle&) {
+    return (manager_general(7));
+}
+
+// The next functions are duplicates of some of the above, but return an error.
+
+int manager_one_error(CalloutHandle& handle) {
+    (void) manager_one(handle);
+    return (1);
+}
+
+int manager_two_error(CalloutHandle& handle) {
+    (void) manager_two(handle);
+    return (1);
+}
+
+int manager_three_error(CalloutHandle& handle) {
+    (void) manager_three(handle);
+    return (1);
+}
+
+int manager_four_error(CalloutHandle& handle) {
+    (void) manager_four(handle);
+    return (1);
+}
+
+};  // extern "C"
+
+// Check we can register callouts appropriately.
+
+TEST_F(CalloutManagerTest, RegisterCallout) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+
+    // Set up so that hooks "one" and "two" have callouts attached from a
+    // single library.
+
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(1, "two", manager_two);
+
+    // Check all is as expected.
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Check that calling the callouts returns as expected.
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1, callout_value_);
+
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(2, callout_value_);
+
+    // Register some more callouts from different libraries on hook 1.
+    getCalloutManager()->registerCallout(2, "one", manager_three);
+    getCalloutManager()->registerCallout(2, "one", manager_four);
+    getCalloutManager()->registerCallout(3, "one", manager_five);
+
+    // Check it is as expected.
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1345, callout_value_);
+
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(2, callout_value_);
+
+    // Add another callout to hook one from library iindex 2 - this should
+    // appear at the end of the callout list for that library.
+    getCalloutManager()->registerCallout(2, "one", manager_six);
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(13465, callout_value_);
+
+    // Add a callout from library index 1 - this should appear between the
+    // callouts from library index 0 and linrary index 2.
+    getCalloutManager()->registerCallout(1, "one", manager_seven);
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(173465, callout_value_);
+
+
+}
+
+// Check the "calloutsPresent()" method.
+
+TEST_F(CalloutManagerTest, CalloutsPresent) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    // Set up so that hooks "one", "two" and "four" have callouts attached
+    // to them, and callout  "three" does not. (In the statements below, the
+    // exact callouts attached to a hook are not relevant - only the fact
+    // that some callouts are).  Chose the libraries for which the callouts
+    // are registered randomly.
+
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+
+    getCalloutManager()->registerCallout(1, "one", manager_two);
+    getCalloutManager()->registerCallout(1, "two", manager_two);
+
+    getCalloutManager()->registerCallout(3, "one", manager_three);
+    getCalloutManager()->registerCallout(3, "four", manager_four);
+
+    // Check all is as expected.
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(four_index_));
+
+    // Check we fail on an invalid index.
+    EXPECT_THROW(getCalloutManager()->calloutsPresent(42), NoSuchHook);
+    EXPECT_THROW(getCalloutManager()->calloutsPresent(-1), NoSuchHook);
+}
+
+// Test that calling a hook with no callouts on it returns success.
+
+TEST_F(CalloutManagerTest, CallNoCallouts) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    // Call the callouts on an arbitrary hook and ensure that nothing happens.
+    callout_value_ = 475;
+    int status = getCalloutManager()->callCallouts(one_index_,
+                                                   getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(475, callout_value_); // Unchanged
+}
+
+// Test that the callouts are called in the correct order.
+
+TEST_F(CalloutManagerTest, CallCalloutsSuccess) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributes one callout on hook "one".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(1, "one", manager_two);
+    getCalloutManager()->registerCallout(2, "one", manager_three);
+    getCalloutManager()->registerCallout(3, "one", manager_four);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1234, callout_value_);
+
+    // Do a random selection of callouts on hook "two".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "two", manager_one);
+    getCalloutManager()->registerCallout(0, "two", manager_three);
+    getCalloutManager()->registerCallout(1, "two", manager_two);
+    getCalloutManager()->registerCallout(3, "two", manager_four);
+    status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1324, callout_value_);
+
+    // Ensure that calling the callouts on a hook with no callouts works.
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(three_index_,
+                                               getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(0, callout_value_);
+}
+
+// Test that the callouts are called in order, but that callouts occurring
+// after a callout that returns an error are not called.
+//
+// (Note: in this test, the callouts that return an error set the value of
+// callout_value_ before they return the error code.)
+
+TEST_F(CalloutManagerTest, CallCalloutsError) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributing one callout on hook "one". The first callout
+    // returns an error (after adding its value to the result).
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_one_error);
+    getCalloutManager()->registerCallout(1, "one", manager_two);
+    getCalloutManager()->registerCallout(2, "one", manager_three);
+    getCalloutManager()->registerCallout(3, "one", manager_four);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(1, status);
+    EXPECT_EQ(1, callout_value_);
+
+    // Each library contributing multiple callouts on hook "two". The last
+    // callout on the first library returns an error.
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "two", manager_one);
+    getCalloutManager()->registerCallout(0, "two", manager_one_error);
+    getCalloutManager()->registerCallout(1, "two", manager_two);
+    getCalloutManager()->registerCallout(1, "two", manager_two);
+    getCalloutManager()->registerCallout(1, "two", manager_three);
+    getCalloutManager()->registerCallout(1, "two", manager_three);
+    getCalloutManager()->registerCallout(3, "two", manager_four);
+    getCalloutManager()->registerCallout(3, "two", manager_four);
+    status = getCalloutManager()->callCallouts(two_index_, getCalloutHandle());
+    EXPECT_EQ(1, status);
+    EXPECT_EQ(11, callout_value_);
+
+    // A callout in a random position in the callout list returns an error.
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "three", manager_one);
+    getCalloutManager()->registerCallout(0, "three", manager_one);
+    getCalloutManager()->registerCallout(1, "three", manager_two);
+    getCalloutManager()->registerCallout(1, "three", manager_two);
+    getCalloutManager()->registerCallout(3, "three", manager_four_error);
+    getCalloutManager()->registerCallout(3, "three", manager_four);
+    status = getCalloutManager()->callCallouts(three_index_,
+                                               getCalloutHandle());
+    EXPECT_EQ(1, status);
+    EXPECT_EQ(11224, callout_value_);
+
+    // The last callout on a hook returns an error.
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "four", manager_one);
+    getCalloutManager()->registerCallout(0, "four", manager_one);
+    getCalloutManager()->registerCallout(1, "four", manager_two);
+    getCalloutManager()->registerCallout(1, "four", manager_two);
+    getCalloutManager()->registerCallout(2, "four", manager_three);
+    getCalloutManager()->registerCallout(2, "four", manager_three);
+    getCalloutManager()->registerCallout(3, "four", manager_four);
+    getCalloutManager()->registerCallout(3, "four", manager_four_error);
+    status = getCalloutManager()->callCallouts(four_index_, getCalloutHandle());
+    EXPECT_EQ(1, status);
+    EXPECT_EQ(11223344, callout_value_);
+}
+
+// Now test that we can deregister a single callout on a hook.
+
+TEST_F(CalloutManagerTest, DeregisterSingleCallout) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributes one callout on hook "one".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_two);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(2, callout_value_);
+
+    // Remove it and check that the no callouts are present.
+    EXPECT_TRUE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+}
+
+// Now test that we can deregister a single callout on a hook that has multiple
+// callouts from the same library.
+
+TEST_F(CalloutManagerTest, DeregisterSingleCalloutSameLibrary) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributes one callout on hook "one".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(0, "one", manager_two);
+    getCalloutManager()->registerCallout(0, "one", manager_three);
+    getCalloutManager()->registerCallout(0, "one", manager_four);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1234, callout_value_);
+
+    // Remove the manager_two callout.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(134, callout_value_);
+
+    // Try removing it again.
+    EXPECT_FALSE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(134, callout_value_);
+
+}
+
+// Check we can deregister multiple callouts from the same library.
+
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsSameLibrary) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributes one callout on hook "one".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(0, "one", manager_two);
+    getCalloutManager()->registerCallout(0, "one", manager_two);
+    getCalloutManager()->registerCallout(0, "one", manager_three);
+    getCalloutManager()->registerCallout(0, "one", manager_three);
+    getCalloutManager()->registerCallout(0, "one", manager_four);
+    getCalloutManager()->registerCallout(0, "one", manager_four);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(11223344, callout_value_);
+
+    // Remove the manager_two callout.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(113344, callout_value_);
+
+    // Try removing multiple callouts from the end of the list.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_four));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(1133, callout_value_);
+
+    // ... and from the start.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_one));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(33, callout_value_);
+
+    // ... and the remaining callouts.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one",
+                                                       manager_three));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(0, callout_value_);
+
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+}
+
+// Check we can deregister multiple callouts from multiple libraries
+
+TEST_F(CalloutManagerTest, DeregisterMultipleCalloutsMultipleLibraries) {
+    // Ensure that no callouts are attached to any of the hooks.
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(one_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(two_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(three_index_));
+    EXPECT_FALSE(getCalloutManager()->calloutsPresent(four_index_));
+                 
+    int status = 0;
+
+    // Each library contributes two callouts to hook "one".
+    callout_value_ = 0;
+    getCalloutManager()->registerCallout(0, "one", manager_one);
+    getCalloutManager()->registerCallout(0, "one", manager_two);
+    getCalloutManager()->registerCallout(1, "one", manager_three);
+    getCalloutManager()->registerCallout(1, "one", manager_four);
+    getCalloutManager()->registerCallout(2, "one", manager_five);
+    getCalloutManager()->registerCallout(2, "one", manager_two);
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(123452, callout_value_);
+
+    // Remove the manager_two callout from library 0.  It should not affect
+    // the second manager_two callout.
+    EXPECT_TRUE(getCalloutManager()->deregisterCallout(0, "one", manager_two));
+    callout_value_ = 0;
+    status = getCalloutManager()->callCallouts(one_index_, getCalloutHandle());
+    EXPECT_EQ(0, status);
+    EXPECT_EQ(13452, callout_value_);
+}
+
+
+} // Anonymous namespace

+ 0 - 447
src/lib/util/tests/library_handle_collection_unittest.cc

@@ -1,447 +0,0 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <exceptions/exceptions.h>
-#include <util/hooks/callout_handle.h>
-#include <util/hooks/library_handle.h>
-#include <util/hooks/server_hooks.h>
-
-#include <gtest/gtest.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-using namespace isc;
-using namespace isc::util;
-using namespace std;
-
-namespace {
-
-/// @brief No such hook
-///
-/// Thrown if an attempt it made to obtain an invalid library handle.
-class InvalidIndex : public isc::Exception {
-public:
-    InvalidIndex(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-class LibraryHandleCollectionTest : public ::testing::Test {
-public:
-    /// @brief Constructor
-    ///
-    /// Sets up a collection of three LibraryHandle objects to use in the test.
-    LibraryHandleCollectionTest()
-        : collection_(new LibraryHandleCollection()), handles_(),
-          hooks_(new ServerHooks()) {
-
-        // Set up the server hooks
-        hooks_->registerHook("one");
-        hooks_->registerHook("two");
-        hooks_->registerHook("three");
-        hooks_->registerHook("four");
-
-        // Set up the library handles and collection.
-        for (int i = 0; i < 4; ++i) {
-            boost::shared_ptr<LibraryHandle> handle(new LibraryHandle(hooks_));
-            handles_.push_back(handle);
-            collection_->addLibraryHandle(handle);
-        }
-
-        callout_value_ = 0;
-    }
-
-    /// @brief Obtain constructed server hooks
-    ///
-    /// @return Reference to shared pointer pointing to server hooks object.
-    boost::shared_ptr<ServerHooks>& getServerHooks() {
-        return (hooks_);
-    }
-
-    /// @brief Obtain LibraryHandleCollection object
-    ///
-    /// @return Reference to shared pointer pointing to handle collection
-    boost::shared_ptr<LibraryHandleCollection>& getLibraryHandleCollection() {
-        return (collection_);
-    }
-
-    /// @brief Obtain individual LibraryHandle.
-    ///
-    /// @param i Index of the library handle required.
-    ///
-    /// @return Reference to shared pointer pointing to the relevant handle.
-    ///
-    /// @throws InvalidIndex if the requested index is not valid.
-    boost::shared_ptr<LibraryHandle>& getLibraryHandle(int i) {
-        if ((i < 0) || (i >= handles_.size())) {
-            isc_throw(InvalidIndex, "handle index of " << i << " not valid for "
-                      " size of handle vector (" << handles_.size() << ")");
-        }
-        return (handles_[i]);
-    }
-
-    /// Variable for callouts test. This is public and static to allow non-
-    /// member functions to access it.  It is initialized every time a
-    /// new test starts.
-    static int callout_value_;
-
-private:
-
-    /// Library handle collection and the individual handles (as the
-    /// collection has no method for accessing an individual member).
-    boost::shared_ptr<LibraryHandleCollection> collection_;
-    std::vector<boost::shared_ptr<LibraryHandle> > handles_;
-
-    /// Server hooks and hooks manager
-    boost::shared_ptr<ServerHooks> hooks_;
-};
-
-// Definition of the static variable.
-int LibraryHandleCollectionTest::callout_value_ = 0;
-
-// *** Callout Tests ***
-//
-// The next set of tests check that callouts can be called.
-
-// The callouts defined here are structured in such a way that it is possible
-// to determine the order in which they are called and whether they are called
-// at all. The method used is simple - after a sequence of callouts, the digits
-// in the value, reading left to right, determines the order of the callouts
-// called.  For example, callout one followed by two followed by three followed
-// by two followed by one results in a value of 12321.
-//
-// Functions return a zero to indicate success.
-
-extern "C" {
-int collection_one(CalloutHandle&) {
-    LibraryHandleCollectionTest::callout_value_ =
-        10 * LibraryHandleCollectionTest::callout_value_ + 1;
-    return (0);
-}
-
-int collection_two(CalloutHandle&) {
-    LibraryHandleCollectionTest::callout_value_ =
-        10 * LibraryHandleCollectionTest::callout_value_ + 2;
-    return (0);
-}
-
-int collection_three(CalloutHandle&) {
-    LibraryHandleCollectionTest::callout_value_ =
-        10 * LibraryHandleCollectionTest::callout_value_ + 3;
-    return (0);
-}
-
-int collection_four(CalloutHandle&) {
-    LibraryHandleCollectionTest::callout_value_ =
-        10 * LibraryHandleCollectionTest::callout_value_ + 4;
-    return (0);
-}
-
-// The next functions are duplicates of the above, but return an error.
-
-int collection_one_error(CalloutHandle& handle) {
-    (void) collection_one(handle);
-    return (1);
-}
-
-int collection_two_error(CalloutHandle& handle) {
-    (void) collection_two(handle);
-    return (1);
-}
-
-int collection_three_error(CalloutHandle& handle) {
-    (void) collection_three(handle);
-    return (1);
-}
-
-int collection_four_error(CalloutHandle& handle) {
-    (void) collection_four(handle);
-    return (1);
-}
-
-// The next functions are duplicates of the above, but set the skip flag.
-
-int collection_one_skip(CalloutHandle& handle) {
-    handle.setSkip(true);
-    return (collection_one(handle));
-}
-
-int collection_two_skip(CalloutHandle& handle) {
-    handle.setSkip(true);
-    return (collection_two(handle));
-}
-
-int collection_three_skip(CalloutHandle& handle) {
-    handle.setSkip(true);
-    return (collection_three(handle));
-}
-
-int collection_four_skip(CalloutHandle& handle) {
-    handle.setSkip(true);
-    return (collection_four(handle));
-}
-
-};  // extern "C"
-
-// Check the "calloutsPresent()" method.
-//
-// Note: as we needed to use the addHandleMethod() to set up the handles to
-// which the callouts are attached, this can also be construed as a test
-// of the addLibraryHandle method as well.
-
-TEST_F(LibraryHandleCollectionTest, CalloutsPresent) {
-    const int one_index = getServerHooks()->getIndex("one");
-    const int two_index = getServerHooks()->getIndex("two");
-    const int three_index = getServerHooks()->getIndex("three");
-    const int four_index = getServerHooks()->getIndex("four");
-
-    // Ensure that no callouts are attached to any of the hooks.
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-                 
-    // Set up so that hooks "one", "two" and "four" have callouts attached
-    // to them, and callout  "three" does not. (In the statements below, the
-    // exact callouts attached to a hook are not relevant - only the fact
-    // that some callouts are).
-
-    getLibraryHandle(0)->registerCallout("one", collection_one);
-
-    getLibraryHandle(1)->registerCallout("one", collection_two);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-
-    getLibraryHandle(3)->registerCallout("one", collection_four);
-    getLibraryHandle(3)->registerCallout("four", collection_two);
-
-    // Check all is as expected.
-    EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(one_index));
-    EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(two_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
-    EXPECT_TRUE(getLibraryHandleCollection()->calloutsPresent(four_index));
-
-    // Check we fail on an invalid index.
-    EXPECT_THROW(getLibraryHandleCollection()->calloutsPresent(42), NoSuchHook);
-    EXPECT_THROW(getLibraryHandleCollection()->calloutsPresent(-1), NoSuchHook);
-
-    // Check we get a negative result on an empty collection.
-    LibraryHandleCollection empty_collection;
-    EXPECT_FALSE(empty_collection.calloutsPresent(-1));
-}
-
-// Test that the callouts are called in the correct order.
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsSuccess) {
-    const int one_index = getServerHooks()->getIndex("one");
-    const int two_index = getServerHooks()->getIndex("two");
-    const int three_index = getServerHooks()->getIndex("three");
-    const int four_index = getServerHooks()->getIndex("four");
-
-    // Ensure that no callouts are attached to any of the hooks.
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-                 
-    // Set up different sequences of callouts on different handles.
-    CalloutHandle callout_handle(getLibraryHandleCollection());
-    int status;
-
-    // Each library contributing one callout on hook "one".
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("one", collection_one);
-    getLibraryHandle(1)->registerCallout("one", collection_two);
-    getLibraryHandle(2)->registerCallout("one", collection_three);
-    getLibraryHandle(3)->registerCallout("one", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(one_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(1234, callout_value_);
-
-    // Do a random selection of callouts on hook "two".
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("two", collection_one);
-    getLibraryHandle(0)->registerCallout("two", collection_one);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-    getLibraryHandle(3)->registerCallout("two", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(two_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(1124, callout_value_);
-
-    // Ensure that calling the callouts on a hook with no callouts works.
-    callout_value_ = 0;
-    status = getLibraryHandleCollection()->callCallouts(three_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(0, callout_value_);
-}
-
-// Test that the callouts are called in order, but that callouts occurring
-// after a callout that returns an error are not called.
-//
-// (Note: in this test, the callouts that return an error set the value of
-// callout_value_ before they return the error code.)
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsError) {
-    const int one_index = getServerHooks()->getIndex("one");
-    const int two_index = getServerHooks()->getIndex("two");
-    const int three_index = getServerHooks()->getIndex("three");
-    const int four_index = getServerHooks()->getIndex("four");
-
-    // Ensure that no callouts are attached to any of the hooks.
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-                 
-    // Set up different sequences of callouts on different handles.
-    CalloutHandle callout_handle(getLibraryHandleCollection());
-    int status;
-
-    // Each library contributing one callout on hook "one". The first callout
-    // returns an error.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("one", collection_one_error);
-    getLibraryHandle(1)->registerCallout("one", collection_two);
-    getLibraryHandle(2)->registerCallout("one", collection_three);
-    getLibraryHandle(3)->registerCallout("one", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(one_index,
-                                                        callout_handle);
-    EXPECT_EQ(1, status);
-    EXPECT_EQ(1, callout_value_);
-
-    // Each library contributing multiple callouts on hook "two". The last
-    // callout on the first library returns an error.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("two", collection_one);
-    getLibraryHandle(0)->registerCallout("two", collection_one_error);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-    getLibraryHandle(1)->registerCallout("two", collection_three);
-    getLibraryHandle(1)->registerCallout("two", collection_three);
-    getLibraryHandle(3)->registerCallout("two", collection_four);
-    getLibraryHandle(3)->registerCallout("two", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(two_index,
-                                                        callout_handle);
-    EXPECT_EQ(1, status);
-    EXPECT_EQ(11, callout_value_);
-
-    // A callout in a random position in the callout list returns an error.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("three", collection_one);
-    getLibraryHandle(0)->registerCallout("three", collection_one);
-    getLibraryHandle(1)->registerCallout("three", collection_two);
-    getLibraryHandle(1)->registerCallout("three", collection_two);
-    getLibraryHandle(3)->registerCallout("three", collection_four_error);
-    getLibraryHandle(3)->registerCallout("three", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(three_index,
-                                                        callout_handle);
-    EXPECT_EQ(1, status);
-    EXPECT_EQ(11224, callout_value_);
-
-    // The last callout on a hook returns an error.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("four", collection_one);
-    getLibraryHandle(0)->registerCallout("four", collection_one);
-    getLibraryHandle(1)->registerCallout("four", collection_two);
-    getLibraryHandle(1)->registerCallout("four", collection_two);
-    getLibraryHandle(2)->registerCallout("four", collection_three);
-    getLibraryHandle(2)->registerCallout("four", collection_three);
-    getLibraryHandle(3)->registerCallout("four", collection_four);
-    getLibraryHandle(3)->registerCallout("four", collection_four_error);
-    status = getLibraryHandleCollection()->callCallouts(four_index,
-                                                        callout_handle);
-    EXPECT_EQ(1, status);
-    EXPECT_EQ(11223344, callout_value_);
-}
-
-// Same test as CallCalloutsSucess, but with functions returning a "skip"
-// instead.
-
-TEST_F(LibraryHandleCollectionTest, CallCalloutsSkip) {
-    const int one_index = getServerHooks()->getIndex("one");
-    const int two_index = getServerHooks()->getIndex("two");
-    const int three_index = getServerHooks()->getIndex("three");
-    const int four_index = getServerHooks()->getIndex("four");
-
-    // Ensure that no callouts are attached to any of the hooks.
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(one_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(two_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(three_index));
-    EXPECT_FALSE(getLibraryHandleCollection()->calloutsPresent(four_index));
-                 
-    // Set up different sequences of callouts on different handles.
-    CalloutHandle callout_handle(getLibraryHandleCollection());
-    int status;
-
-    // Each library contributing one callout on hook "one". The first callout
-    // sets the "skip" flag.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("one", collection_one_skip);
-    getLibraryHandle(1)->registerCallout("one", collection_two);
-    getLibraryHandle(2)->registerCallout("one", collection_three);
-    getLibraryHandle(3)->registerCallout("one", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(one_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(1, callout_value_);
-
-    // Each library contributing multiple callouts on hook "two". The last
-    // callout on the first library sets the "skip" flag.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("two", collection_one);
-    getLibraryHandle(0)->registerCallout("two", collection_one_skip);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-    getLibraryHandle(1)->registerCallout("two", collection_two);
-    getLibraryHandle(1)->registerCallout("two", collection_three);
-    getLibraryHandle(1)->registerCallout("two", collection_three);
-    getLibraryHandle(3)->registerCallout("two", collection_four);
-    getLibraryHandle(3)->registerCallout("two", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(two_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(11, callout_value_);
-
-    // A callout in a random position in the callout list sets the "skip" flag.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("three", collection_one);
-    getLibraryHandle(0)->registerCallout("three", collection_one);
-    getLibraryHandle(1)->registerCallout("three", collection_two);
-    getLibraryHandle(1)->registerCallout("three", collection_two);
-    getLibraryHandle(3)->registerCallout("three", collection_four_skip);
-    getLibraryHandle(3)->registerCallout("three", collection_four);
-    status = getLibraryHandleCollection()->callCallouts(three_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(11224, callout_value_);
-
-    // The last callout on a hook sets the "skip" flag.
-    callout_value_ = 0;
-    getLibraryHandle(0)->registerCallout("four", collection_one);
-    getLibraryHandle(0)->registerCallout("four", collection_one);
-    getLibraryHandle(1)->registerCallout("four", collection_two);
-    getLibraryHandle(1)->registerCallout("four", collection_two);
-    getLibraryHandle(2)->registerCallout("four", collection_three);
-    getLibraryHandle(2)->registerCallout("four", collection_three);
-    getLibraryHandle(3)->registerCallout("four", collection_four);
-    getLibraryHandle(3)->registerCallout("four", collection_four_skip);
-    status = getLibraryHandleCollection()->callCallouts(four_index,
-                                                        callout_handle);
-    EXPECT_EQ(0, status);
-    EXPECT_EQ(11223344, callout_value_);
-}
-
-} // Anonymous namespace

+ 4 - 3
src/lib/util/tests/library_handle_unittest.cc

@@ -33,12 +33,11 @@ public:
     ///
     /// Sets up an appropriate number of server hooks to pass to the
     /// constructed callout handle objects.
-    LibraryHandleTest()
-        : hooks_(new ServerHooks()),
-          collection_(new LibraryHandleCollection()) {
+    LibraryHandleTest() : hooks_(new ServerHooks()) {
         hooks_->registerHook("alpha");
         hooks_->registerHook("beta");
         hooks_->registerHook("gamma");
+        collection_.reset(new LibraryHandleCollection(hooks_));
 
         // Also initialize the variable used to pass information back from the
         // callouts to the tests.
@@ -63,6 +62,8 @@ public:
 private:
     boost::shared_ptr<ServerHooks> hooks_;
     boost::shared_ptr<LibraryHandleCollection> collection_;
+    boost::shared_ptr<LibraryHandle> handle_0_;
+    boost::shared_ptr<LibraryHandle> handle_1_;
 };
 
 // Definition of the static variable.