pvAccessCPP  7.1.2
pvAccess.h
1 /**
2  * Copyright - See the COPYRIGHT that is included with this distribution.
3  * pvAccessCPP is distributed subject to a Software License Agreement found
4  * in file LICENSE that is included with this distribution.
5  */
6 
7 #ifndef PVACCESS_H
8 #define PVACCESS_H
9 
10 #include <vector>
11 #include <set>
12 
13 #ifdef epicsExportSharedSymbols
14 # define pvAccessEpicsExportSharedSymbols
15 # undef epicsExportSharedSymbols
16 #endif
17 
18 #include <pv/pvData.h>
19 #include <pv/createRequest.h>
20 #include <pv/status.h>
21 #include <pv/bitSet.h>
22 
23 #ifdef pvAccessEpicsExportSharedSymbols
24 # define epicsExportSharedSymbols
25 # undef pvAccessEpicsExportSharedSymbols
26 #endif
27 
28 #include <pv/pvaVersion.h>
29 #include <pv/destroyable.h>
30 #include <pv/monitor.h>
31 
32 #include <shareLib.h>
33 
34 /* C++11 keywords
35  @code
36  struct Base {
37  virtual void foo();
38  };
39  struct Class : public Base {
40  virtual void foo() OVERRIDE FINAL;
41  };
42  @endcode
43  */
44 #ifndef FINAL
45 # if __cplusplus>=201103L
46 # define FINAL final
47 # else
48 # define FINAL
49 # endif
50 #endif
51 #ifndef OVERRIDE
52 # if __cplusplus>=201103L
53 # define OVERRIDE override
54 # else
55 # define OVERRIDE
56 # endif
57 #endif
58 
59 namespace epics {
60 //! Holds all PVA related
61 namespace pvAccess {
62 class Configuration;
63 
64 using epics::pvData::Requester;
65 using epics::pvData::RequesterPtr;
66 using epics::pvData::MessageType;
67 using epics::pvData::getMessageTypeName;
68 
69 // TODO add write-only?
70 // change names
71 enum AccessRights {
72  /**
73  * Neither read or write access is allowed.
74  */
75  none,
76  /**
77  * Read access is allowed but write access is not allowed.
78  */
79  read,
80  /**
81  * Both read and write access are allowed.
82  */
83  readWrite
84 };
85 
86 
87 /**
88  *
89  */
90 class epicsShareClass Lockable
91 {
92 public:
93  POINTER_DEFINITIONS(Lockable);
94 
95  virtual ~Lockable() {}
96 
97  virtual void lock() {}
98  virtual void unlock() {}
99 };
100 
101 /**
102  * Scope lock.
103  */
104 class epicsShareClass ScopedLock {
105  EPICS_NOT_COPYABLE(ScopedLock)
106 public:
107 
108  explicit ScopedLock(Lockable::shared_pointer const & li)
109  : lockable(li), locked(true) {
110  lockable->lock();
111  }
112 
113  ~ScopedLock() {
114  unlock();
115  }
116 
117  void lock() {
118  if(!locked) {
119  lockable->lock();
120  locked = true;
121  }
122  }
123 
124  void unlock() {
125  if(locked) {
126  lockable->unlock();
127  locked=false;
128  }
129  }
130 
131  bool ownsLock() const {
132  return locked;
133  }
134 
135 private:
136 
137  Lockable::shared_pointer const lockable;
138  bool locked;
139 };
140 
141 class Channel;
142 class ChannelProvider;
143 class ChannelArrayRequester;
144 class ChannelFindRequester;
145 class ChannelGetRequester;
146 class ChannelProcessRequester;
147 class ChannelPutRequester;
148 class ChannelPutGetRequester;
149 class ChannelRPCRequester;
150 
151 /** @brief Expose statistics related to network transport
152  *
153  * Various sub-classes of ChannelBaseRequester (for servers) or ChannelRequest (for clients)
154  * may by dynamic_cast<>able to NetStats.
155  */
156 struct epicsShareClass NetStats {
157  struct Counter {
158  size_t tx, rx;
159 
160  inline Counter() :tx(0u), rx(0u) {}
161  };
162  struct Stats {
163  std::string transportPeer;
164  Counter transportBytes;
165  Counter operationBytes;
166  bool populated;
167 
168  inline Stats() :populated(false) {}
169  };
170 
171  virtual ~NetStats();
172  //! Query current counter values
173  virtual void stats(Stats& s) const =0;
174 };
175 
176 //! Base for all Requesters (callbacks to client)
177 struct epicsShareClass ChannelBaseRequester : virtual public epics::pvData::Requester
178 {
179  POINTER_DEFINITIONS(ChannelBaseRequester);
180 
181  static size_t num_instances;
182 
183  ChannelBaseRequester();
184  virtual ~ChannelBaseRequester();
185 
186  /** Notification when underlying Channel becomes DISCONNECTED or DESTORYED
187  *
188  * (re)connection is notified through a sub-class *Connect() method.
189  *
190  * Any in-progress get()/put()/request()/start() is implicitly cancel()'d or stop()'d
191  * before this method is called.
192  *
193  * Ownership of any PVStructures passed to completion callbacks (eg. ChannelGetRequester::getDone() )
194  * is returned the operation
195  *
196  * @param destroy true for final disconnect.
197  */
198  virtual void channelDisconnect(bool destroy) {}
199 
200 private:
201  ChannelBaseRequester(const ChannelBaseRequester&);
202  ChannelBaseRequester& operator=(const ChannelBaseRequester&);
203 };
204 
205 /**
206  * Base interface for all channel requests (aka. Operations).
207  */
208 class epicsShareClass ChannelRequest : public virtual Destroyable, public Lockable {
209 public:
210  POINTER_DEFINITIONS(ChannelRequest);
211 
212  static size_t num_instances;
213 
214  ChannelRequest();
215  virtual ~ChannelRequest();
216 
217  /**
218  * Get a channel instance this request belongs to.
219  * @return the channel instance.
220  */
221  virtual std::tr1::shared_ptr<Channel> getChannel() = 0;
222 
223  /**
224  * Cancel any pending request.
225  * Completion will be reported via request's response callback:
226  * <ul>
227  * <li>if cancel() request is issued after the request was already complete, request success/failure completion will be reported and cancel() request ignored.</li>
228  * <li>if the request was actually canceled, cancellation completion is reported.</li>
229  * </ul>
230  */
231  virtual void cancel() = 0;
232 
233  /**
234  * Announce next request as last request.
235  * When last request will be completed (regardless of completion status) the remote and local instance will be destroyed.
236  */
237  virtual void lastRequest() = 0;
238 
239 private:
240  EPICS_NOT_COPYABLE(ChannelRequest)
241 };
242 
243 /**
244  * @brief Callback implemented by monitor clients.
245  *
246  * Requester for ChannelMonitor.
247  * @author mrk
248  */
249 class epicsShareClass MonitorRequester : public ChannelBaseRequester {
250  public:
251  POINTER_DEFINITIONS(MonitorRequester);
252  typedef Monitor operation_type;
253 
254  virtual ~MonitorRequester(){}
255  /**
256  * Underlying Channel is connected and operation setup is complete.
257  * Call start() to begin subscription updates.
258  *
259  * @param status Completion status.
260  * @param monitor The monitor
261  * @param structure The structure defining the data.
262  */
263  virtual void monitorConnect(epics::pvData::Status const & status,
264  MonitorPtr const & monitor, epics::pvData::StructureConstPtr const & structure) = 0;
265  /**
266  * Monitor queue is not empty.
267  *
268  * The requester must call Monitor.poll to get data.
269  * @param monitor The monitor.
270  */
271  virtual void monitorEvent(MonitorPtr const & monitor) = 0;
272  /**
273  * No more subscription update will be sent.
274  * @param monitor The monitor.
275  */
276  virtual void unlisten(MonitorPtr const & monitor) = 0;
277 };
278 
279 /**
280  * Request to put and get Array Data.
281  * The data is either taken from or put in the PVArray returned by ChannelArrayRequester.channelArrayConnect.
282  */
283 class epicsShareClass ChannelArray : public ChannelRequest {
284 public:
285  POINTER_DEFINITIONS(ChannelArray);
286  typedef ChannelArrayRequester requester_type;
287 
288  virtual ~ChannelArray() {}
289 
290  /**
291  * put to the remote array.
292  *
293  * Ownership of the PVArray is transferred to the ChannelArray until ChannelArrayRequester::putArrayDone()
294  * or ChannelArrayRequester::channelDisconnect() is called.
295  *
296  * @param putArray array to put.
297  * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester::channelArrayConnect.
298  * @param count The number of elements to put, 0 means "entire array".
299  * @param stride 1 means all the elements from offset to count, 2 means every other, 3 means every third, etc.
300  */
301  virtual void putArray(
302  epics::pvData::PVArray::shared_pointer const & putArray,
303  size_t offset = 0, size_t count = 0, size_t stride = 1) = 0;
304 
305  /**
306  * get from the remote array.
307  *
308  * Ownership of the PVArray previously passed to ChannelArrayRequester::getArrayDone()
309  * is returned to the ChannelArray from the ChannelArrayRequester.
310  *
311  * @param offset The offset in the remote array, i.e. the PVArray returned by ChannelArrayRequester::channelArrayConnect.
312  * @param count The number of elements to get, 0 means "till the end of an array".
313  * @param stride 1 means all the elements from offset to count, 2 means every other, 3 means every third, etc.
314  */
315  virtual void getArray(size_t offset = 0, size_t count = 0, size_t stride = 1) = 0;
316 
317  /**
318  * Get the length.
319  */
320  virtual void getLength() = 0;
321 
322  /**
323  * Set the length and/or the capacity.
324  * @param length The new length.
325  */
326  virtual void setLength(size_t length) = 0;
327 };
328 
329 /**
330  * The Requester for a ChannelArray.
331  */
332 class epicsShareClass ChannelArrayRequester : public ChannelBaseRequester {
333 public:
334  POINTER_DEFINITIONS(ChannelArrayRequester);
335  typedef ChannelArray operation_type;
336 
337  virtual ~ChannelArrayRequester() {}
338 
339  /**
340  * Underlying Channel is connected and operation setup is complete.
341  * May call putArray(), getArray(), getLength(), or setLength() to execute.
342  *
343  * @param status Completion status.
344  * @param channelArray The channelArray interface or nullptr if the request failed.
345  * @param pvArray The PVArray that holds the data or nullptr if the request failed.
346  */
347  virtual void channelArrayConnect(
348  const epics::pvData::Status& status,
349  ChannelArray::shared_pointer const & channelArray,
350  epics::pvData::Array::const_shared_pointer const & array) = 0;
351 
352  /**
353  * The request is done. This is always called with no locks held.
354  *
355  * Ownership of PVArray passed to ChannelArray::putArray() returns to ChannelArrayRequester
356  *
357  * @param status Completion status.
358  * @param channelArray The channelArray interface.
359  */
360  virtual void putArrayDone(
361  const epics::pvData::Status& status,
362  ChannelArray::shared_pointer const & channelArray) = 0;
363 
364  /**
365  * The request is done. This is always called with no locks held.
366  *
367  * Ownership of the PVArray is transfered to the ChannelArrayRequester until
368  * a subsequent call to ChannelArray::getArray() or ChannelArrayRequester::channelDisconnect().
369  *
370  * @param status Completion status.
371  * @param channelArray The channelArray interface.
372  * @param pvArray The PVArray that holds the data or nullptr if the request failed.
373  */
374  virtual void getArrayDone(
375  const epics::pvData::Status& status,
376  ChannelArray::shared_pointer const & channelArray,
377  epics::pvData::PVArray::shared_pointer const & pvArray) = 0;
378 
379  /**
380  * The request is done. This is always called with no locks held.
381  * @param status Completion status.
382  * @param channelArray The channelArray interface.
383  * @param length The length of the array, 0 if the request failed.
384  */
385  virtual void getLengthDone(
386  const epics::pvData::Status& status,
387  ChannelArray::shared_pointer const & channelArray,
388  size_t length) = 0;
389 
390  /**
391  * The request is done. This is always called with no locks held.
392  * @param status Completion status.
393  * @param channelArray The channelArray interface.
394  */
395  virtual void setLengthDone(
396  const epics::pvData::Status& status,
397  ChannelArray::shared_pointer const & channelArray) = 0;
398 };
399 
400 
401 /**
402  *
403  */
404 class epicsShareClass ChannelFind : public Destroyable {
405  EPICS_NOT_COPYABLE(ChannelFind)
406 public:
407  POINTER_DEFINITIONS(ChannelFind);
408  typedef ChannelFindRequester requester_type;
409 
410  ChannelFind() {}
411  virtual ~ChannelFind() {}
412 
413  virtual std::tr1::shared_ptr<ChannelProvider> getChannelProvider() = 0;
414  virtual void cancel() = 0;
415 
416  //! Allocate a no-op ChannelFind. This is sufficient for most, if not all, ChannelProvider implementations.
417  //! Holds only a weak_ptr<ChannelProvider>
418  static ChannelFind::shared_pointer buildDummy(const std::tr1::shared_ptr<ChannelProvider>& provider);
419 };
420 
421 struct PeerInfo; // see pv/security.h
422 
423 /**
424  *
425  */
426 class epicsShareClass ChannelFindRequester {
427 public:
428  POINTER_DEFINITIONS(ChannelFindRequester);
429  typedef ChannelFind operation_type;
430 
431  virtual ~ChannelFindRequester() {}
432 
433  /**
434  * @param status Completion status.
435  */
436  virtual void channelFindResult(
437  const epics::pvData::Status& status,
438  ChannelFind::shared_pointer const & channelFind,
439  bool wasFound) = 0;
440 
441  /**
442  * @brief Return information on requesting peer if applicable.
443  *
444  * A server-type ChannelProvider will use this method to discover if a remote client
445  * has provided credentials which may be used in access control decisions.
446  *
447  * The returned PeerInfo is only required to have valid values for: peer, transport, and transportVersion.
448  * PeerInfo::authority may be empty if authentication has not yet occured (UDP search).
449  *
450  * Default implementation returns NULL.
451  *
452  * isConnected()==true and getPeerInfo()==NULL when the ChannelProvider does not provide
453  * information about the peer. This should be treated as an unauthenticated, anonymous,
454  * peer.
455  *
456  * The returned instance must not change, and a different instance should be returned
457  * if/when peer information changes (eg. after reconnect).
458  *
459  * May return !NULL when !isConnected(). getPeerInfo() must be called _before_
460  * testing isConnected() in situations where connection state is being polled.
461  */
462  virtual std::tr1::shared_ptr<const PeerInfo> getPeerInfo()
463  { return std::tr1::shared_ptr<const PeerInfo>(); }
464 };
465 
466 /**
467  *
468  */
469 class epicsShareClass ChannelListRequester {
470 public:
471  POINTER_DEFINITIONS(ChannelListRequester);
472  typedef ChannelFind operation_type;
473 
474  virtual ~ChannelListRequester() {}
475 
476  /**
477  * @param status Completion status.
478  */
479  virtual void channelListResult(
480  const epics::pvData::Status& status,
481  ChannelFind::shared_pointer const & channelFind,
482  epics::pvData::PVStringArray::const_svector const & channelNames,
483  bool hasDynamic) = 0;
484 };
485 
486 /**
487  * Request to get data from a channel.
488  */
489 class epicsShareClass ChannelGet : public ChannelRequest {
490 public:
491  POINTER_DEFINITIONS(ChannelGet);
492  typedef ChannelGetRequester requester_type;
493 
494  virtual ~ChannelGet() {}
495 
496  /**
497  * Get data from the channel.
498  *
499  * Ownership of the PVStructure passed to ChannelGetRequester::getDone() is
500  * returned to the ChannelGet.
501  *
502  * Completion status is reported by calling ChannelGetRequester::getDone() callback.
503  */
504  virtual void get() = 0;
505 };
506 
507 
508 /**
509  * Requester for channelGet.
510  */
511 class epicsShareClass ChannelGetRequester : public ChannelBaseRequester {
512 public:
513  POINTER_DEFINITIONS(ChannelGetRequester);
514  typedef ChannelGet operation_type;
515 
516  virtual ~ChannelGetRequester() {}
517 
518  /**
519  * The client and server have both completed the createChannelGet request.
520  * @param status Completion status.
521  * @param channelGet The channelGet interface or nullptr if the request failed.
522  * @param structure The introspection interface of requested get structure or nullptr if the request failed.
523  */
524  virtual void channelGetConnect(
525  const epics::pvData::Status& status,
526  ChannelGet::shared_pointer const & channelGet,
527  epics::pvData::Structure::const_shared_pointer const & structure) = 0;
528 
529  /**
530  * The request is done. This is always called with no locks held.
531  *
532  * Ownership of the PVStructure is passed to the ChannelGetRequester until a subsequent call to
533  * ChannelGet::get() or ChannelGetRequester::channelDisconnect()
534  *
535  * @param status Completion status.
536  * @param channelGet The channelGet interface.
537  * @param pvStructure The PVStructure that holds the data or nullptr if the request failed.
538  * @param bitSet The bitSet for that shows what data has changed or nullptr if the request failed.
539  */
540  virtual void getDone(
541  const epics::pvData::Status& status,
542  ChannelGet::shared_pointer const & channelGet,
543  epics::pvData::PVStructure::shared_pointer const & pvStructure,
544  epics::pvData::BitSet::shared_pointer const & bitSet) = 0;
545 };
546 
547 
548 /**
549  * ChannelProcess - request that a channel be processed..
550  */
551 class epicsShareClass ChannelProcess : public ChannelRequest {
552 public:
553  POINTER_DEFINITIONS(ChannelProcess);
554  typedef ChannelProcessRequester requester_type;
555 
556  virtual ~ChannelProcess() {}
557 
558  /**
559  * Issue a process request.
560  * Completion status is reported by calling ChannelProcessRequester.processDone() callback.
561  */
562  virtual void process() = 0;
563 };
564 
565 
566 /**
567  * Requester for channelProcess.
568  */
569 class epicsShareClass ChannelProcessRequester : public ChannelBaseRequester {
570 public:
571  POINTER_DEFINITIONS(ChannelProcessRequester);
572  typedef ChannelProcess operation_type;
573 
574  virtual ~ChannelProcessRequester() {}
575 
576  /**
577  * The client and server have both completed the createChannelProcess request.
578  * @param status Completion status.
579  * @param channelProcess The channelProcess interface or nullptr if the client could not become
580  * the record processor.
581  */
582  virtual void channelProcessConnect(
583  const epics::pvData::Status& status,
584  ChannelProcess::shared_pointer const & channelProcess) = 0;
585 
586  /**
587  * The process request is done. This is always called with no locks held.
588  * @param status Completion status.
589  * @param channelProcess The channelProcess interface.
590  */
591  virtual void processDone(
592  const epics::pvData::Status& status,
593  ChannelProcess::shared_pointer const & channelProcess) = 0;
594 };
595 
596 
597 /**
598  * Interface for a channel access put request.
599  */
600 class epicsShareClass ChannelPut : public ChannelRequest {
601 public:
602  POINTER_DEFINITIONS(ChannelPut);
603  typedef ChannelPutRequester requester_type;
604 
605  virtual ~ChannelPut() {}
606 
607  /**
608  * Put data to a channel.
609  *
610  * Completion status is reported by calling ChannelPutRequester::putDone()
611  *
612  * Ownership of the PVStructure is transfered to the ChannelPut until
613  * ChannelPutRequester::putDone() or ChannelPutRequester::channelDisconnect()
614  * is called.
615  *
616  * @param pvPutStructure The PVStructure that holds the putData.
617  * @param putBitSet putPVStructure bit-set (selects what fields to put).
618  */
619  virtual void put(
620  epics::pvData::PVStructure::shared_pointer const & pvPutStructure,
621  epics::pvData::BitSet::shared_pointer const & putBitSet) = 0;
622 
623  /**
624  * Get the current data.
625  *
626  * Ownership transfer as with ChannelGet::get()
627  */
628  virtual void get() = 0;
629 
630 };
631 
632 /**
633  * Requester for ChannelPut.
634  */
635 class epicsShareClass ChannelPutRequester : public ChannelBaseRequester {
636 public:
637  POINTER_DEFINITIONS(ChannelPutRequester);
638  typedef ChannelPut operation_type;
639 
640  virtual ~ChannelPutRequester() {}
641 
642  /**
643  * The client and server have both processed the createChannelPut request.
644  * @param status Completion status.
645  * @param channelPut The channelPut interface or null if the request failed.
646  * @param structure The introspection interface of requested put/get structure or nullptr if the request failed.
647  */
648  virtual void channelPutConnect(
649  const epics::pvData::Status& status,
650  ChannelPut::shared_pointer const & channelPut,
651  epics::pvData::Structure::const_shared_pointer const & structure) = 0;
652 
653  /**
654  * The request is done. This is always called with no locks held.
655  * @param status Completion status.
656  * @param channelPut The channelPut interface.
657  */
658  virtual void putDone(
659  const epics::pvData::Status& status,
660  ChannelPut::shared_pointer const & channelPut) = 0;
661 
662  /**
663  * The get request is done. This is always called with no locks held.
664  *
665  * Ownership transfer as with ChannelGetRequester::getDone()
666  *
667  * @param status Completion status.
668  * @param channelPut The channelPut interface.
669  * @param pvStructure The PVStructure that holds the data or nullptr if the request failed.
670  * @param bitSet The bitSet for that shows what data has changed or nullptr if the request failed.
671  */
672  virtual void getDone(
673  const epics::pvData::Status& status,
674  ChannelPut::shared_pointer const & channelPut,
675  epics::pvData::PVStructure::shared_pointer const & pvStructure,
676  epics::pvData::BitSet::shared_pointer const & bitSet) = 0;
677 };
678 
679 
680 /**
681  * Channel access put/get request.
682  * The put is performed first, followed optionally by a process request, and then by a get request.
683  */
684 class epicsShareClass ChannelPutGet : public ChannelRequest {
685 public:
686  POINTER_DEFINITIONS(ChannelPutGet);
687  typedef ChannelPutGetRequester requester_type;
688 
689  virtual ~ChannelPutGet() {}
690 
691  /**
692  * Issue a put/get request. If process was requested when the ChannelPutGet was created this is a put, process, get.
693  * Completion status is reported by calling ChannelPutGetRequester.putGetDone() callback.
694  * @param pvPutStructure The PVStructure that holds the putData.
695  * @param putBitSet putPVStructure bit-set (selects what fields to put).
696  */
697  virtual void putGet(
698  epics::pvData::PVStructure::shared_pointer const & pvPutStructure,
699  epics::pvData::BitSet::shared_pointer const & putBitSet) = 0;
700 
701  /**
702  * Get the put PVStructure. The record will not be processed.
703  * Completion status is reported by calling ChannelPutGetRequester.getPutDone() callback.
704  */
705  virtual void getPut() = 0;
706 
707  /**
708  * Get the get PVStructure. The record will not be processed.
709  * Completion status is reported by calling ChannelPutGetRequester.getGetDone() callback.
710  */
711  virtual void getGet() = 0;
712 };
713 
714 
715 /**
716  * Requester for ChannelPutGet.
717  */
718 class epicsShareClass ChannelPutGetRequester : public ChannelBaseRequester
719 {
720 public:
721  POINTER_DEFINITIONS(ChannelPutGetRequester);
722  typedef ChannelPutGet operation_type;
723 
724  virtual ~ChannelPutGetRequester() {}
725 
726  /**
727  * The client and server have both completed the createChannelPutGet request.
728  * @param status Completion status.
729  * @param channelPutGet The channelPutGet interface or null if the request failed.
730  * @param putStructure The put structure introspection data or nullptr if the request failed.
731  * @param getStructure The get structure introspection data or nullptr if the request failed.
732  */
733  virtual void channelPutGetConnect(
734  const epics::pvData::Status& status,
735  ChannelPutGet::shared_pointer const & channelPutGet,
736  epics::pvData::Structure::const_shared_pointer const & putStructure,
737  epics::pvData::Structure::const_shared_pointer const & getStructure) = 0;
738 
739  /**
740  * The putGet request is done. This is always called with no locks held.
741  * @param status Completion status.
742  * @param channelPutGet The channelPutGet interface.
743  * @param pvGetStructure The PVStructure that holds the getData or nullptr if the request failed.
744  * @param getBitSet getPVStructure changed bit-set or nullptr if the request failed.
745  */
746  virtual void putGetDone(
747  const epics::pvData::Status& status,
748  ChannelPutGet::shared_pointer const & channelPutGet,
749  epics::pvData::PVStructure::shared_pointer const & pvGetStructure,
750  epics::pvData::BitSet::shared_pointer const & getBitSet) = 0;
751 
752  /**
753  * The getPut request is done. This is always called with no locks held.
754  * @param status Completion status.
755  * @param channelPutGet The channelPutGet interface.
756  * @param pvPutStructure The PVStructure that holds the putData or nullptr if the request failed.
757  * @param putBitSet putPVStructure changed bit-set or nullptr if the request failed.
758  */
759  virtual void getPutDone(
760  const epics::pvData::Status& status,
761  ChannelPutGet::shared_pointer const & channelPutGet,
762  epics::pvData::PVStructure::shared_pointer const & pvPutStructure,
763  epics::pvData::BitSet::shared_pointer const & putBitSet) = 0;
764 
765  /**
766  * The getGet request is done. This is always called with no locks held.
767  * @param status Completion status.
768  * @param channelPutGet The channelPutGet interface.
769  * @param pvGetStructure The PVStructure that holds the getData or nullptr if the request failed.
770  * @param getBitSet getPVStructure changed bit-set or nullptr if the request failed.
771  */
772  virtual void getGetDone(
773  const epics::pvData::Status& status,
774  ChannelPutGet::shared_pointer const & channelPutGet,
775  epics::pvData::PVStructure::shared_pointer const & pvGetStructure,
776  epics::pvData::BitSet::shared_pointer const & getBitSet) = 0;
777 };
778 
779 
780 /**
781  * Handle for an RPC operation
782  */
783 class epicsShareClass ChannelRPC : public ChannelRequest {
784 public:
785  POINTER_DEFINITIONS(ChannelRPC);
786  typedef ChannelRPCRequester requester_type;
787 
788  virtual ~ChannelRPC() {}
789 
790  /**
791  * Issue an RPC request to the channel.
792  *
793  * Completion status is reported by calling ChannelRPCRequester::requestDone() callback,
794  * which may be called from this method.
795  *
796  * @pre The underlying Channel must be connected, and this ChannelRPC valid.
797  * Otherwise the ChannelRPCRequester::requestDone() is called with an error.
798  *
799  * @post After calling request(), the requestDone() callback will be called at some later time.
800  * May call ChannelRPC::cancel() to request to abort() this operation.
801  *
802  * @param pvArgument The argument structure for an RPC request.
803  */
804  virtual void request(epics::pvData::PVStructure::shared_pointer const & pvArgument) = 0;
805 };
806 
807 
808 /**
809  * Notifications associated with Channel::createChannelRPC()
810  *
811  * No locks may be held while calling these methods.
812  */
813 class epicsShareClass ChannelRPCRequester : public ChannelBaseRequester {
814 public:
815  POINTER_DEFINITIONS(ChannelRPCRequester);
816  typedef ChannelRPC operation_type;
817 
818  virtual ~ChannelRPCRequester() {}
819 
820  /**
821  * RPC creation request satisfied.
822  *
823  * Must check status.isOk().
824  *
825  * On Success, a non-NULL 'operation' is provided.
826  * This is the same pointer which was, or will be, returned from Channel::createChannelRPC().
827  *
828  * It is allowed to call ChannelRPC::request() from within this method.
829  */
830  virtual void channelRPCConnect(
831  const epics::pvData::Status& status,
832  ChannelRPC::shared_pointer const & operation) = 0;
833 
834  /**
835  * RPC request (execution) completed.
836  *
837  * Must check status.isOk().
838  *
839  * On Success, a non-NULL 'pvResponse' is provided.
840  *
841  * It is allowed to call ChannelRPC::request() from within this method.
842  */
843  virtual void requestDone(
844  const epics::pvData::Status& status,
845  ChannelRPC::shared_pointer const & operation,
846  epics::pvData::PVStructure::shared_pointer const & pvResponse) = 0;
847 };
848 
849 
850 /**
851  * Completion notification for Channel::getField()
852  */
853 class epicsShareClass GetFieldRequester : public ChannelBaseRequester {
854 public:
855  POINTER_DEFINITIONS(GetFieldRequester);
856 
857  virtual ~GetFieldRequester() {}
858 
859  /**
860  * Check status.isOk() to determine success.
861  * On success the 'field' will be non-NULL.
862  * On failure 'field' will be NULL.
863  *
864  * @param status Completion status.
865  * @param field The Structure for the request.
866  */
867  virtual void getDone(
868  const epics::pvData::Status& status,
869  epics::pvData::FieldConstPtr const & field) = 0; // TODO naming convention
870 
871 };
872 
873 class ChannelRequester;
874 
875 /**
876  * The interface through which Operations (get, put, monitor, ...) are initiated.
877  *
878  * Handle for a Channel returned by ChannelProvider::createChannel()
879  *
880  * At any given moment a Channel may be CONNECTED or DISCONNECTED. (NEVER_CONNECTED and DESTORYED are special cases of DISCONNECTED)
881  *
882  * A Channel is required to honor calls to Channel::create*() methods while in the disconnected state.
883  *
884  * A Channel is required to maintain a strong reference (shared_ptr<>) to the ChannelProvider through which it was created.
885  */
886 class epicsShareClass Channel :
887  public Requester,
888  public Destroyable
889 {
890  EPICS_NOT_COPYABLE(Channel)
891 public:
892  POINTER_DEFINITIONS(Channel);
893  typedef ChannelRequester requester_type;
894 
895  static size_t num_instances;
896 
897  Channel();
898  virtual ~Channel();
899 
900  virtual std::string getRequesterName();
901  virtual void message(std::string const & message, epics::pvData::MessageType messageType);
902 
903  /**
904  * Channel connection status.
905  */
906  enum ConnectionState {
907  NEVER_CONNECTED, CONNECTED, DISCONNECTED, DESTROYED
908  };
909 
910  static const char* ConnectionStateNames[];
911 
912  /**
913  * The ChannelProvider from which this Channel was requested.
914  * May never be NULL.
915  */
916  virtual std::tr1::shared_ptr<ChannelProvider> getProvider() = 0;
917 
918  /**
919  * Returns the channel's remote address, signal name, etc...
920  * For example:
921  * - client side channel would return server's address, e.g. "/192.168.1.101:5064"
922  * - server side channel would return underlying bus address, e.g. "#C0 S1".
923  *
924  * The value returned here will changed depending on the connection status.
925  * A disconnected channel should return an empty() string.
926  **/
927  virtual std::string getRemoteAddress() = 0;
928 
929  /**
930  * Poll the connection state in more detail
931  **/
932  virtual ConnectionState getConnectionState();
933 
934  /**
935  * The name passed to ChannelProvider::createChannel()
936  */
937  virtual std::string getChannelName() = 0;
938 
939  /**
940  * The ChannelRequester passed to ChannelProvider::createChannel()
941  *
942  * @throws std::tr1::bad_weak_ptr
943  */
944  virtual std::tr1::shared_ptr<ChannelRequester> getChannelRequester() = 0;
945 
946  /**
947  * Poll connection state
948  */
949  virtual bool isConnected();
950 
951  /**
952  * Initiate a request to retrieve a description of the structure of this Channel.
953  *
954  * While the type described by calls to getField() should match what is provided for all operations except RPC.
955  *
956  * GetFieldRequester::getDone() will be called before getField() returns, or at some time afterwards.
957  *
958  * @param Requester The Requester.
959  * @param subField Empty string, or the field name of a sub-structure.
960  */
961  virtual void getField(GetFieldRequester::shared_pointer const & requester,std::string const & subField);
962 
963  /**
964  * Not useful...
965  *
966  * @param pvField The field for which access rights is desired.
967  * @return The access rights.
968  */
969  virtual AccessRights getAccessRights(epics::pvData::PVField::shared_pointer const & pvField);
970 
971  /**
972  * Initiate a request for a Process action.
973  *
974  * ChannelProcessRequester::channelProcessConnect() may be called before createChannelProcess() returns, or at some time afterwards.
975  *
976  * Failure is indicated by a call to channelProcessConnect with !Error::isOk()
977  *
978  * @pre The Channel need not be CONNECTED
979  *
980  * @post The returned ChannelProcess will hold a strong reference to the provided ChannelProcessRequester.
981  *
982  * @post Returned shared_ptr<ChannelProcess> will have unique()==true.
983  *
984  * @return A non-NULL ChannelProcess unless channelProcessConnect() called with an Error
985  *
986  * @note The default implementation proxies using createChannelPut() and ChannelPut::put() with no data (empty bit set)
987  */
988  virtual ChannelProcess::shared_pointer createChannelProcess(
989  ChannelProcessRequester::shared_pointer const & requester,
990  epics::pvData::PVStructure::shared_pointer const & pvRequest);
991 
992  /**
993  * Initiate a request for a Get action.
994  *
995  * ChannelGetRequester::channelGetConnect() may be called before createChannelGet() returns, or at some time afterwards.
996  *
997  * Failure is indicated by a call to channelProcessConnect with !Error::isOk()
998  *
999  * @pre The Channel need not be CONNECTED
1000  *
1001  * @post The returned ChannelGet will hold a strong reference to the provided ChannelGetRequester.
1002  *
1003  * @post Returned shared_ptr<ChannelGet> will have unique()==true.
1004  *
1005  * @return A non-NULL ChannelGet unless channelGetConnect() called with an Error
1006  *
1007  * @note The default implementation proxies to createChannelPut()
1008  */
1009  virtual ChannelGet::shared_pointer createChannelGet(
1010  ChannelGetRequester::shared_pointer const & requester,
1011  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1012 
1013  /**
1014  * Initiate a request for a Put action.
1015  *
1016  * ChannelPutRequester::channelPutConnect() may be called before createChannelPut() returns, or at some time afterwards.
1017  *
1018  * Failure is indicated by a call to channelProcessConnect with !Error::isOk()
1019  *
1020  * @pre The Channel need not be CONNECTED
1021  *
1022  * @post The returned ChannelPut will hold a strong reference to the provided ChannelPutRequester.
1023  *
1024  * @post Returned shared_ptr<ChannelPut> will have unique()==true.
1025  *
1026  * @return A non-NULL ChannelPut unless channelPutConnect() called with an Error
1027  *
1028  * @note The default implementation yields a not implemented error
1029  */
1030  virtual ChannelPut::shared_pointer createChannelPut(
1031  ChannelPutRequester::shared_pointer const & requester,
1032  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1033 
1034  /**
1035  * Initiate a request for a PutGet action.
1036  *
1037  * ChannelPutGetRequester::channelPutGetConnect() may be called before createChannelPutGet() returns, or at some time afterwards.
1038  *
1039  * Failure is indicated by a call to channelProcessConnect with !Error::isOk()
1040  *
1041  * @pre The Channel need not be CONNECTED
1042  *
1043  * @post The returned ChannelPutGet will hold a strong reference to the provided ChannelPutGetRequester.
1044  *
1045  * @post Returned shared_ptr<ChannelPutGet> will have unique()==true.
1046  *
1047  * @return A non-NULL ChannelPutGet unless channelPutGetConnect() called with an Error
1048  *
1049  * @note The default implementation yields a not implemented error
1050  */
1051  virtual ChannelPutGet::shared_pointer createChannelPutGet(
1052  ChannelPutGetRequester::shared_pointer const & requester,
1053  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1054 
1055  /**
1056  * Initiate a request for a RPC action.
1057  *
1058  * ChannelRPCRequester::channelRPCConnect() may be called before createChannelRPC() returns, or at some time afterwards.
1059  *
1060  * Failure is indicated by a call to channelProcessConnect with !Error::isOk()
1061  *
1062  * @pre The Channel need not be CONNECTED
1063  *
1064  * @post The returned ChannelRPC will hold a strong reference to the provided ChannelRPCRequester.
1065  *
1066  * @post Returned shared_ptr<ChannelRPC> will have unique()==true.
1067  *
1068  * @return A non-NULL ChannelRPC unless channelRPCConnect() called with an Error
1069  *
1070  * @note The default implementation yields a not implemented error
1071  */
1072  virtual ChannelRPC::shared_pointer createChannelRPC(
1073  ChannelRPCRequester::shared_pointer const & requester,
1074  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1075 
1076  /**
1077  * Initiate a request for a Monitor action.
1078  *
1079  * MonitorRequester::channelMonitorConnect() may be called before createMonitor() returns, or at some time afterwards.
1080  *
1081  * Failure is indicated by a call to monitorConnect with !Error::isOk()
1082  *
1083  * @pre The Channel need not be CONNECTED
1084  *
1085  * @post The returned Monitor will hold a strong reference to the provided MonitorRequester.
1086  *
1087  * @post Returned shared_ptr<Monitor> will have unique()==true.
1088  *
1089  * @return A non-NULL Monitor unless monitorConnect() called with an Error
1090  *
1091  * @note The default implementation yields a not implemented error
1092  */
1093  virtual Monitor::shared_pointer createMonitor(
1094  MonitorRequester::shared_pointer const & requester,
1095  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1096 
1097  /**
1098  * Initiate a request for a Array (get) action.
1099  *
1100  * ChannelArrayRequester::channelArrayConnect() may be called before createChannelArray() returns, or at some time afterwards.
1101  *
1102  * Failure is indicated by a call to channelArrayConnect with !Error::isOk()
1103  *
1104  * @pre The Channel need not be CONNECTED
1105  *
1106  * @post The returned ChannelArray will hold a strong reference to the provided MonitorRequester.
1107  *
1108  * @post Returned shared_ptr<ChannelArray> will have unique()==true.
1109  *
1110  * @return A non-NULL ChannelArray unless channelArrayConnect() called with an Error
1111  *
1112  * Create a ChannelArray.
1113  * @param channelArrayRequester The ChannelArrayRequester
1114  * @param pvRequest Additional options (e.g. triggering).
1115  * @return <code>ChannelArray</code> instance.
1116  *
1117  * @note The default implementation yields a not implemented error
1118  */
1119  virtual ChannelArray::shared_pointer createChannelArray(
1120  ChannelArrayRequester::shared_pointer const & requester,
1121  epics::pvData::PVStructure::shared_pointer const & pvRequest);
1122 
1123  /**
1124  * Prints detailed information about the context to the standard output stream.
1125  */
1126  virtual void printInfo() { printInfo(std::cout); }
1127 
1128  /**
1129  * Prints detailed information about the context to the specified output stream.
1130  * @param out the output stream.
1131  */
1132  virtual void printInfo(std::ostream& out) {}
1133 };
1134 
1135 
1136 /**
1137  * Event notifications associated with Channel life-cycle.
1138  *
1139  * See ChannelProvider::createChannel()
1140  */
1141 class epicsShareClass ChannelRequester : public virtual Requester
1142 {
1143  ChannelRequester(const ChannelRequester&);
1144  ChannelRequester& operator=(const ChannelRequester&);
1145 public:
1146  POINTER_DEFINITIONS(ChannelRequester);
1147  typedef Channel operation_type;
1148 
1149  static size_t num_instances;
1150 
1151  ChannelRequester();
1152  virtual ~ChannelRequester();
1153 
1154  /**
1155  * The request made with ChannelProvider::createChannel() is satisfied.
1156  *
1157  * Will be called at most once for each call to createChannel().
1158  *
1159  * The Channel passed here must be the same as was returned by createChannel(), if it has returned.
1160  * Note that this method may be called before createChanel() returns.
1161  *
1162  * Status::isOk() indicates that the Channel is valid.
1163  * Calls to Channel methods can be made from this method, and later until Channel::destroy() is called.
1164  *
1165  * !Status::isOk() indicates that the Channel is not available.
1166  * No calls to the Channel are permitted.
1167  * channelStateChange() will never be called.
1168  *
1169  * Caller must hold no locks.
1170  *
1171  * @param status Completion status.
1172  * @param channel The channel.
1173  */
1174  virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) = 0;
1175 
1176  /**
1177  * Called occasionally after channelCreated() with Status::isOk() to give notification of
1178  * connection state changes.
1179  *
1180  * Caller must hold no locks.
1181  *
1182  * @param c The channel.
1183  * @param connectionState The new connection state.
1184  */
1185  virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState) = 0;
1186 
1187  /**
1188  * @brief Return information on connected peer if applicable.
1189  *
1190  * A server-type ChannelProvider will use this method to discover if a remote client
1191  * has provided credentials which may be used in access control decisions.
1192  *
1193  * Default implementation returns NULL.
1194  *
1195  * isConnected()==true and getPeerInfo()==NULL when the ChannelProvider does not provide
1196  * information about the peer. This should be treated as an unauthenticated, anonymous,
1197  * peer.
1198  *
1199  * The returned instance must not change, and a different instance should be returned
1200  * if/when peer information changes (eg. after reconnect).
1201  *
1202  * May return !NULL when !isConnected(). getPeerInfo() must be called _before_
1203  * testing isConnected() in situations where connection state is being polled.
1204  */
1205  virtual std::tr1::shared_ptr<const PeerInfo> getPeerInfo();
1206 };
1207 
1208 //! Used when ChannelProvider::createChannel() is passed a NULL ChannelRequester
1209 struct epicsShareClass DefaultChannelRequester : public ChannelRequester
1210 {
1211  virtual ~DefaultChannelRequester() {}
1212  virtual std::string getRequesterName() OVERRIDE FINAL;
1213  virtual void channelCreated(const epics::pvData::Status& status, Channel::shared_pointer const & channel) OVERRIDE FINAL;
1214  virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState) OVERRIDE FINAL;
1215  static ChannelRequester::shared_pointer build();
1216 };
1217 
1218 /**
1219  * @brief The FlushStrategy enum
1220  */
1221 enum FlushStrategy {
1222  IMMEDIATE, DELAYED, USER_CONTROLED
1223 };
1224 
1225 /**
1226  * An instance of a Client or Server.
1227  *
1228  * Uniquely configurable (via ChannelProviderFactory::newInstance(Configuration*)
1229  */
1230 class epicsShareClass ChannelProvider : public Destroyable
1231 {
1232  EPICS_NOT_COPYABLE(ChannelProvider)
1233 public:
1234  POINTER_DEFINITIONS(ChannelProvider);
1235 
1236  /** Minimal priority. */
1237  static const short PRIORITY_MIN = 0;
1238  /** Maximal priority. */
1239  static const short PRIORITY_MAX = 99;
1240  /** Default priority. */
1241  static const short PRIORITY_DEFAULT = PRIORITY_MIN;
1242  /** DB links priority. */
1243  static const short PRIORITY_LINKS_DB = PRIORITY_MAX;
1244  /** Archive priority. */
1245  static const short PRIORITY_ARCHIVE = (PRIORITY_MAX + PRIORITY_MIN) / 2;
1246  /** OPI priority. */
1247  static const short PRIORITY_OPI = PRIORITY_MIN;
1248 
1249  static size_t num_instances;
1250 
1251  ChannelProvider();
1252  virtual ~ChannelProvider();
1253 
1254  /**
1255  * Get the provider name.
1256  * @return The name.
1257  */
1258  virtual std::string getProviderName() = 0;
1259 
1260  /**
1261  * Test to see if this provider has the named channel.
1262  *
1263  * May call ChannelFindRequester::channelFindResult() before returning, or at some time later.
1264  * If an exception is thrown, then channelFindResult() will never be called.
1265  *
1266  * @param name The channel name.
1267  * @param requester The Requester.
1268  * @return An unique()==true handle for the pending response. May only return NULL if channelFindResult() called with an Error
1269  */
1270  virtual ChannelFind::shared_pointer channelFind(std::string const & name,
1271  ChannelFindRequester::shared_pointer const & requester) = 0;
1272 
1273  /**
1274  * Request a list of all valid channel names for this provider.
1275  *
1276  * May call ChannelListRequester::channelListResult() before returning, or at some time later.
1277  * If an exception is thrown, then channelListResult() will never be called.
1278  *
1279  * @param requester The Requester.
1280  * @return An unique()==true handle for the pending response. May only return NULL if channelFindResult() called with an Error
1281  */
1282  virtual ChannelFind::shared_pointer channelList(ChannelListRequester::shared_pointer const & requester);
1283 
1284  /**
1285  * See longer form
1286  */
1287  virtual Channel::shared_pointer createChannel(std::string const & name,
1288  ChannelRequester::shared_pointer const & requester = DefaultChannelRequester::build(),
1289  short priority = PRIORITY_DEFAULT);
1290 
1291  /**
1292  * Request a Channel.
1293  *
1294  * Channel creation is immediate.
1295  * ChannelRequester::channelCreated() will be called before returning.
1296  * The shared_ptr which is passed to channelCreated() will also be returned.
1297  *
1298  * Failures during channel creation are delivered to ChannelRequester::channelCreated() with Status::isSuccess()==false.
1299  *
1300  * @post The returned Channel will hold a strong reference to the provided ChannelRequester
1301  * and to the ChannelProvider through which it is created.
1302  *
1303  * @post The shared_ptr passed to ChannelRequester::channelCreated() is unique. See @ref providers_ownership_unique
1304  *
1305  * @post The new Channel will _not_ hold a strong reference to this ChannelProvider.
1306  * This provider must be kept alive in order to keep the Channel from being destoryed.
1307  *
1308  * @param name The name of the channel.
1309  * @param requester Will receive notifications about channel state changes
1310  * @param priority channel priority, must be <code>PRIORITY_MIN</code> <= priority <= <code>PRIORITY_MAX</code>.
1311  * @param address Implementation dependent condition. eg. A network address to bypass the search phase. Pass an empty() string for default behavour.
1312  * @return A non-NULL Channel unless channelCreated() called with an Error
1313  */
1314  virtual Channel::shared_pointer createChannel(std::string const & name,ChannelRequester::shared_pointer const & requester,
1315  short priority, std::string const & address) = 0;
1316 };
1317 
1318 /**
1319  * <code>ChanneProvider</code> factory interface.
1320  */
1321 class epicsShareClass ChannelProviderFactory {
1322  EPICS_NOT_COPYABLE(ChannelProviderFactory)
1323 public:
1324  POINTER_DEFINITIONS(ChannelProviderFactory);
1325 
1326  ChannelProviderFactory() {}
1327  virtual ~ChannelProviderFactory() {}
1328 
1329  /**
1330  * Get factory name (i.e. name of the provider).
1331  * @return the factory name.
1332  */
1333  virtual std::string getFactoryName() = 0;
1334 
1335  /**
1336  * Get a shared instance using the default Configuration.
1337  * @return a shared instance.
1338  */
1339  virtual ChannelProvider::shared_pointer sharedInstance() = 0;
1340 
1341  /**
1342  * Create a new instance using the default Configuration.
1343  * @return a new instance.
1344  */
1345  virtual ChannelProvider::shared_pointer newInstance() {
1346  return newInstance(std::tr1::shared_ptr<Configuration>());
1347  }
1348 
1349  /**
1350  * Create a new instance using a specific Configuration.
1351  * @return a new instance.
1352  */
1353  virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr<Configuration>&) {
1354  throw std::logic_error("This ChannelProviderFactory does not support non-default configurations");
1355  }
1356 };
1357 
1358 //! Simple ChannelProviderFactory which requires the existance of a ctor
1359 //! Provider(const std::tr1::shared_ptr<Configuration>& conf)
1360 //! which is called with a Configuration instance or NULL (use some defaults)
1361 template<class Provider>
1362 struct SimpleChannelProviderFactory : public ChannelProviderFactory
1363 {
1364  SimpleChannelProviderFactory(const std::string& name) :pname(name) {}
1365  virtual ~SimpleChannelProviderFactory() {}
1366 
1367  virtual std::string getFactoryName() OVERRIDE FINAL { return pname; }
1368 
1369  virtual ChannelProvider::shared_pointer sharedInstance() OVERRIDE FINAL
1370  {
1371  epics::pvData::Lock L(sharedM);
1372  ChannelProvider::shared_pointer ret(shared.lock());
1373  if(!ret) {
1374  std::tr1::shared_ptr<Provider> inst(new Provider(std::tr1::shared_ptr<Configuration>()));
1375  shared = ret = inst;
1376  }
1377  return ret;
1378  }
1379 
1380  virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr<Configuration>& conf) OVERRIDE FINAL
1381  {
1382  std::tr1::shared_ptr<Provider> ret(new Provider(conf));
1383  return ret;
1384  }
1385 
1386 private:
1387  const std::string pname;
1388  epics::pvData::Mutex sharedM;
1389  ChannelProvider::weak_pointer shared;
1390 };
1391 
1392 //! Helper for ChannelProviders which access a singleton resource (eg. process database).
1393 //! Only one concurrent instance will be created.
1394 //! Requires the existance of a ctor
1395 //! Provider(const std::tr1::shared_ptr<const Configuration>& conf)
1396 template<class Provider>
1397 struct SingletonChannelProviderFactory : public ChannelProviderFactory
1398 {
1399  SingletonChannelProviderFactory(const std::string& name,
1400  const std::tr1::shared_ptr<const Configuration>& conf = std::tr1::shared_ptr<const Configuration>())
1401  :pname(name), config(conf)
1402  {}
1403  virtual ~SingletonChannelProviderFactory() {}
1404 
1405  virtual std::string getFactoryName() OVERRIDE FINAL { return pname; }
1406 
1407  virtual ChannelProvider::shared_pointer sharedInstance() OVERRIDE FINAL
1408  {
1409  epics::pvData::Lock L(sharedM);
1410  ChannelProvider::shared_pointer ret(shared.lock());
1411  if(!ret) {
1412  std::tr1::shared_ptr<Provider> inst(new Provider(config));
1413  shared = ret = inst;
1414  }
1415  return ret;
1416  }
1417 
1418  virtual ChannelProvider::shared_pointer newInstance(const std::tr1::shared_ptr<Configuration>& conf) OVERRIDE FINAL
1419  {
1420  (void)conf; // ignore and use our Configuration
1421  return sharedInstance();
1422  }
1423 private:
1424  const std::string pname;
1425  epics::pvData::Mutex sharedM;
1426  ChannelProvider::weak_pointer shared;
1427  const std::tr1::shared_ptr<const Configuration> config;
1428 };
1429 
1430 /**
1431  * Interface for locating channel providers.
1432  */
1433 class epicsShareClass ChannelProviderRegistry {
1434 public:
1435  POINTER_DEFINITIONS(ChannelProviderRegistry);
1436 
1437  typedef std::vector<std::string> stringVector_t;
1438 
1439  virtual ~ChannelProviderRegistry() {}
1440 
1441 
1442  //! Create a custom registry
1443  static ChannelProviderRegistry::shared_pointer build();
1444  //! The global registry for "clients".
1445  //! Register providers which will be used within this process.
1446  //! Typically providers which access data outside of the process.
1447  //! Associated with EPICS_PVA_PROVIDER_NAMES
1448  static ChannelProviderRegistry::shared_pointer clients();
1449  //! The global registry for "servers".
1450  //! Register providers which will be used outside of this process (via ServerContext).
1451  //! Typically providers which access data within the process.
1452  //! Associated with EPICS_PVAS_PROVIDER_NAMES
1453  static ChannelProviderRegistry::shared_pointer servers();
1454 
1455  /**
1456  * Get a shared instance of the provider with the specified name.
1457  * @param providerName The name of the provider.
1458  * @return The interface for the provider or null if the provider is not known.
1459  */
1460  ChannelProvider::shared_pointer getProvider(std::string const & providerName);
1461 
1462  /**
1463  * Creates a new instanceof the provider with the specified name.
1464  * @param providerName The name of the provider.
1465  * @return The interface for the provider or null if the provider is not known.
1466  */
1467  ChannelProvider::shared_pointer createProvider(std::string const & providerName,
1468  const std::tr1::shared_ptr<Configuration>& conf = std::tr1::shared_ptr<Configuration>());
1469 
1470  /**
1471  * Fetch provider factor with the specified name.
1472  * @param providerName The name of the provider.
1473  * @return The factor or null if the provider is not known.
1474  */
1475  virtual ChannelProviderFactory::shared_pointer getFactory(std::string const & providerName);
1476 
1477  typedef std::set<std::string> provider_name_set;
1478  /**
1479  * Find currently registered provider names.
1480  */
1481  virtual void getProviderNames(provider_name_set& names);
1482 
1483  //! Add new factory. if replace=false and name already in use, return false with no change
1484  //! in other cases insert provided factory and return true.
1485  virtual bool add(const ChannelProviderFactory::shared_pointer& fact, bool replace=true);
1486 
1487  //! Add a new Provider which will be built using SimpleChannelProviderFactory<Provider>
1488  template<class Provider>
1489  ChannelProviderFactory::shared_pointer add(const std::string& name, bool replace=true)
1490  {
1491  typedef SimpleChannelProviderFactory<Provider> Factory;
1492  typename Factory::shared_pointer fact(new Factory(name));
1493  return add(fact, replace) ? fact : typename Factory::shared_pointer();
1494  }
1495 
1496  typedef ChannelProvider::shared_pointer (*factoryfn_t)(const std::tr1::shared_ptr<Configuration>&);
1497 
1498  ChannelProviderFactory::shared_pointer add(const std::string& name, factoryfn_t, bool replace=true);
1499 
1500  //! Add a new Provider which will be built using SingletonChannelProviderFactory<Provider>
1501  template<class Provider>
1502  ChannelProviderFactory::shared_pointer addSingleton(const std::string& name,
1503  const std::tr1::shared_ptr<const Configuration>& conf = std::tr1::shared_ptr<const Configuration>(),
1504  bool replace=true)
1505  {
1506  typedef SingletonChannelProviderFactory<Provider> Factory;
1507  typename Factory::shared_pointer fact(new Factory(name, conf));
1508  return add(fact, replace) ? fact : typename Factory::shared_pointer();
1509  }
1510 
1511  //! Add a pre-created Provider instance.
1512  //! Only a weak ref to this instance is kept, so the instance must be kept active
1513  //! through some external means
1514  //! @since 6.1.0
1515  ChannelProviderFactory::shared_pointer addSingleton(const ChannelProvider::shared_pointer& provider,
1516  bool replace=true);
1517 
1518  //! Attempt to remove a factory with the given name. Return Factory which was removed, or NULL if not found.
1519  ChannelProviderFactory::shared_pointer remove(const std::string& name);
1520 
1521  //! Attempt to remove a factory. Return true if Factory was previously registered, and now removed.
1522  virtual bool remove(const ChannelProviderFactory::shared_pointer& factory);
1523 
1524  //! Drop all factories
1525  virtual void clear();
1526 
1527 private:
1528  // ctor is hidden to ensure explict compile errors from a hypothetical sub-class
1529  // we no longer support sub-classing by outside code
1530  ChannelProviderRegistry() {}
1531  friend struct CompatRegistry;
1532 
1533  epics::pvData::Mutex mutex;
1534  typedef std::map<std::string, ChannelProviderFactory::shared_pointer> providers_t;
1535  providers_t providers;
1536 };
1537 
1538 /* Deprecated in favor of either ChannelProviderRegistry::clients() or ChannelProviderRegistry::servers()
1539  *
1540  * These functions have been removed as a signal that the shared_ptr ownership symantics of ChannelProvider
1541  * and friends has changed.
1542  */
1543 #if __GNUC__>4 || (__GNUC__==4&&__GNUC_MINOR__>=3)
1544 
1545 #define gCPRMSG __attribute__((error("ChannelProvider shared_ptr ownership rules have changed.")))
1546 
1547 epicsShareFunc ChannelProviderRegistry::shared_pointer getChannelProviderRegistry() gCPRMSG;
1548 // Shorthand for getChannelProviderRegistry()->add(channelProviderFactory);
1549 epicsShareFunc void registerChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) gCPRMSG;
1550 // Shorthand for getChannelProviderRegistry()->remove(channelProviderFactory);
1551 epicsShareFunc void unregisterChannelProviderFactory(ChannelProviderFactory::shared_pointer const & channelProviderFactory) gCPRMSG;
1552 // Shorthand for getChannelProviderRegistry()->clear();
1553 epicsShareFunc void unregisterAllChannelProviderFactory() gCPRMSG;
1554 
1555 #undef gCPRMSG
1556 
1557 #endif // __GNUC__
1558 
1559 /**
1560  * @brief Pipeline (streaming) support API (optional).
1561  * This is used by pvAccess to implement pipeline (streaming) monitors.
1562  */
1563 typedef Monitor PipelineMonitor;
1564 
1565 
1566 }
1567 }
1568 
1569 // compatibility
1570 namespace epics { namespace pvData {
1571 using epics::pvAccess::MonitorRequester;
1572 }}
1573 
1574 
1575 #endif /* PVACCESS_H */
1576 
1577 /** @page Overview Documentation
1578  *
1579  *<a href = "../documentation/pvAccessCPP.html">pvAccessCPP.html</a>
1580  *
1581  */
#define OVERRIDE
Definition: pvAccess.h:55
#define FINAL
Copyright - See the COPYRIGHT that is included with this distribution.
Definition: pvAccess.h:48