49c086e486ce5a7b30cc609da97a241960902432
[senf.git] / Packets / PacketRegistry.hh
1 // $Id$
2 //
3 // Copyright (C) 2006 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23
24 #ifndef HH_PacketRegistryImpl_
25 #define HH_PacketRegistryImpl_ 1
26
27 // Custom includes
28 #include <map>
29 #include <boost/utility.hpp> // for boost::noncopyable
30 #include <boost/shared_ptr.hpp>
31 #include "Packet.hh"
32
33 //#include "PacketRegistry.mpp"
34 ///////////////////////////////hh.p////////////////////////////////////////
35
36 namespace senf {
37
38
39     namespace impl { template <class key> class PacketRegistryImpl; }
40
41     /** \brief Packet registration facility
42
43         The PacketRegistry provides a generic facility to associate an
44         arbitrary key with Packets. Example keys are Ethertype or IP
45         protocols.
46         
47         Every PacketRegistry is identified by a type tag:
48         \code
49           struct SomeTag {
50               typedef some_key_type key_t;
51           };
52         \endcode
53         The key type can be an arbitrary valuetype. The PacketRegistry
54         for this Tag can then be accessed using
55         <code>PacketRegistry<SomeTag>::</code>.
56
57         The PacketRegistry class has only static members and provides
58         access to the packet registry. It allows to register Packet
59         classes and to create new Packets given a key. Methods are
60         also provided to find the key of a Packet type.
61
62         \code
63             PacketRegistry<SomeTag>::registerPacket<SomePacket>(key_of_somePacket);
64             p = PacketRegistry<SomeTag>::create(some_key,begin,end);
65             SomeTag::key_t key = PacketRegistry<SomeTag>::key<SomePacket>();
66         \endcode
67
68         Normally, packet classes are registered statically and not
69         procedurally. To this end, the RegistrationProxy is provided:
70         \code
71           PacketRegistry<SomeTag>::RegistrationProxy<SomePacket> 
72               registerSomePacket (key_of_somePacket);
73         \endcode
74         This global variable declaration will register \c SomePacket
75         with the \c SomeTag registry under the key \c
76         key_of_somePacket. The variable \c registerSomePacket is a
77         dummy. It's only function is to force the call of it's
78         constructor during global construction time.
79
80         The PacketRegistry's purpose is mostly to assist in
81         implementing the v_nextInterpreter() member of packet
82         facades. This is further supported by the PacketRegistryMixin
83         class.
84
85         \todo Add parameterless create() method
86      */
87     template <class Tag>
88     class PacketRegistry
89     {
90     public:
91         /** \brief Statically register a packet type in a PacketRegistry
92
93             \fixme This fails to work within a library since the linker will
94             remove all unused object files ...
95          */
96         template <class OtherPacket>
97         struct RegistrationProxy
98         {
99             RegistrationProxy(typename Tag::key_t key);
100         };
101         
102         /** \brief Register new packet type
103             
104             Register \c OtherPacket in the packet registry \c Tag
105             under the given \c key.
106
107             \par Preconditions:
108                 The given \c key must be unique and not be assigned to
109                 any other packet class in this registry.
110                 The Packet must not already be registered in the registry.
111
112             \param OtherPacket packet to regiser
113             \param key key of the packet
114          */
115         template <class OtherPacket>
116         static void registerPacket(typename Tag::key_t key);
117
118         /** \brief Find key of a packet
119             
120             Return the key of \c OtherPacket as registered in the \c
121             Tag registry
122
123             \param OtherPacket packet of which the key is requested
124             \returns key of the packet
125             \throws PacketTypeNotRegistered if the packet type is not
126                 found in the registry.
127          */
128         template <class OtherPacket>
129         static typename Tag::key_t key();
130
131         /** \brief Create new Packet
132
133             \param key Key of packet type to create instance of
134             \param b begin iterator argument to Packet::create()
135             \param e end iterator argment to Packet::create()
136             \returns new Instance of the packet type registered under
137                 key or DataPacket, if the key is not registered.
138          */
139         template <class InputIterator>
140         static Packet::ptr create(typename Tag::key_t key, InputIterator b, InputIterator e);
141         
142     private:
143         typedef impl::PacketRegistryImpl<typename Tag::key_t> Registry;
144         static Registry & registry();
145         
146         template <class T, class D> friend class PacketRegistryMixin;
147     };
148
149     /** \brief Helper class for v_nextInterpreter implementations
150
151         This class is a helper class which is to be inherited from in
152         a packet facade which wants to register a new interpreter with
153         the packet framework depending on a packet registry.
154
155         This mixin class provides a new registerInterpreter
156         implementation which can be used besides the methods provided
157         bei senf::Packet to add a new interpreter to the
158         interpreter chain.
159
160         \code
161           class SomePacket
162               : public Packet,
163                 private PacketRegistryMixin<SomeTag,SomePacket>
164           {
165               using Packet::retgisterInterpreter;
166               using PacketRegistryMixin<SomeTag,SomePacket>::registerInterpreter;
167
168               virtual void v_nextInterpreter()
169               {
170                   registerInterpreter(some_key_value, subpacket_begin, subpacket_end);
171               }
172           };
173         \endcode
174         This example is not complete, it only contains the parts
175         concerned with PacketRegistryMixin.
176      */
177     template <class Tag, class Derived>
178     class PacketRegistryMixin
179     {
180     protected:
181         /** \brief add interpreter to interpreter chain
182             
183             This method is used by v_nextInterpreter() to add a new
184             interpreter to the interpreter chain (see the Packet
185             reference for more). Instead of specifying the type of
186             packet to use as a template argument it is specified using
187             the \c key value from the \c Tag registry
188          */
189         void registerInterpreter(typename Tag::key_t key, 
190                                  Packet::iterator b, Packet::iterator e) const;
191     };
192
193     struct PacketTypeNotRegistered : public std::exception
194     { virtual char const * what() const throw() { return "packet type not registered"; } };
195
196 }
197
198 ///////////////////////////////hh.e////////////////////////////////////////
199 //#include "PacketRegistry.cci"
200 #include "PacketRegistry.ct"
201 #include "PacketRegistry.cti"
202 #endif
203
204 \f
205 // Local Variables:
206 // mode: c++
207 // c-file-style: "senf"
208 // End: