From 1f7c6f55201c1594f4a94ff5b0469f3527ff50c5 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sun, 19 Dec 2010 13:28:30 +0100 Subject: [PATCH 1/2] Moved status and monitor out of pvAccessCPP; interfaces only. --- pvDataApp/Makefile | 6 +++ pvDataApp/misc/destroyable.h | 25 ++++++++++ pvDataApp/misc/status.h | 70 +++++++++++++++++++++++++++ pvDataApp/monitor/monitor.h | 94 ++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+) create mode 100644 pvDataApp/misc/destroyable.h create mode 100644 pvDataApp/misc/status.h create mode 100644 pvDataApp/monitor/monitor.h diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index 5d06118..e9b07ff 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -25,6 +25,8 @@ INC += timer.h INC += queueVoid.h INC += queue.h INC += messageQueue.h +INC += destroyable.h +INC += status.h LIBSRCS += byteBuffer.cpp LIBSRCS += bitSet.cpp @@ -106,6 +108,10 @@ SRC_DIRS += $(PVDATA)/pvMisc INC += bitSetUtil.h LIBSRCS += bitSetUtil.cpp +SRC_DIRS += $(PVDATA)/monitor +INC += monitor.h + + LIBRARY=pvData pvData_LIBS += Com diff --git a/pvDataApp/misc/destroyable.h b/pvDataApp/misc/destroyable.h new file mode 100644 index 0000000..e2a63a3 --- /dev/null +++ b/pvDataApp/misc/destroyable.h @@ -0,0 +1,25 @@ +/* destroyable.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef DESTROYABLE_H +#define DESTROYABLE_H +namespace epics { namespace pvData { + + + /** + * Instance declaring destroy method. + * @author mse + */ + class Destroyable { + public: + /** + * Destroy this instance. + */ + virtual void destroy() = 0; + }; + +}} +#endif /* DESTROYABLE_H */ diff --git a/pvDataApp/misc/status.h b/pvDataApp/misc/status.h new file mode 100644 index 0000000..6d2ca45 --- /dev/null +++ b/pvDataApp/misc/status.h @@ -0,0 +1,70 @@ +/* status.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef STATUS_H +#define STATUS_H + +#include "serialize.h" + +namespace epics { namespace pvData { + + /** + * Status type enum. + */ + enum StatusType { + /** Operation completed successfully. */ + OK, + /** Operation completed successfully, but there is a warning message. */ + WARNING, + /** Operation failed due to an error. */ + ERROR, + /** Operation failed due to an unexpected error. */ + FATAL + }; + + /** + * Status interface. + * @author mse + */ + class Status : public epics::pvData::Serializable { + public: + + /** + * Get status type. + * @return status type, non-null. + */ + virtual StatusType getType() = 0; + + /** + * Get error message describing an error. Required if error status. + * @return error message. + */ + virtual epics::pvData::String getMessage() = 0; + + /** + * Get stack dump where error (exception) happened. Optional. + * @return stack dump. + */ + virtual epics::pvData::String getStackDump() = 0; + + /** + * Convenient OK test. Same as (getType() == StatusType.OK). + * NOTE: this will return false on WARNING message although operation succeeded. + * To check if operation succeeded, use isSuccess. + * @return OK status. + * @see #isSuccess() + */ + virtual bool isOK() = 0; + + /** + * Check if operation succeeded. + * @return operation success status. + */ + virtual bool isSuccess() = 0; + }; + +}} +#endif /* STATUS_H */ diff --git a/pvDataApp/monitor/monitor.h b/pvDataApp/monitor/monitor.h new file mode 100644 index 0000000..d2fc0f6 --- /dev/null +++ b/pvDataApp/monitor/monitor.h @@ -0,0 +1,94 @@ +/* monitor.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#ifndef MONITOR_H +#define MONITOR_H + +#include +#include + +namespace epics { namespace pvData { + + /** + * Class instance representing monitor element. + * @author mrk + */ + class MonitorElement { + public: + /** + * Get the PVStructure. + * @return The PVStructure. + */ + virtual PVStructure* getPVStructure() = 0; + /** + * Get the bitSet showing which fields have changed. + * @return The bitSet. + */ + virtual BitSet* getChangedBitSet() = 0; + /** + * Get the bitSet showing which fields have been changed more than once. + * @return The bitSet. + */ + virtual BitSet* getOverrunBitSet() = 0; + }; + + + /** + * Interface for Monitor. + * @author mrk + */ + class Monitor : public Destroyable, private NoDefaultMethods { + public: + /** + * Start monitoring. + * @return completion status. + */ + virtual Status* start() = 0; + /** + * Stop Monitoring. + * @return completion status. + */ + virtual Status* stop() = 0; + /** + * If monitor has occurred return data. + * @return monitorElement for modified data on null if no monitors have occurred. + */ + virtual MonitorElement* poll() = 0; + /** + * Release a MonitorElement that was returned by poll. + * @param monitorElement + */ + virtual void release(MonitorElement* monitorElement) = 0; + }; + + + /** + * Requester for ChannelMonitor. + * @author mrk + */ + class MonitorRequester : public Requester { + public: + /** + * The client and server have both completed the createMonitor request. + * @param status Completion status. + * @param monitor The monitor + * @param structure The structure defining the data. + */ + virtual void monitorConnect(Status* status, Monitor* monitor, Structure* structure) = 0; + /** + * A monitor event has occurred. The requester must call Monitor.poll to get data. + * @param monitor The monitor. + */ + virtual void monitorEvent(Monitor* monitor) = 0; + /** + * The data source is no longer available. + * @param monitor The monitor. + */ + virtual void unlisten(Monitor* monitor) = 0; + }; + +}} +#endif /* MONITOR_H */ From e4ea15aff3fed9c534674e91998342d466c3076b Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sun, 19 Dec 2010 21:17:59 +0100 Subject: [PATCH 2/2] Status factory added. --- pvDataApp/Makefile | 1 + pvDataApp/factory/StatusCreateFactory.cpp | 198 ++++++++++++++++++++++ pvDataApp/misc/destroyable.h | 6 + pvDataApp/misc/status.h | 52 +++++- 4 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 pvDataApp/factory/StatusCreateFactory.cpp diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile index e9b07ff..89e3d6d 100644 --- a/pvDataApp/Makefile +++ b/pvDataApp/Makefile @@ -83,6 +83,7 @@ LIBSRCS += PVDataCreateFactory.cpp LIBSRCS += Convert.cpp LIBSRCS += StandardField.cpp LIBSRCS += StandardPVField.cpp +LIBSRCS += StatusCreateFactory.cpp SRC_DIRS += $(PVDATA)/property diff --git a/pvDataApp/factory/StatusCreateFactory.cpp b/pvDataApp/factory/StatusCreateFactory.cpp new file mode 100644 index 0000000..f18a0f9 --- /dev/null +++ b/pvDataApp/factory/StatusCreateFactory.cpp @@ -0,0 +1,198 @@ +/*StatusCreateFactory.cpp*/ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvDataCPP is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#include +#include +#include +#include +#include +#include "factory.h" +#include "byteBuffer.h" +#include "showConstructDestruct.h" +#include "status.h" +#include "serializeHelper.h" + +namespace epics { namespace pvData { + +//static DebugLevel debugLevel = lowDebug; + +static volatile int64 totalConstruct = 0; +static volatile int64 totalDestruct = 0; +static Mutex *globalMutex = 0; + +static int64 getTotalConstruct() +{ + Lock xx(globalMutex); + return totalConstruct; +} + +static int64 getTotalDestruct() +{ + Lock xx(globalMutex); + return totalDestruct; +} + +static ConstructDestructCallback *pConstructDestructCallback; + +static void init() +{ + static Mutex mutex = Mutex(); + Lock xx(&mutex); + if(globalMutex==0) { + globalMutex = new Mutex(); + pConstructDestructCallback = new ConstructDestructCallback( + String("status"), + getTotalConstruct,getTotalDestruct,0); + } +} + +class StatusImpl : public Status +{ + public: + + StatusImpl(StatusType type, String message, String stackDump) : + m_type(type), m_message(message), m_stackDump(stackDump) + { + Lock xx(globalMutex); + totalConstruct++; + } + + ~StatusImpl() { + Lock xx(globalMutex); + totalDestruct++; + } + + virtual StatusType getType() + { + return m_type; + } + + + virtual epics::pvData::String getMessage() + { + return m_message; + } + + virtual epics::pvData::String getStackDump() + { + return m_stackDump; + } + + virtual bool isOK() + { + return (m_type == STATUSTYPE_OK); + } + + virtual bool isSuccess() + { + return (m_type == STATUSTYPE_OK || m_type == STATUSTYPE_WARNING); + } + + virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) + { + flusher->ensureBuffer(1); + if (this == getStatusCreate()->getStatusOK()) + { + // special code for okStatus (optimization) + buffer->putByte((int8)-1); + } + else + { + buffer->putByte((int8)m_type); + SerializeHelper::serializeString(m_message, buffer, flusher); + SerializeHelper::serializeString(m_stackDump, buffer, flusher); + } + } + + virtual void deserialize(ByteBuffer *pbuffer, DeserializableControl *pflusher) + { + throw new std::runtime_error("use getStatusCreate()->deserialize()"); + } + + virtual void toString(StringBuilder buffer, int indentLevel) + { + *buffer += "StatusImpl [type="; + *buffer += StatusTypeName[m_type]; + if (!m_message.empty()) + { + *buffer += ", message="; + *buffer += m_message; + } + if (!m_stackDump.empty()) + { + *buffer += ", stackDump="; + *buffer += '\n'; + *buffer += m_stackDump; + } + *buffer += ']'; + } + + private: + + StatusType m_type; + String m_message; + String m_stackDump; + +}; + + + + +class StatusCreateImpl : public StatusCreate { + public: + + StatusCreateImpl() + { + init(); + m_ok = createStatus(STATUSTYPE_OK, "OK", 0); + } + + virtual Status* getStatusOK() { + return m_ok; + } + + virtual Status* createStatus(StatusType type, String message, BaseException* cause) { + if (cause == 0) + return new StatusImpl(type, message, ""); + else + { + std::string stackDump; + cause->toString(stackDump); + return new StatusImpl(type, message, stackDump); + } + } + + virtual Status* deserializeStatus(ByteBuffer* buffer, DeserializableControl* control) { + control->ensureData(1); + int8 typeCode = buffer->getByte(); + if (typeCode == (int8)-1) + return m_ok; + else { + String message = SerializeHelper::deserializeString(buffer, control); + String stackDump = SerializeHelper::deserializeString(buffer, control); + return new StatusImpl((StatusType)typeCode, message, stackDump); + } + } + + private: + + Status* m_ok; +}; + + + + +static StatusCreate* statusCreate = 0; + +StatusCreate* getStatusCreate() { + static Mutex mutex = Mutex(); + Lock xx(&mutex); + + if(statusCreate==0) statusCreate = new StatusCreateImpl(); + return statusCreate; +} + +}} diff --git a/pvDataApp/misc/destroyable.h b/pvDataApp/misc/destroyable.h index e2a63a3..0f5b7ed 100644 --- a/pvDataApp/misc/destroyable.h +++ b/pvDataApp/misc/destroyable.h @@ -19,6 +19,12 @@ namespace epics { namespace pvData { * Destroy this instance. */ virtual void destroy() = 0; + + private: + /** + * Do not allow delete on this instance. + */ + //~Destroyable() {}; }; }} diff --git a/pvDataApp/misc/status.h b/pvDataApp/misc/status.h index 6d2ca45..5e9b38b 100644 --- a/pvDataApp/misc/status.h +++ b/pvDataApp/misc/status.h @@ -8,6 +8,8 @@ #define STATUS_H #include "serialize.h" +#include "epicsException.h" +#include "byteBuffer.h" namespace epics { namespace pvData { @@ -16,14 +18,16 @@ namespace epics { namespace pvData { */ enum StatusType { /** Operation completed successfully. */ - OK, + STATUSTYPE_OK, /** Operation completed successfully, but there is a warning message. */ - WARNING, + STATUSTYPE_WARNING, /** Operation failed due to an error. */ - ERROR, + STATUSTYPE_ERROR, /** Operation failed due to an unexpected error. */ - FATAL + STATUSTYPE_FATAL }; + + const char* StatusTypeName[] = { "OK", "WARNING", "ERROR", "FATAL" }; /** * Status interface. @@ -64,7 +68,47 @@ namespace epics { namespace pvData { * @return operation success status. */ virtual bool isSuccess() = 0; + + + virtual void toString(StringBuilder buffer, int indentLevel = 0) = 0; + }; + + /** + * Interface for creating status. + * @author mse + */ + class StatusCreate : private epics::pvData::NoDefaultMethods { + public: + /** + * Get OK status. Static instance should be returned. + * @return OK Status instance. + */ + virtual Status* getStatusOK() = 0; + + /** + * Create status. + * @param type status type, non-null. + * @param message message describing an error, non-null. + * NOTE: Do NOT use throwable.getMessage() as message, since it will be supplied with the cause. + * @param cause exception that caused an error. Optional. + * @return status instance. + */ + virtual Status* createStatus(StatusType type, String message, BaseException* cause) = 0; + + /** + * Deserialize status. + * NOTE: use this method instead of Status.deserialize(), since this allows OK status optimization. + * @param buffer deserialization buffer. + * @param control deserialization control. + * @return status instance. + */ + virtual Status* deserializeStatus(ByteBuffer* buffer, DeserializableControl* control) = 0; + }; + + extern StatusCreate* getStatusCreate(); + + }} #endif /* STATUS_H */