[go: up one dir, main page]

File: RLogNode.cpp

package info (click to toggle)
rlog 1.3.7-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 2,440 kB
  • ctags: 3,785
  • sloc: sh: 11,016; cpp: 1,533; makefile: 127
file content (248 lines) | stat: -rw-r--r-- 6,983 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*****************************************************************************
 * Author:   Valient Gough <vgough@pobox.com>
 *
 *****************************************************************************
 * Copyright (c) 2004, Valient Gough
 *
 * This library is free software; you can distribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL), as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the LGPL in the file COPYING for more
 * details.
 *
 */
		                                                                                

#include "RLogNode.h"

#include "Lock.h"

using namespace rlog;
using namespace std;


/*! @class rlog::RLogNode <rlog/RLogNode.h>
  @brief Core of publication system, forms activation network.

  RLogNode formes the core of the publication system.  It has two primary
  purposes :
  - link publications with subscribers
  - transfer meta-data in the form or node activations

  Both publishers (eg RLogPublisher) and subscribers (eg StdioNode) are
  derived from RLogNode, although RLogNode can be used entirely unmodified.

  An RLogNode contains a list of publishers which it is linked with.  It
  also contains a list of subscribers which it is linked with.
  Publications always flow from publishers to subscribers, and activation
  information flows the opposite direction from subscribers to publishers.

  An RLogNode by default acts as both a subscriber and publisher -- when
  it has been subscribed to another node and receives a publication it
  simply repeats the information to all of its subscribers.

  More specifically, it only publishes to subscribers who have also voiced
  an interest in receiving the publication.  If a node has no subscribers
  which are also interested (or no subscribers at all), then it can be said
  to be dormant and it tells the publishers that it is subscribed to that
  it is no longer interested.  This propogates all the way up to
  RLogPublishers which will disable the logging statement completely if
  there are no interested parties.

  @author Valient Gough
*/



/*! @brief Instantiate an empty RLogNode.  No subscribers or publishers..
*/
RLogNode::RLogNode()
{
}

/*! @brief Disconnects from any remaining subscribers and publishers
*/
RLogNode::~RLogNode()
{
    clear();
}

/*! @brief Force disconnection from any subscribers or publishers
*/
void
RLogNode::clear()
{
    Lock lock( &mutex );

    list<RLogNode*>::iterator it;
    //bool enabled = !interestList.empty();

    for(it = publishers.begin(); it != publishers.end(); ++it)
    {
	//if(enabled)
	    (*it)->isInterested( this, false );
	(*it)->dropSubscriber( this );
    }

    // unsubscribe
    // dropPublisher(.., false) tells not to callback to our dropSubscriber or
    // isInterested methods (othrewise we'd have locking issues)...
    for(it = subscribers.begin(); it != subscribers.end(); ++it)
	(*it)->dropPublisher( this, false );

    subscribers.clear();
    interestList.clear();

    setEnabled( false );
}

/*! @brief Publish data.

  This iterates over the list of subscribers which have stated interest and
  sends them the data.
*/
void
RLogNode::publish( const RLogData &data )
{
    Lock lock( &mutex );

    list<RLogNode*>::iterator it;
    for(it = interestList.begin(); it != interestList.end(); ++it)
	(*it)->publish( data );
}

/*! @brief Have this node subscribe to a new publisher.

  We become a subscriber of the publisher.  The publisher's addSubscriber()
  function is called to complete the link.

  If our node is active then we also tell the publisher that we want
  publications.
*/
void
RLogNode::addPublisher( RLogNode *publisher )
{
    Lock lock( &mutex );

    publishers.push_back( publisher );

    publisher->addSubscriber( this );

    if( !interestList.empty() )
	publisher->isInterested( this, true );
}

/*! @brief Drop our subscription to a publisher

  A callback parameter is provided to help avoid loops in the code which may
  affect the thread locking code.

  @param callback If True, then we call publisher->dropSubscriber() to make
  sure the publisher also drops us as a subscriber.
*/
void
RLogNode::dropPublisher( RLogNode *publisher, bool callback )
{
    Lock lock( &mutex );

    publishers.remove( publisher );

    if(callback)
    {
	if( !interestList.empty() )
	    publisher->isInterested( this, false );

	publisher->dropSubscriber( this );
    }
}

/*! @brief Add a subscriber.

  Normally a subscriber calls this for itself when it's addPublisher() method is
  called.
*/
void
RLogNode::addSubscriber( RLogNode *subscriber )
{
    Lock lock( &mutex );
    subscribers.push_back( subscriber );
}

/*! @brief Remove a subscriber.

  Normally a subscriber calls this for itself when it's dropPublisher() method
  is called.

  Note that the subscriber list is kept separate from the interest list.  If
  the subscriber is active, then you must undo that by calling
  isInterested(subscriber, false) in addition to dropSubscriber
*/
void
RLogNode::dropSubscriber( RLogNode *subscriber )
{
    Lock lock( &mutex );
    subscribers.remove( subscriber );
}

/*! @brief Change the state of one of our subscribers.  

  This allows a subscriber to say that it wants to be notified of publications
  or not.  The @a node should already be registered as a subscriber.

  If we previously had no interested parties and now we do, then we need to
  notify the publishers in our publishers list that we are now interested.

  If we previously had interested parties and we remove the last one, then we
  can notify the publishers that we are no longer interested..
*/
void
RLogNode::isInterested( RLogNode *node, bool interest)
{
    Lock lock( &mutex );
    bool changeInterest;

    if(interest)
    {
	changeInterest = interestList.empty();
	interestList.push_back( node );
    } else
    {
	interestList.remove( node );
	changeInterest = interestList.empty();
    }
	    
    if(changeInterest)
    {
	list<RLogNode*>::iterator it;
	for(it = publishers.begin(); it != publishers.end(); ++it)
	    (*it)->isInterested( this, interest );

	// let derived classes know that we have become active (or dormant)
	setEnabled( interest );
    }
}

/*! @brief Returns @e true if this node is active
  @return @e true if we have one or more interested subscribers, otherwise false
*/
bool
RLogNode::enabled() const
{
    return !interestList.empty();
}

/*! @brief For derived classes to get notified of activation status change.

  This is called by isInterested() when our state changes.  If @e true is
  passed, then this node has become active.  If @e false is passed, then this
  node has just become dormant.
*/
void
RLogNode::setEnabled(bool)
{
}