PPI: Add support for multiple notify sources per notify target
[senf.git] / PPI / Route.ih
1 // $Id$
2 //
3 // Copyright (C) 2007 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <g0dil@berlios.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 /** \file
24     \brief Route internal header */
25
26 #ifndef IH_Route_
27 #define IH_Route_ 1
28
29 // Custom includes
30 #include <boost/type_traits/is_convertible.hpp>
31 #include <boost/type_traits/is_base_of.hpp>
32 #include <boost/mpl/if.hpp>
33 #include <boost/mpl/bool.hpp>
34 #include <boost/static_assert.hpp>
35
36 ///////////////////////////////ih.p////////////////////////////////////////
37
38 namespace senf {
39 namespace ppi {
40 namespace detail {
41
42     // This is the RoutingTraits implementation for Connectors. Events are handled in the
43     // specialization below
44     template <class Connector, bool isEvent>
45     struct RoutingTraitsImplementation
46     {
47         BOOST_STATIC_ASSERT((boost::is_base_of<connector::Connector, Connector>::value));
48
49         static bool const notifySource = boost::is_base_of<
50             connector::ActiveConnector, Connector>::value;
51         static bool const notifyTarget = boost::is_base_of<
52             connector::PassiveConnector, Connector>::value;
53
54         static bool const dataSource = boost::is_base_of<
55             connector::InputConnector, Connector>::value;
56         static bool const dataTarget = boost::is_base_of<
57             connector::OutputConnector, Connector>::value;
58         
59         typedef Connector type;
60     };
61
62     // RoutingTraits specialization for Event types. Events may be both dataSource or dataTarget but
63     // cannot be notifySource.
64     template <class Event>
65     struct RoutingTraitsImplementation<Event,true>
66     {
67         static bool const notifySource = false;
68         static bool const notifyTarget = true;
69
70         static bool const dataSource = true;
71         static bool const dataTarget = true;
72
73         typedef EventDescriptor type;
74     };
75     
76     // The RoutingTraits give routing related information about the argument type:
77     //  - Wether the type is a notifySource or notifyTarget
78     //  - Wether the type is dataSource or dataTarget
79     //  - Provide the generalized target type
80     //
81     // The real implementation is in RoutingTraitsImplementation which is appropriately specialized
82     // for Events
83     template <class Object>
84     struct RoutingTraits
85         : public RoutingTraitsImplementation<Object, 
86                                              boost::is_convertible<Object*,
87                                                                    EventDescriptor*>::value>
88     {};
89
90     // This is the generic route implementation for all routes. It just provides access to the 
91     // source and target.
92     template <class Source, class Target, class Base>
93     class BaseRouteImplementation
94         : public Base
95     {
96     public:
97         typedef Source source_type;
98         typedef Target target_type;
99
100         Source & source() const;
101         Target & target() const;
102
103     protected:
104         BaseRouteImplementation(module::Module & module, Source & source, Target & target);
105
106     private:
107         Source * source_;
108         Target * target_;
109     };
110
111     // The ForwardingRouteImplementation is based on the same BaseRouteImplementation
112     // as non-forwarding routes are but injects a different base-class (the third template
113     // argument to BaseRouteImplementation). ForwardingRouteImplementation has two additional
114     // functions:
115     //  1) Register the ForwardingRoute with the notifySource
116     //  2) Implement the abstract ForwardingRoute interface
117     //
118     // Since we don't know explicitly, which of Source or Target is the notifySource or
119     // notifyTarget, the implementation calls registerRoute and notifyThrottle/notifyUnthrottle on
120     // *both*, the source and target, however qualified with an additional argument of type
121     // boost::mpl::bool_ which is used to select the correct overloads, of which the 'false'
122     // overload always is a no-op. This way, only the correct call will generate any code, the
123     // disabled call will be optimized away.
124     template <class Source, class Target>
125     class ForwardingRouteImplementation
126         : public BaseRouteImplementation<Source, Target, ForwardingRoute>
127     {
128         typedef BaseRouteImplementation<Source, Target, ForwardingRoute> Base;
129         
130     protected:
131         ForwardingRouteImplementation(module::Module & module, Source & source, Target & target);
132
133     private:
134         // send a throttle/unthrottle notification  only if the second argument is a 'true' type
135         template <class T> void notifyThrottle(T & ob, boost::mpl::bool_<true> const &);
136         template <class T> void notifyThrottle(T & ob, boost::mpl::bool_<false> const &);
137         template <class T> void notifyUnthrottle(T & ob, boost::mpl::bool_<true> const &);
138         template <class T> void notifyUnthrottle(T & ob, boost::mpl::bool_<false> const &);
139
140         template <class T> bool throttled(T & ob, boost::mpl::bool_<true> const &) const;
141         template <class T> bool throttled(T & ob, boost::mpl::bool_<false> const &) const;
142
143         virtual void v_notifyThrottle();
144         virtual void v_notifyUnthrottle();
145         virtual bool v_throttled() const;
146     };
147
148     // This helper class finds the base-class suitable for a specific route. Routes are classified
149     // into two groups: 
150     //  1) A forwarding routes is a routed which forwards notifications from a notifySource to a
151     //     notifyTarget. Forwarding routes are implemneted using ForwardingRouteImplementation
152     //  2) Non-forwarding routes don't forward notifications. They are implemented directly
153     //     using BaseRouteImplementation
154     template <class Source, class Target>
155     struct RouteImplementationBase
156     {
157         typedef RoutingTraits<Source> srcTrait;
158         typedef RoutingTraits<Target> trgTrait;
159
160         static bool const isForwarding = (srcTrait::notifySource && trgTrait::notifyTarget)
161             || (srcTrait::notifyTarget && trgTrait::notifySource);
162         
163         typedef typename boost::mpl::if_c<
164             isForwarding, 
165             ForwardingRouteImplementation<Source,Target>, 
166             BaseRouteImplementation<Source,Target,RouteBase> >::type base;
167     };
168
169     // RouteImplementation2 has two purposes: 
170     //  1) Ensure, that routing is always from a data source to a data target
171     //  2) To find the correct base-class. This is delegated to RouteImplementationBase
172     template <class Source, class Target>
173     class RouteImplementation2
174         : public RouteImplementationBase<Source,Target>::base
175     {
176         typedef typename RouteImplementationBase<Source,Target>::base Base;
177
178         BOOST_STATIC_ASSERT( RoutingTraits<Source>::dataSource && 
179                              RoutingTraits<Target>::dataTarget );
180
181     protected:
182         RouteImplementation2(module::Module & module, Source & source, Target & target);
183     };
184
185     // RouteImplementation just forwards to RouteImplementation2 replacing the template arguments
186     // with the appropriately generalized type: If either Source or Target is an Event type, it is
187     // replaced with the general Event base-class EventDescriptor. Connector types are left as is.
188     template <class Source, class Target>
189     class RouteImplementation
190         : public RouteImplementation2<typename RoutingTraits<Source>::type,
191                                       typename RoutingTraits<Target>::type>
192     {
193         typedef RouteImplementation2<typename RoutingTraits<Source>::type,
194                                      typename RoutingTraits<Target>::type> Base;
195
196     protected:
197         RouteImplementation(module::Module & module, Source & source, Target & target);
198     };
199
200 }}}
201
202 ///////////////////////////////ih.e////////////////////////////////////////
203 #endif
204
205 \f
206 // Local Variables:
207 // mode: c++
208 // fill-column: 100
209 // comment-column: 40
210 // c-file-style: "senf"
211 // indent-tabs-mode: nil
212 // ispell-local-dictionary: "american"
213 // compile-command: "scons -u test"
214 // End: