// Copyright (C) 2010  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.

// $Id$

#ifndef __RRSET_H
#define __RRSET_H 1

#include <iostream>
#include <string>

#include <boost/shared_ptr.hpp>

#include <exceptions/exceptions.h>

#include <dns/rdata.h>
#include <dns/rrtype.h>

namespace isc {
namespace dns {

///
/// \brief A standard DNS module exception that is thrown if an RRset object
/// does not contain any RDATA where required.
///
class EmptyRRset : public Exception {
public:
    EmptyRRset(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

// forward declarations
class Name;
class RRType;
class RRClass;
class RRTTL;
class OututBuffer;
class MessageRenderer;
class AbstractRRset;
class BasicRRset;
class RdataIterator;
class BasicRRsetImpl;
class RRset;

/// \brief A pointer-like type pointing to an \c RRset object.
///
/// This type is commonly used as an argument of various functions defined
/// in this library in order to handle RRsets in a polymorphic manner.
typedef boost::shared_ptr<RRset> RRsetPtr;

/// \brief A pointer-like type pointing to an (immutable) \c RRset
/// object.
///
/// This type is commonly used as an argument of various functions defined
/// in this library in order to handle RRsets in a polymorphic manner.
typedef boost::shared_ptr<const RRset> ConstRRsetPtr;

/// \brief A pointer-like type point to an \c RdataIterator object.
typedef boost::shared_ptr<RdataIterator> RdataIteratorPtr;

/// \brief The \c AbstractRRset class is an abstract base class that
/// models a DNS RRset.
///
/// An object of (a specific derived class of) \c AbstractRRset
/// models an RRset as described in the DNS standard:
/// A set of DNS resource records (RRs) of the same type and class.
/// The standard requires the TTL of all RRs in an RRset be the same;
/// this class follows that requirement.

/// Note about duplicate RDATA: RFC2181 states that it's meaningless that an
/// RRset contains two identical RRs and that name servers should suppress
/// such duplicates.
/// This class is not responsible for ensuring this requirement: For example,
/// \c addRdata() method doesn't check if there's already RDATA identical
/// to the one being added.
/// This is because such checks can be expensive, and it's often easy to
/// ensure the uniqueness requirement at the %data preparation phase
/// (e.g. when loading a zone).
/// When parsing an incoming DNS message, the uniqueness may not be guaranteed,
/// so the application needs to detect and ignore any duplicate RDATA
/// (the \c Message class of this library should provide this responsibility).
///
/// Another point to note is that \c AbstractRRset and its derived classes
/// allow an object to have an empty set of RDATA.
/// Even though there's no corresponding notion in the protocol specification,
/// it would be more intuitive for a container-like %data structure
/// to allow an empty set.
///
/// Since \c AbstractRRset is an abstract class, it is generally used
/// via a pointer (or pointer like object) or a reference.
/// In particular, \c RRsetPtr, a pointer like type for \c AbstractRRset,
/// is used for polymorphic RRset operations throughout this library.
///
/// The \c AbstractRRset class is also intended to be a major customization
/// point.  For example, a high performance server implementation may want
/// to define an optimized "pre-compiled" RRset and provide an optimized
/// implementation of the \c toWire() method.
///
/// Note about design choice: In BIND9, a set of RDATA with a common tuple
/// of RR class, RR type, and TTL was represented in a structure named
/// \c rdataset.  Unlike the RRset classes, an \c rdataset did not contain
/// the information of the owner name.
/// This might be advantageous if we want to handle "RRsets", that is,
/// a set of different types of RRset for the same owner name, because
/// a single "name" structure can be used for multiple RRsets, minimizing
/// %data copy and memory footprint.
/// On the other hand, it's inconvenient for API users since in many cases
/// a pair of name and an \c rdataset must be maintained.  It's also counter
/// intuitive in implementing protocol operations as an RRset is often used
/// as an atomic entity in DNS protocols while an \c rdataset is a component
/// of an RRset.
///
/// We have therefore defined the notion of RRset explicitly in our initial
/// API design.  We believe memory footprint is not a big concern because
/// RRsets are generally expected to be used as temporary objects, e.g.
/// while parsing or constructing a DNS message, or searching a DNS %data
/// source; for longer term purposes such as in-memory %data source entries,
/// the corresponding %data would be represented in a different, memory
/// optimized format.  As for the concern about %data copy, we believe
/// it can be mitigated by using copy-efficient implementation for the
/// \c Name class implementation, such as reference counted objects.
/// Later, We plan to perform benchmark tests later to see if this assumption
/// is valid and to revisit the design if necessary.
///
/// Note about terminology: there has been a discussion at the IETF
/// namedroppers ML about RRset vs RRSet (case of "s")
/// [http://ops.ietf.org/lists/namedroppers/namedroppers.2009/msg02737.html].
/// While RFC2181 uses the latter, many other RFCs use the former,
/// and most of the list members who showed their opinion seem to prefer
/// "RRset".  We follow that preference in this implementation.
///
/// The current design of \c AbstractRRset is still in flux.
/// There are many open questions in design details:
///   - support more set-like operations, e.g, merge two RRsets of the same
///     type?
///   - more convenient methods or non member utility functions, e.g.
///      "sort" and "search(find)" method?
///   - what about comparing two RRsets of the same type?  If we need this,
///     should it compare rdata's as a set or as a list (i.e. compare
///     each %rdata one by one or as a whole)?  c.f. NLnet Labs' ldns
///     (http://www.nlnetlabs.nl/projects/ldns/doc/index.html)
///     has \c ldns_rr_list_compare(), which takes the latter approach
///     (seemingly assuming the caller sorts the lists beforehand).
///   - BIND9 libdns has some special DNSSEC-related methods
///     such as \c addnoqname() or \c addclosest().  Do we need these?
///     (Probably not.  We wouldn't want to make the class design too
///     monolithic.)
///   - Do we need to allow the user to remove specific Rdata?
///     Probably not, according to the current usage of the BIND9 code.
class AbstractRRset {
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are intentionally
    /// defined as private to make it explicit that this is a pure base class.
    //@{
private:
    AbstractRRset(const AbstractRRset& source);
    AbstractRRset& operator=(const AbstractRRset& source);
protected:
    /// \brief The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class should
    /// never be instantiated (except as part of a derived class).
    AbstractRRset() {}
public:
    /// The destructor.
    virtual ~AbstractRRset() {}
    //@}

    ///
    /// \name Getter and Setter Methods
    ///
    /// These methods are generally expected to be exception free, but it's
    /// not guaranteed at the interface level;
    /// for example, some performance optimized derived class may manage
    /// the information corresponding to the class "attributes" to get or set,
    /// and may require dynamic memory allocation to execute the method.
    /// Consult the derived class description to see if a specific derived
    /// \c RRset class may throw an exception from these methods.
    ///
    /// Note that setter methods are not provided for \c RRClass and
    /// \c RRType.  This is intentional.  Since the format and semantics of
    /// \c Rdata are dependent on the RR type (and RR class for some RR types),
    /// allowing dynamically modify these attributes can easily lead to a
    /// bug where the RDATA and type and/or class become inconsistent.
    /// We want to avoid that situation by restricting the access.
    //@{
    /// \brief Returns the number of \c Rdata objects contained in the \c RRset.
    ///
    /// Note that an \c RRset with an empty set of \c Rdata can exist, so
    /// this method may return 0.
    ///
    /// \return The number of \c Rdata objects contained.
    virtual unsigned int getRdataCount() const = 0;

    /// \brief Returns the owner name of the \c RRset.
    ///
    /// \return A reference to a \c Name class object corresponding to the
    /// \c RRset owner name.
    virtual const Name& getName() const = 0;

    /// \brief Returns the RR Class of the \c RRset.
    ///
    /// \return A reference to a \c RRClass class object corresponding to the
    /// RR class of the \c RRset.
    virtual const RRClass& getClass() const = 0;

    /// \brief Returns the RR Type of the \c RRset.
    ///
    /// \return A reference to a \c RRType class object corresponding to the
    /// RR type of the \c RRset.
    virtual const RRType& getType() const = 0;

    /// \brief Returns the TTL of the RRset.
    ///
    /// \return A reference to a \c RRTTL class object corresponding to the
    /// TTL of the \c RRset.
    virtual const RRTTL& getTTL() const = 0;

    /// \brief Updates the owner name of the \c RRset.
    ///
    /// \param name A reference to a \c RRTTL class object to be copied as the
    /// new TTL.
    virtual void setName(const Name& name) = 0;

    /// \brief Updates the TTL of the \c RRset.
    ///
    /// \param ttl A reference to a \c RRTTL class object to be copied as the
    /// new TTL.
    virtual void setTTL(const RRTTL& ttl) = 0;
    //@}

    ///
    /// \name Converter Methods
    ///
    /// These methods have the default implementation that can be reused by
    /// derived classes.
    /// Since they are defined as pure virtual, derived classes
    /// that want to reuse the default implementation must explicitly
    /// invoke their base class version (see the description for
    /// <code>addRdata(const rdata::Rdata&)</code>).
    ///
    /// Design Note: the default implementations are defined only using
    /// other public methods of the \c AbstractRRset class, and could be
    /// implemented as non member functions (as some C++ textbooks suggest).
    /// However, since derived classes may want to provide customized versions
    /// (especially of the \c toWire() method for performance reasons)
    /// we chose to define them as virtual functions, and, as a result,
    /// member functions.
    //@{
    /// \brief Convert the RRset to a string.
    ///
    /// Unlike other similar methods of this library, this method terminates
    /// the resulting string with a trailing newline character.
    /// (following the BIND9 convention)
    ///
    /// The RRset must contain some RDATA; otherwise, an exception of class
    /// \c EmptyRRset will be thrown.
    /// If resource allocation fails, a corresponding standard exception
    /// will be thrown.
    /// The default implementation may throw other exceptions if the
    /// \c toText() method of the RDATA objects throws.
    /// If a derived class of \c AbstractRRset overrides the default
    /// implementation, the derived version may throw its own exceptions.
    ///
    /// Open issue: We may want to support multiple output formats as
    /// BIND9 does.  For example, we might want to allow omitting the owner
    /// name when possible in the context of zone dump.  This is a future
    /// TODO item.
    ///
    /// \param rrset A reference to a (derived class of) \c AbstractRRset object
    /// whose content is to be converted.
    /// \return A string representation of the RRset.
    virtual std::string toText() const = 0;

    /// \brief Render the RRset in the wire format with name compression and
    /// truncation handling.
    ///
    /// This method compresses the owner name of the RRset and domain names
    /// used in RDATA that should be compressed.
    /// In addition, this method detects the case where rendering the entire
    /// RRset would cause truncation, and handles the case appropriately
    /// (this is a TODO item, and not implemented in this version).
    ///
    /// Note: perhaps we may want to add more arguments to convey optional
    /// information such as an "rrset-order" policy or how to handle truncation
    /// case.  This is a TODO item.
    ///
    /// If resource allocation fails, a corresponding standard exception
    /// will be thrown.
    /// The RRset must contain some RDATA; otherwise, an exception of class
    /// \c EmptyRRset will be thrown.
    /// The default implementation may throw other exceptions if the
    /// \c toWire() method of the RDATA objects throws.
    /// If a derived class of \c AbstractRRset overrides the default
    /// implementation, the derived version may throw its own exceptions.
    ///
    /// \param renderer DNS message rendering context that encapsulates the
    /// output buffer and name compression information.
    /// \return The number of RRs rendered.  If the truncation is necessary
    /// this value may be different from the number of RDATA objects contained
    /// in the RRset.
    virtual unsigned int toWire(MessageRenderer& renderer) const = 0;

    /// \brief Render the RRset in the wire format without any compression.
    ///
    /// See the other toWire() description about possible exceptions.
    ///
    /// \param buffer An output buffer to store the wire data.
    /// \return The number of RRs rendered.
    virtual unsigned int toWire(OutputBuffer& buffer) const = 0;
    //@}

    ///
    /// \name RDATA Manipulation Methods
    ///
    //@{
    /// \brief Add an RDATA to the RRset (pointer version).
    ///
    /// This method adds the given RDATA (as a pointer-like type to a
    /// derived class object of \c rdata::Rdata) to the \c RRset.
    ///
    /// \param rdata A pointer (like) type of \c rdata::RdataPtr to be added
    /// to the \c RRset.
    virtual void addRdata(rdata::ConstRdataPtr rdata) = 0;

    /// \brief Add an RDATA to the RRset (reference version).
    ///
    /// This method adds the given RDATA (as a reference to a
    /// derived class object of \c rdata::Rdata) to the \c RRset.
    ///
    /// This method has the default implementation that can be reused by
    /// derived classes.
    /// Since this method is defined as pure virtual, derived classes
    /// that want to reuse the default implementation must explicitly
    /// invoke this base class version.
    /// For example, if the class \c CustomizedRRset, a derived class of
    /// \c AbstractRRset, wants to reuse the default implementation of
    /// \c %addRdata() (reference version), it would be defined as follows:
    /// \code void
    /// CustomizedRRset::addRdata(const rdata::Rdata& rdata)
    /// {
    ///     AbstractRRset::addRdata(rdata);
    /// }
    /// \endcode
    ///
    /// This method is more strictly typed than the pointer version:
    /// If \c %rdata does not refer to the appropriate derived
    /// \c Rdata class
    /// for the \c RRType for this \c RRset, it throws an exception of class
    /// \c std::bad_cast.
    /// If resource allocation fails, a corresponding standard exception
    /// will be thrown.
    /// The RRset must contain some RDATA; otherwise, an exception of class
    /// \c EmptyRRset will be thrown.
    /// The default implementation may throw other exceptions if the
    /// \c toWire() method of the RDATA objects throws.
    /// If a derived class of \c AbstractRRset overrides the default
    /// implementation, the derived version may throw its own exceptions.
    ///
    /// The default implementation simply constructs an \c rdata::RdataPtr
    /// object from a newly allocated RDATA object copying from parameter
    /// \c rdata, and calls the other version of
    /// \c addRdata(const rdata::RdataPtr).
    /// So it is inherently less efficient than the other version.
    /// Still, this version would offer a more intuitive interface and is
    /// provided as such.
    ///
    /// \param rdata A reference to a \c rdata::RdataPtr (derived) class
    /// object, a copy of which is to be added to the \c RRset.
    virtual void addRdata(const rdata::Rdata& rdata) = 0;

    /// \brief Return an iterator to go through all RDATA stored in the
    /// \c RRset.
    ///
    /// Using the design pattern terminology, \c getRdataIterator()
    /// is an example of a <em>factory method</em>.
    ///
    /// Whether this method throws an exception depends on the actual
    /// implementation of the derived \c AbstractRRset class, but in general
    /// it will involve resource allocation and can throw a standard exception
    /// if it fails.
    ///
    /// \return A pointer-like object pointing to the derived \c RdataIterator
    /// object.
    virtual RdataIteratorPtr getRdataIterator() const = 0;
    //@}
};

/// \brief The \c RdataIterator class is an abstract base class that
/// provides an interface for accessing RDATA objects stored in an RRset.
///
/// While different derived classes of \c AbstractRRset may maintain the RDATA
/// objects in different ways, the \c RdataIterator class provides a
/// unified interface to iterate over the RDATA objects in a polymorphic
/// manner.
///
/// Each derived class of \c AbstractRRset is expected to provide a concrete
/// derived class of \c RdataIterator, and each derived \c RdataIterator
/// class implements the unified interface in a way specific to the
/// implementation of the corresponding derived \c AbstractRRset class.
/// Using the design pattern terminology, this is a typical example of
/// the \e Iterator pattern.
///
/// The RDATA objects stored in the \c RRset are considered to form
/// a unidirectional list from the \c RdataIterator point of view (while
/// the actual implementation in the derived \c RRset may not use a list).
/// We call this unidirectional list the <em>%rdata list</em>.
///
/// An \c RdataIterator object internally (and conceptually) holds a
/// <em>%rdata cursor</em>, which points to a specific item of the %rdata list.
///
/// Note about design choice: as is clear from the interface, \c RdataIterator
/// is not compatible with the standard iterator classes.
/// Although it would be useful (for example, we could then use STL algorithms)
/// and is not necessarily impossible, it would make the iterator implementation
/// much more complicated.
/// For instance, any standard iterator must be assignable and
/// copy-constructible.
/// So we'd need to implement \c RdataIterator::operator=() in a polymorphic
/// way.  This will require non-trivial implementation tricks.
/// We believe the simplified iterator interface as provided by the
/// \c RdataIterator class is sufficient in practice:
/// Most applications will simply go through the RDATA objects contained in
/// an RRset, examining (and possibly using) each object, as one path
/// operation.
class RdataIterator {
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are intentionally
    /// defined as private to make it explicit that this is a pure base class.
    //@{
protected:
    /// \brief The default constructor.
    ///
    /// This is intentionally defined as \c protected as this base class should
    /// never be instantiated (except as part of a derived class).
    RdataIterator() {}
public:
    /// \brief Destructor
    virtual ~RdataIterator() {}
private:
    RdataIterator(const RdataIterator& source);
    RdataIterator& operator=(const RdataIterator& source);
    //@}

public:
    /// \brief Move the %rdata cursor to the first RDATA in the %rdata list
    /// (if any).
    ///
    /// This method can safely be called multiple times, even after moving
    /// the %rdata cursor forward by the \c next() method.
    ///
    /// This method should never throw an exception.
    virtual void first() = 0;

    /// \brief Move the %rdata cursor to the next RDATA in the %rdata list
    /// (if any).
    ///
    /// This method should never throw an exception.
    virtual void next() = 0;

    /// \brief Return the current \c Rdata corresponding to the %rdata cursor.
    ///
    /// \return A reference to an \c rdata::::Rdata object corresponding
    /// to the %rdata cursor.
    virtual const rdata::Rdata& getCurrent() const = 0;

    /// \brief Return true iff the %rdata cursor has reached the end of the
    /// %rdata list.
    ///
    /// Once this method returns \c true, the behavior of any subsequent
    /// call to \c next() or \c getCurrent() is undefined.
    /// Likewise, the result of \c isLast() call followed by such undefined
    /// operations is also undefined.
    ///
    /// This method should never throw an exception.
    ///
    /// \return \c true if the %rdata cursor has reached the end of the
    /// %rdata list; otherwise \c false.
    virtual bool isLast() const = 0;
};

/// \brief The \c BasicRRset class is a concrete derived class of
/// \c AbstractRRset that defines a straightforward RRset implementation.
///
/// This class is designed to be as portable as possible, and so it adopts
/// the Pimpl idiom to hide as many details as possible.
/// Performance is a secondary concern for this class.
///
/// This class is intended to be used by applications that only need
/// moderate level of performance with full functionality provided by
/// the \c AbstractRRset interfaces.
/// Highly performance-sensitive applications, such as a large scale
/// authoritative or caching name servers will implement and use a customized
/// version of derived \c AbstractRRset class.
class BasicRRset : public AbstractRRset {
    ///
    /// \name Constructors and Destructor
    ///
    /// Note: The copy constructor and the assignment operator are intentionally
    /// defined as private.  The intended use case wouldn't require copies of
    /// a \c BasicRRset object; once created, it would normally be used
    /// as a \c const object (via references).
    //@{
private:
    BasicRRset(const BasicRRset& source);
    BasicRRset& operator=(const BasicRRset& source);
public:
    /// \brief Constructor from (mostly) fixed parameters of the RRset.
    ///
    /// This constructor is normally expected to be exception free, but
    /// copying the name may involve resource allocation, and if it fails
    /// the corresponding standard exception will be thrown.
    ///
    /// \param name The owner name of the RRset.
    /// \param rrclass The RR class of the RRset.
    /// \param rrtype The RR type of the RRset.
    /// \param ttl The TTL of the RRset.
    explicit BasicRRset(const Name& name, const RRClass& rrclass,
                        const RRType& rrtype, const RRTTL& ttl);
    /// \brief The destructor.
    virtual ~BasicRRset();
    //@}

    ///
    /// \name Getter and Setter Methods
    ///
    //@{
    /// \brief Returns the number of \c Rdata objects contained in the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \return The number of \c Rdata objects contained.
    virtual unsigned int getRdataCount() const;

    /// \brief Returns the owner name of the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \return A reference to a \c Name class object corresponding to the
    /// \c RRset owner name.
    virtual const Name& getName() const;

    /// \brief Returns the RR Class of the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \return A reference to a \c RRClass class object corresponding to the
    /// RR class of the \c RRset.
    virtual const RRClass& getClass() const;

    /// \brief Returns the RR Type of the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \return A reference to a \c RRType class object corresponding to the
    /// RR type of the \c RRset.
    virtual const RRType& getType() const;

    /// \brief Returns the TTL of the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \return A reference to a \c RRTTL class object corresponding to the
    /// TTL of the \c RRset.
    virtual const RRTTL& getTTL() const;

    /// \brief Updates the owner name of the \c RRset.
    ///
    /// This method normally does not throw an exception, but could throw
    /// some standard exception on resource allocation failure if the
    /// internal copy of the \c name involves resource allocation and it
    /// fails.
    ///
    /// \param name A reference to a \c RRTTL class object to be copied as the
    /// new TTL.
    virtual void setName(const Name& name);

    /// \brief Updates the TTL of the \c RRset.
    ///
    /// This method never throws an exception.
    ///
    /// \param ttl A reference to a \c RRTTL class object to be copied as the
    /// new TTL.
    virtual void setTTL(const RRTTL& ttl);
    //@}

    ///
    /// \name Converter Methods
    ///
    //@{
    /// \brief Convert the RRset to a string.
    ///
    /// This method simply uses the default implementation.
    /// See \c AbstractRRset::toText().
    virtual std::string toText() const;

    /// \brief Render the RRset in the wire format with name compression and
    /// truncation handling.
    ///
    /// This method simply uses the default implementation.
    /// See \c AbstractRRset::toWire(MessageRenderer&)const.
    virtual unsigned int toWire(MessageRenderer& renderer) const;

    /// \brief Render the RRset in the wire format without any compression.
    ///
    /// This method simply uses the default implementation.
    /// See \c AbstractRRset::toWire(OutputBuffer&)const.
    virtual unsigned int toWire(OutputBuffer& buffer) const;
    //@}

    ///
    /// \name RDATA manipulation methods
    ///
    //@{
    /// \brief Add an RDATA to the RRset (pointer version).
    ///
    /// This method is normally expected to be exception free, but it may
    /// involve resource allocation, and if it fails the corresponding
    /// standard exception will be thrown.
    ///
    /// \param rdata A pointer (like) type of \c rdata::RdataPtr to be added
    /// to the \c BasicRRset.
    virtual void addRdata(rdata::ConstRdataPtr rdata);

    /// \brief Add an RDATA to the RRset (reference version).
    ///
    /// This method simply uses the default implementation.
    /// See \c AbstractRRset::addRdata(const rdata::Rdata&).
    virtual void addRdata(const rdata::Rdata& rdata);

    /// \brief Return an iterator to go through all RDATA stored in the
    /// \c BasicRRset.
    ///
    /// This is a concrete derived implementation of
    /// \c AbstractRRset::getRdataIterator().
    ///
    /// This method dynamically allocates resources.  If it fails it will
    /// throw the corresponding standard exception.
    /// The iterator methods for the \c BasicRRset class are exception free.
    ///
    /// \return A pointer-like object pointing to the derived \c RdataIterator
    /// object for the \c BasicRRset class.
    virtual RdataIteratorPtr getRdataIterator() const;
    //@}
private:
    BasicRRsetImpl* impl_;
};

/// \brief The \c RRset class is a concrete derived class of
/// \c BasicRRset which contains a pointer to an additional RRset
/// containing associated RRSIG records.  This allows DNSSEC aware
/// applications to treat data associated with a particular
/// QNAME/QTYPE/QCLASS as a single object.
class RRset : public BasicRRset {
public:
    explicit RRset(const Name& name, const RRClass& rrclass,
          const RRType& rrtype, const RRTTL& ttl);

    virtual ~RRset();

    /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
    virtual void setName(const Name& n) {
        BasicRRset::setName(n);
        if (rrsig_) {
            rrsig_->setName(n);
        }
    }

    /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
    virtual void setTTL(const RRTTL& ttl) {
        BasicRRset::setTTL(ttl);
        if (rrsig_) {
            rrsig_->setTTL(ttl);
        }
    }

    /// \brief Adds an RRSIG RR to this RRset's signatures
    virtual void addRRsig(const rdata::RdataPtr rdata) {
        if (!rrsig_) {
            rrsig_ = RRsetPtr(new RRset(getName(), getClass(),
                                        RRType::RRSIG(), getTTL()));
        }
        rrsig_->addRdata(rdata);
    }

    /// \brief Adds an RRSIG RRset to this RRset
    void addRRsig(AbstractRRset& sigs) {
        RdataIteratorPtr it = sigs.getRdataIterator();

        if (!rrsig_) {
            rrsig_ = RRsetPtr(new RRset(getName(), getClass(),
                                        RRType::RRSIG(), getTTL()));
        }

        for (it->first(); !it->isLast(); it->next()) {
            rrsig_->addRdata(it->getCurrent());
        }
    }

    void addRRsig(RRsetPtr sigs) { addRRsig(*sigs); }

    /// \brief Clear the RRSIGs for this RRset
    void removeRRsig() { rrsig_ = RRsetPtr(); }

    /// \brief Return a pointer to this RRset's RRSIG RRset
    RRsetPtr getRRsig() { return (rrsig_); }
private:
    RRsetPtr rrsig_;
};


/// \brief Insert the \c RRset as a string into stream.
///
/// This method convert the \c rrset into a string and inserts it into the
/// output stream \c os.
///
/// This function overloads the global \c operator<< to behave as described in
/// \c %ostream::%operator<< but applied to RRset objects.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param rrset A reference to a (derived class of) \c AbstractRRset object
/// output by the operation.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c os after the insertion operation.
std::ostream& operator<<(std::ostream& os, const AbstractRRset& rrset);
} // end of namespace dns
} // end of namespace isc
#endif  // __RRSET_H

// Local Variables: 
// mode: c++
// End: 
