Merge with 2240b8485ef2182e083614fc304bfe7e1b6c771a
This commit is contained in:
@@ -17,18 +17,22 @@ INC += arrayFIFO.h
|
||||
INC += growingCircularBuffer.h
|
||||
INC += inetAddressUtil.h
|
||||
INC += logger.h
|
||||
INC += introspectionRegistry.h
|
||||
LIBSRCS += hexDump.cpp
|
||||
LIBSRCS += wildcharMatcher.cpp
|
||||
LIBSRCS += inetAddressUtil.cpp
|
||||
LIBSRCS += logger.cpp
|
||||
LIBSRCS += introspectionRegistry.cpp
|
||||
|
||||
|
||||
SRC_DIRS += $(PVACCESS)/client
|
||||
INC += pvAccess.h
|
||||
LIBSRCS += pvAccess.cpp
|
||||
|
||||
|
||||
SRC_DIRS += $(PVACCESS)/factory
|
||||
LIBSRCS += ChannelAccessFactory.cpp
|
||||
LIBSRCS += CreateRequestFactory.cpp
|
||||
|
||||
|
||||
SRC_DIRS += $(PVACCESS)/remote
|
||||
|
||||
13
pvAccessApp/client/pvAccess.cpp
Normal file
13
pvAccessApp/client/pvAccess.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/*pvAccess.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 <pvAccess.h>
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
const char* ConnectionStateNames[] = { "NEVER_CONNECTED", "CONNECTED", "DISCONNECTED", "DESTROYED" };
|
||||
|
||||
}}
|
||||
@@ -33,7 +33,7 @@ namespace epics { namespace pvAccess {
|
||||
NEVER_CONNECTED, CONNECTED, DISCONNECTED, DESTROYED
|
||||
};
|
||||
|
||||
const char* ConnectionStateNames[] = { "NEVER_CONNECTED", "CONNECTED", "DISCONNECTED", "DESTROYED" };
|
||||
extern const char* ConnectionStateNames[];
|
||||
|
||||
|
||||
class Channel;
|
||||
@@ -714,6 +714,27 @@ namespace epics { namespace pvAccess {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface for creating request structure.
|
||||
* @author mse
|
||||
*
|
||||
*/
|
||||
class CreateRequest : private epics::pvData::NoDefaultMethods {
|
||||
public:
|
||||
virtual ~CreateRequest() {};
|
||||
|
||||
/**
|
||||
* Create a request structure for the create calls in Channel.
|
||||
* See the package overview documentation for details.
|
||||
* @param request The field request. See the package overview documentation for details.
|
||||
* @param requester The requester;
|
||||
* @return The request structure if an invalid request was given.
|
||||
*/
|
||||
virtual epics::pvData::PVStructure* createRequest(String request, epics::pvData::Requester* requester) = 0;
|
||||
};
|
||||
|
||||
extern CreateRequest * getCreateRequest();
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <lock.h>
|
||||
#include <noDefaultMethods.h>
|
||||
#include "pvAccess.h"
|
||||
#include "pvData.h"
|
||||
#include "factory.h"
|
||||
#include <pvAccess.h>
|
||||
#include <pvData.h>
|
||||
#include <factory.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
263
pvAccessApp/factory/CreateRequestFactory.cpp
Normal file
263
pvAccessApp/factory/CreateRequestFactory.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/*CreateRequestFactory.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 <string>
|
||||
#include <sstream>
|
||||
#include <pvData.h>
|
||||
#include <lock.h>
|
||||
#include <pvAccess.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
class CreateRequestImpl : public CreateRequest {
|
||||
private:
|
||||
|
||||
static void trim(std::string& str)
|
||||
{
|
||||
std::string::size_type pos = str.find_last_not_of(' ');
|
||||
if(pos != std::string::npos) {
|
||||
str.erase(pos + 1);
|
||||
pos = str.find_first_not_of(' ');
|
||||
if(pos != std::string::npos) str.erase(0, pos);
|
||||
}
|
||||
else str.erase(str.begin(), str.end());
|
||||
}
|
||||
|
||||
static int findMatchingBrace(std::string& request, int index, int numOpen) {
|
||||
size_t openBrace = request.find('{', index+1);
|
||||
size_t closeBrace = request.find('}', index+1);
|
||||
if(openBrace == std::string::npos && closeBrace == std::string::npos) return std::string::npos;
|
||||
if (openBrace != std::string::npos) {
|
||||
if(openBrace<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
|
||||
static bool createFieldRequest(PVStructure* pvParent,std::string request,bool fieldListOK,Requester* requester) {
|
||||
trim(request);
|
||||
if(request.length()<=0) return true;
|
||||
size_t comma = request.find(',');
|
||||
size_t openBrace = request.find('{');
|
||||
size_t openBracket = request.find('[');
|
||||
if(openBrace != std::string::npos || openBracket != std::string::npos) fieldListOK = false;
|
||||
if(openBrace != std::string::npos && (comma==std::string::npos || comma>openBrace)) {
|
||||
//find matching brace
|
||||
size_t closeBrace = findMatchingBrace(request,openBrace+1,1);
|
||||
if(closeBrace==std::string::npos) {
|
||||
requester->message(request + "mismatched { }", errorMessage);
|
||||
return false;
|
||||
}
|
||||
String fieldName = request.substr(0,openBrace);
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0);
|
||||
createFieldRequest(pvStructure,request.substr(openBrace+1,closeBrace-openBrace-1),false,requester);
|
||||
// error check?
|
||||
pvParent->appendPVField(pvStructure);
|
||||
if(request.length()>closeBrace+1) {
|
||||
if(request.at(closeBrace+1) != ',') {
|
||||
requester->message(request + "misssing , after }", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createFieldRequest(pvParent,request.substr(closeBrace+2),false,requester)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(openBracket==std::string::npos && fieldListOK) {
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvParent, "fieldList", pvString));
|
||||
pvStringField->put(request);
|
||||
pvParent->appendPVField(pvStringField);
|
||||
return true;
|
||||
}
|
||||
if(openBracket!=std::string::npos && (comma==std::string::npos || comma>openBracket)) {
|
||||
size_t closeBracket = request.find(']');
|
||||
if(closeBracket==std::string::npos) {
|
||||
requester->message(request + "option does not have matching []", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createLeafFieldRequest(pvParent,request.substr(0, closeBracket+1),requester)) return false;
|
||||
if(request.rfind(',')>closeBracket) {
|
||||
int nextComma = request.find(',', closeBracket);
|
||||
if(!createFieldRequest(pvParent,request.substr(nextComma+1),false,requester)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(comma!=std::string::npos) {
|
||||
if(!createLeafFieldRequest(pvParent,request.substr(0, comma),requester)) return false;
|
||||
return createFieldRequest(pvParent,request.substr(comma+1),false,requester);
|
||||
}
|
||||
return createLeafFieldRequest(pvParent,request,requester);
|
||||
}
|
||||
|
||||
static bool createLeafFieldRequest(PVStructure* pvParent,String request,Requester* requester) {
|
||||
size_t openBracket = request.find('[');
|
||||
String fullName = request;
|
||||
if(openBracket != std::string::npos) fullName = request.substr(0,openBracket);
|
||||
size_t indLast = fullName.rfind('.');
|
||||
String fieldName = fullName;
|
||||
if(indLast>1 && indLast != std::string::npos) fieldName = fullName.substr(indLast+1);
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0);
|
||||
PVStructure* pvLeaf = getPVDataCreate()->createPVStructure(pvStructure,"leaf", 0);
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvLeaf, "source", pvString));
|
||||
pvStringField->put(fullName);
|
||||
pvLeaf->appendPVField(pvStringField);
|
||||
if(openBracket != std::string::npos) {
|
||||
size_t closeBracket = request.find(']');
|
||||
if(closeBracket==std::string::npos) {
|
||||
delete pvLeaf;
|
||||
delete pvStructure;
|
||||
requester->message("option does not have matching []", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createRequestOptions(pvLeaf,request.substr(openBracket+1, closeBracket-openBracket-1),requester))
|
||||
{
|
||||
delete pvLeaf;
|
||||
delete pvStructure;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pvStructure->appendPVField(pvLeaf);
|
||||
pvParent->appendPVField(pvStructure);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool createRequestOptions(PVStructure* pvParent,std::string request,Requester* requester) {
|
||||
trim(request);
|
||||
if(request.length()<=1) return true;
|
||||
|
||||
std::string token;
|
||||
std::istringstream iss(request);
|
||||
while (getline(iss, token, ','))
|
||||
{
|
||||
size_t equalsPos = token.find('=');
|
||||
size_t equalsRPos = token.rfind('=');
|
||||
if (equalsPos != equalsRPos)
|
||||
{
|
||||
requester->message("illegal option", errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvParent, token.substr(0, equalsPos), pvString));
|
||||
pvStringField->put(token.substr(equalsPos+1));
|
||||
pvParent->appendPVField(pvStringField);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual PVStructure* createRequest(String request, Requester* requester)
|
||||
{
|
||||
static String emptyString;
|
||||
if (!request.empty()) trim(request);
|
||||
if (request.empty())
|
||||
{
|
||||
return getPVDataCreate()->createPVStructure(0, emptyString, 0);
|
||||
}
|
||||
|
||||
size_t offsetRecord = request.find("record[");
|
||||
size_t offsetField = request.find("field(");
|
||||
size_t offsetPutField = request.find("putField(");
|
||||
size_t offsetGetField = request.find("getField(");
|
||||
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(0, emptyString, 0);
|
||||
if (offsetRecord != std::string::npos) {
|
||||
size_t offsetBegin = request.find('[', offsetRecord);
|
||||
size_t offsetEnd = request.find(']', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("record[ does not have matching ]", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "record", 0);
|
||||
if(!createRequestOptions(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("field( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "field", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetPutField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetPutField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("putField( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "putField", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetGetField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetGetField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("getField( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "getField", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (pvStructure->getStructure()->getNumberFields()==0) {
|
||||
if(!createFieldRequest(pvStructure,request,true,requester))
|
||||
{
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static CreateRequest* createRequest = 0;
|
||||
|
||||
CreateRequest * getCreateRequest() {
|
||||
static Mutex mutex = Mutex();
|
||||
Lock guard(&mutex);
|
||||
|
||||
if(createRequest==0){
|
||||
createRequest = new CreateRequestImpl();
|
||||
}
|
||||
return createRequest;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
476
pvAccessApp/utils/introspectionRegistry.cpp
Normal file
476
pvAccessApp/utils/introspectionRegistry.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* introspectionRegistry.cpp
|
||||
*/
|
||||
|
||||
#include "introspectionRegistry.h"
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
const int8 IntrospectionRegistry::NULL_TYPE_CODE = (int8)-1;
|
||||
const int8 IntrospectionRegistry::ONLY_ID_TYPE_CODE = (int8)-2;
|
||||
const int8 IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE = (int8)-3;
|
||||
PVDataCreate* IntrospectionRegistry::_pvDataCreate = getPVDataCreate();
|
||||
StatusCreate* IntrospectionRegistry::_statusCreate = getStatusCreate();
|
||||
FieldCreate* IntrospectionRegistry::_fieldCreate = getFieldCreate();
|
||||
|
||||
IntrospectionRegistry::IntrospectionRegistry(bool serverSide) : _mutex(Mutex())
|
||||
{
|
||||
|
||||
_direction = serverSide ? 1 : -1;
|
||||
reset();
|
||||
}
|
||||
|
||||
IntrospectionRegistry::~IntrospectionRegistry()
|
||||
{
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::reset()
|
||||
{
|
||||
Lock guard(&_mutex);
|
||||
_outgoingIdPointer = _direction;
|
||||
//decrement references
|
||||
for(_registryRIter = _registry.rbegin(); _registryRIter != _registry.rend(); _registryRIter++)
|
||||
{
|
||||
_registryRIter->second->decReferenceCount();
|
||||
}
|
||||
_registry.clear();
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::getIntrospectionInterface(const short id)
|
||||
{
|
||||
Lock guard(&_mutex);
|
||||
_registryIter = _registry.find(id);
|
||||
if(_registryIter == _registry.end())
|
||||
{
|
||||
throw EpicsException("missing interface with given id");
|
||||
}
|
||||
return _registryIter->second;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::registerIntrospectionInterface(const short id,FieldConstPtr field)
|
||||
{
|
||||
Lock guard(&_mutex);
|
||||
//first decrement reference on old value
|
||||
_registryIter = _registry.find(id);
|
||||
if(_registryIter != _registry.end())
|
||||
{
|
||||
_registryIter->second->decReferenceCount();
|
||||
}
|
||||
_registry[id] = field;
|
||||
field->incReferenceCount();
|
||||
}
|
||||
|
||||
short IntrospectionRegistry::registerIntrospectionInterface(FieldConstPtr field, bool& existing)
|
||||
{
|
||||
Lock guard(&_mutex);
|
||||
short key;
|
||||
if(registryContainsValue(field, key))
|
||||
{
|
||||
existing = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
existing = false;
|
||||
key = _outgoingIdPointer;
|
||||
_outgoingIdPointer += _direction;
|
||||
// wrap check
|
||||
if(_outgoingIdPointer * _direction < 0)
|
||||
{
|
||||
_outgoingIdPointer = _direction;
|
||||
}
|
||||
|
||||
//first decrement reference on old value
|
||||
_registryIter = _registry.find(key);
|
||||
if(_registryIter != _registry.end())
|
||||
{
|
||||
cout << "deleting 2" << endl;
|
||||
_registryIter->second->decReferenceCount();
|
||||
}
|
||||
|
||||
_registry[key] = field;
|
||||
field->incReferenceCount();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::printKeysAndValues(string name)
|
||||
{
|
||||
string buffer;
|
||||
cout << "############## print of all key/values of " << name.c_str() << " registry : ###################" << endl;
|
||||
for(_registryIter = _registry.begin(); _registryIter != _registry.end(); _registryIter++)
|
||||
{
|
||||
buffer.clear();
|
||||
cout << "\t" << "Key: "<< _registryIter->first << endl;
|
||||
cout << "\t" << "Value: " << _registryIter->second << endl;
|
||||
_registryIter->second->toString(&buffer);
|
||||
cout << "\t" << "Value toString: " << buffer.c_str() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool IntrospectionRegistry::registryContainsValue(FieldConstPtr field, short& key)
|
||||
{
|
||||
for(_registryRIter = _registry.rbegin(); _registryRIter != _registry.rend(); _registryRIter++)
|
||||
{
|
||||
if(compareFields(field,_registryRIter->second))
|
||||
{
|
||||
key = _registryRIter->first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IntrospectionRegistry::compareFields(FieldConstPtr field1, FieldConstPtr field2)
|
||||
{
|
||||
if(field1->getFieldName() != field2->getFieldName())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Type typ1 = field1->getType();
|
||||
Type typ2 = field2->getType();
|
||||
if(typ1 != typ2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (typ1)
|
||||
{
|
||||
case epics::pvData::scalar:
|
||||
{
|
||||
if(static_cast<ScalarConstPtr>(field1)->getScalarType() == static_cast<ScalarConstPtr>(field1)->getScalarType())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case epics::pvData::scalarArray:
|
||||
{
|
||||
if(static_cast<ScalarArrayConstPtr>(field1)->getElementType() == static_cast<ScalarArrayConstPtr>(field1)->getElementType())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case epics::pvData::structure:
|
||||
{
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case epics::pvData::structureArray:
|
||||
{
|
||||
if(static_cast<StructureArrayConstPtr>(field1)->getStructure()->getFieldName() == static_cast<StructureArrayConstPtr>(field1)->getStructure()->getFieldName())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serialize(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
serialize(field, NULL, buffer, control, this);
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
return deserialize(buffer, control, this);
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serializeFull(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
serialize(field, NULL, buffer, control, NULL);
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::deserializeFull(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
return deserialize(buffer, control, NULL);
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serialize(FieldConstPtr field, StructureConstPtr parent, ByteBuffer* buffer,
|
||||
SerializableControl* control, IntrospectionRegistry* registry)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
if (field == NULL)
|
||||
{
|
||||
control->ensureBuffer(1);
|
||||
buffer->putByte(IntrospectionRegistry::NULL_TYPE_CODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use registry check
|
||||
// only top IFs and structures
|
||||
if (registry != NULL && (parent == NULL || field->getType() == epics::pvData::structure || field->getType() == epics::pvData::structureArray))
|
||||
{
|
||||
bool existing;
|
||||
const short key = registry->registerIntrospectionInterface(field, existing);
|
||||
/*cout << "@@@@@@@@@" << endl;
|
||||
cout << field->getFieldName() << endl;
|
||||
cout << "address: " << field << endl;
|
||||
cout << "existing: " << existing << endl;
|
||||
cout << "key: " << key << endl;*/
|
||||
if(existing)
|
||||
{
|
||||
control->ensureBuffer(1+sizeof(int16)/sizeof(int8));
|
||||
buffer->putByte(ONLY_ID_TYPE_CODE);
|
||||
buffer->putShort(key);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
control->ensureBuffer(1+sizeof(int16)/sizeof(int8));
|
||||
buffer->putByte(FULL_WITH_ID_TYPE_CODE); // could also be a mask
|
||||
buffer->putShort(key);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: high nibble is field.getType() ordinal, low nibble is scalar type ordinal; -1 is null
|
||||
switch (field->getType())
|
||||
{
|
||||
case epics::pvData::scalar:
|
||||
{
|
||||
ScalarConstPtr scalar = static_cast<ScalarConstPtr>(field);
|
||||
control->ensureBuffer(1);
|
||||
buffer->putByte((int8)(epics::pvData::scalar << 4 | scalar->getScalarType()));
|
||||
SerializeHelper::serializeString(field->getFieldName(), buffer, control);
|
||||
break;
|
||||
}
|
||||
case epics::pvData::scalarArray:
|
||||
{
|
||||
ScalarArrayConstPtr array = static_cast<ScalarArrayConstPtr>(field);
|
||||
control->ensureBuffer(1);
|
||||
buffer->putByte((int8)(epics::pvData::scalarArray << 4 | array->getElementType()));
|
||||
SerializeHelper::serializeString(field->getFieldName(), buffer, control);
|
||||
break;
|
||||
}
|
||||
case epics::pvData::structure:
|
||||
{
|
||||
StructureConstPtr structure = static_cast<StructureConstPtr>(field);
|
||||
control->ensureBuffer(1);
|
||||
buffer->putByte((int8)(epics::pvData::structure << 4));
|
||||
serializeStructureField(buffer, control, registry, structure);
|
||||
break;
|
||||
}
|
||||
case epics::pvData::structureArray:
|
||||
{
|
||||
StructureArrayConstPtr structureArray = static_cast<StructureArrayConstPtr>(field);
|
||||
control->ensureBuffer(1);
|
||||
buffer->putByte((int8)(epics::pvData::structureArray << 4));
|
||||
SerializeHelper::serializeString(field->getFieldName(), buffer, control);
|
||||
// we also need to serialize structure field...
|
||||
const Structure* structureElement = structureArray->getStructure();
|
||||
serializeStructureField(buffer, control, registry, structureElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serializeStructureField(ByteBuffer* buffer, SerializableControl* control,
|
||||
IntrospectionRegistry* registry, StructureConstPtr structure)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
if(structure == NULL)
|
||||
{
|
||||
throw EpicsException("null structure provided");
|
||||
}
|
||||
SerializeHelper::serializeString(structure->getFieldName(), buffer, control);
|
||||
FieldConstPtrArray fields = structure->getFields();
|
||||
SerializeHelper::writeSize(structure->getNumberFields(), buffer, control);
|
||||
for (int i = 0; i < structure->getNumberFields(); i++)
|
||||
{
|
||||
serialize(fields[i], structure, buffer, control, registry);
|
||||
}
|
||||
}
|
||||
|
||||
FieldConstPtr IntrospectionRegistry::deserialize(ByteBuffer* buffer, DeserializableControl* control, IntrospectionRegistry* registry)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
control->ensureData(1);
|
||||
const int8 typeCode = buffer->getByte();
|
||||
if(typeCode == IntrospectionRegistry::NULL_TYPE_CODE)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if(typeCode == IntrospectionRegistry::ONLY_ID_TYPE_CODE)
|
||||
{
|
||||
if (registry == NULL)
|
||||
{
|
||||
throw EpicsException("deserialization provided chached ID, but no registry provided");
|
||||
}
|
||||
control->ensureData(sizeof(int16)/sizeof(int8));
|
||||
return registry->getIntrospectionInterface(buffer->getShort());
|
||||
}
|
||||
|
||||
// could also be a mask
|
||||
if(typeCode == IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE)
|
||||
{
|
||||
if(registry == NULL)
|
||||
{
|
||||
throw EpicsException("deserialization provided chached ID, but no registry provided");
|
||||
}
|
||||
control->ensureData(sizeof(int16)/sizeof(int8));
|
||||
const short key = buffer->getShort();
|
||||
FieldConstPtr field = deserialize(buffer, control, registry);
|
||||
registry->registerIntrospectionInterface(key, field);
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
// high nibble means scalar/array/structure
|
||||
const Type type = (Type)(typeCode >> 4);
|
||||
switch (type)
|
||||
{
|
||||
case scalar:
|
||||
{
|
||||
const ScalarType scalar = (ScalarType)(typeCode & 0x0F);
|
||||
const String scalarFieldName = SerializeHelper::deserializeString(buffer, control);
|
||||
return static_cast<FieldConstPtr>(_fieldCreate->createScalar(scalarFieldName,scalar));
|
||||
}
|
||||
case scalarArray:
|
||||
{
|
||||
const ScalarType element = (ScalarType)(typeCode & 0x0F);
|
||||
const String arrayFieldName = SerializeHelper::deserializeString(buffer, control);
|
||||
return static_cast<FieldConstPtr>(_fieldCreate->createScalarArray(arrayFieldName,element));
|
||||
}
|
||||
case structure:
|
||||
{
|
||||
return static_cast<FieldConstPtr>(deserializeStructureField(buffer, control, registry));
|
||||
}
|
||||
case structureArray:
|
||||
{
|
||||
const String structureArrayFieldName = SerializeHelper::deserializeString(buffer, control);
|
||||
const StructureConstPtr arrayElement = deserializeStructureField(buffer, control, registry);
|
||||
return static_cast<FieldConstPtr>(_fieldCreate->createStructureArray(structureArrayFieldName, arrayElement));
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::string msg = "unsupported type: " + type;
|
||||
throw EpicsException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StructureConstPtr IntrospectionRegistry::deserializeStructureField(ByteBuffer* buffer, DeserializableControl* control, IntrospectionRegistry* registry)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
const String structureFieldName = SerializeHelper::deserializeString(buffer, control);
|
||||
const int32 size = SerializeHelper::readSize(buffer, control);
|
||||
FieldConstPtrArray fields = NULL;
|
||||
if (size > 0)
|
||||
{
|
||||
fields = new FieldConstPtr[size];
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
fields[i] = deserialize(buffer, control, registry);
|
||||
}
|
||||
}
|
||||
//TODO stucture constructor created new fields instead of taking this ones
|
||||
return _fieldCreate->createStructure(structureFieldName, size, fields);
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serializeStructure(ByteBuffer* buffer, SerializableControl* control, PVStructurePtr pvStructure)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
if (pvStructure == NULL)
|
||||
{
|
||||
serialize(NULL, buffer, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize(pvStructure->getField(), buffer, control);
|
||||
pvStructure->serialize(buffer, control);
|
||||
}
|
||||
}
|
||||
|
||||
PVStructurePtr IntrospectionRegistry::deserializeStructure(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
PVStructurePtr pvStructure = NULL;
|
||||
FieldConstPtr structureField = deserialize(buffer, control);
|
||||
if (structureField != NULL)
|
||||
{
|
||||
pvStructure = _pvDataCreate->createPVStructure(NULL, static_cast<StructureConstPtr>(structureField));
|
||||
pvStructure->deserialize(buffer, control);
|
||||
}
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serializePVRequest(ByteBuffer* buffer, SerializableControl* control, PVStructurePtr pvRequest)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
// for now ordinary structure, later can be changed
|
||||
serializeStructure(buffer, control, pvRequest);
|
||||
}
|
||||
|
||||
PVStructurePtr IntrospectionRegistry::deserializePVRequest(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
// for now ordinary structure, later can be changed
|
||||
return deserializeStructure(buffer, control);
|
||||
}
|
||||
|
||||
PVStructurePtr IntrospectionRegistry::deserializeStructureAndCreatePVStructure(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
FieldConstPtr field = deserialize(buffer, control);
|
||||
if (field == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return _pvDataCreate->createPVStructure(NULL,static_cast<StructureConstPtr>(field));
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::serializeStatus(ByteBuffer* buffer, SerializableControl* control, Status* status)
|
||||
{
|
||||
checkBufferAndSerializeControl(buffer, control);
|
||||
if(status != NULL)
|
||||
{
|
||||
status->serialize(buffer, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EpicsException("null status provided");
|
||||
}
|
||||
}
|
||||
|
||||
Status* IntrospectionRegistry::deserializeStatus(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
checkBufferAndDeserializeControl(buffer, control);
|
||||
return _statusCreate->deserializeStatus(buffer, control);
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::checkBufferAndSerializeControl(ByteBuffer* buffer, SerializableControl* control)
|
||||
{
|
||||
if(buffer == NULL)
|
||||
{
|
||||
throw EpicsException("null buffer provided");
|
||||
}
|
||||
if(control == NULL)
|
||||
{
|
||||
throw EpicsException("null control provided");
|
||||
}
|
||||
}
|
||||
|
||||
void IntrospectionRegistry::checkBufferAndDeserializeControl(ByteBuffer* buffer, DeserializableControl* control)
|
||||
{
|
||||
if(buffer == NULL)
|
||||
{
|
||||
throw EpicsException("null buffer provided");
|
||||
}
|
||||
if(control == NULL)
|
||||
{
|
||||
throw EpicsException("null control provided");
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
242
pvAccessApp/utils/introspectionRegistry.h
Normal file
242
pvAccessApp/utils/introspectionRegistry.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* introspectionRegistry.h
|
||||
*/
|
||||
|
||||
#ifndef INTROSPECTIONREGISTRY_H
|
||||
#define INTROSPECTIONREGISTRY_H
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <epicsMutex.h>
|
||||
|
||||
#include "lock.h"
|
||||
#include "pvIntrospect.h"
|
||||
#include "pvData.h"
|
||||
#include "byteBuffer.h"
|
||||
#include "serialize.h"
|
||||
#include "serializeHelper.h"
|
||||
#include "status.h"
|
||||
#include "standardField.h"
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvAccess {
|
||||
|
||||
typedef std::map<const short,const Field*> registryMap_t;
|
||||
|
||||
|
||||
/**
|
||||
* PVData Structure registry.
|
||||
* Registry is used to cache introspection interfaces to minimize network traffic.
|
||||
* @author gjansa
|
||||
*/
|
||||
class IntrospectionRegistry {
|
||||
public:
|
||||
IntrospectionRegistry(bool serverSide);
|
||||
virtual ~IntrospectionRegistry();
|
||||
void printKeysAndValues(string name);
|
||||
/**
|
||||
* Resets registry, i.e. must be done when transport is changed (server restarted).
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* Get introspection interface for given ID.
|
||||
*
|
||||
* @param id id of the introspection interface to get
|
||||
*
|
||||
* @return <code>Field</code> instance for given ID.
|
||||
*/
|
||||
FieldConstPtr getIntrospectionInterface(const short id);
|
||||
|
||||
/**
|
||||
* Registers introspection interface with given ID. Always INCOMING.
|
||||
*
|
||||
* @param id id of the introspection interface to register
|
||||
* @param field introspection interface to register
|
||||
*/
|
||||
void registerIntrospectionInterface(const short id, FieldConstPtr field);
|
||||
|
||||
/**
|
||||
* Registers introspection interface and get it's ID. Always OUTGOING.
|
||||
* If it is already registered only preassigned ID is returned.
|
||||
* @param field introspection interface to register
|
||||
*
|
||||
* @return id of given introspection interface
|
||||
*/
|
||||
short registerIntrospectionInterface(FieldConstPtr field, bool& existing);
|
||||
|
||||
/**
|
||||
* Serializes introspection interface
|
||||
*
|
||||
* @param field
|
||||
* @param buffer
|
||||
* @param control
|
||||
*/
|
||||
void serialize(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control);
|
||||
|
||||
/**
|
||||
* Deserializes introspection interface
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
* @param buffer
|
||||
* @param control
|
||||
*
|
||||
* @return <code>Field</code> deserialized from the buffer.
|
||||
*/
|
||||
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Serializes introspection interface. But this time really fully not like
|
||||
* the serialize which only says it serializes but in fact does not. :)
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
* @param field
|
||||
* @param buffer
|
||||
* @param control
|
||||
*/
|
||||
static void serializeFull(FieldConstPtr field, ByteBuffer* buffer, SerializableControl* control);
|
||||
|
||||
/**
|
||||
* Deserializes introspection interface
|
||||
*
|
||||
* TODO
|
||||
*
|
||||
* @param buffer
|
||||
* @param control
|
||||
*
|
||||
* @return <code>Field</code> deserialized from the buffer.
|
||||
*/
|
||||
static FieldConstPtr deserializeFull(ByteBuffer* buffer, DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Null type.
|
||||
*/
|
||||
const static int8 NULL_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* Serialization contains only an ID (that was assigned by one of the previous <code>FULL_WITH_ID</code> descriptions).
|
||||
*/
|
||||
const static int8 ONLY_ID_TYPE_CODE;
|
||||
|
||||
/**
|
||||
* Serialization contains an ID (that can be used later, if cached) and full interface description.
|
||||
*/
|
||||
const static int8 FULL_WITH_ID_TYPE_CODE;
|
||||
|
||||
|
||||
static void serialize(FieldConstPtr field, StructureConstPtr parent, ByteBuffer* buffer,
|
||||
SerializableControl* control, IntrospectionRegistry* registry);
|
||||
|
||||
|
||||
/**
|
||||
* @param buffer
|
||||
* @param control
|
||||
* @param registry
|
||||
* @param structure
|
||||
*/
|
||||
static void serializeStructureField(ByteBuffer* buffer, SerializableControl* control,
|
||||
IntrospectionRegistry* registry, StructureConstPtr structure);
|
||||
|
||||
/**
|
||||
* @param buffer
|
||||
* @param control
|
||||
* @param registry
|
||||
* @param structure
|
||||
*/
|
||||
static FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control, IntrospectionRegistry* registry);
|
||||
|
||||
/**
|
||||
* Deserialize Structure.
|
||||
* @param buffer
|
||||
* @param control
|
||||
* @param registry
|
||||
* @return deserialized Structure instance.
|
||||
*/
|
||||
static StructureConstPtr deserializeStructureField(ByteBuffer* buffer, DeserializableControl* control, IntrospectionRegistry* registry);
|
||||
|
||||
/**
|
||||
* Serialize optional PVStructrue.
|
||||
* @param buffer data buffer.
|
||||
*/
|
||||
void serializeStructure(ByteBuffer* buffer, SerializableControl* control, PVStructurePtr pvStructure);
|
||||
|
||||
/**
|
||||
* Deserialize optional PVStructrue.
|
||||
* @param payloadBuffer data buffer.
|
||||
* @return deserialized PVStructure, can be <code>null</code>.
|
||||
*/
|
||||
PVStructurePtr deserializeStructure(ByteBuffer* payloadBuffer, DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Serialize PVRequest.
|
||||
* @param buffer data buffer.
|
||||
*/
|
||||
void serializePVRequest(ByteBuffer* buffer, SerializableControl* control, PVStructurePtr pvRequest);
|
||||
|
||||
/**
|
||||
* Deserialize PVRequest.
|
||||
* @param payloadBuffer data buffer.
|
||||
* @param control
|
||||
*
|
||||
* @return deserialized PVRequest, can be <code>null</code>.
|
||||
*/
|
||||
PVStructurePtr deserializePVRequest(ByteBuffer* payloadBuffer, DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Deserialize Structure and create PVStructure instance.
|
||||
* @param payloadBuffer data buffer.
|
||||
* @return PVStructure instance, can be <code>null</code>.
|
||||
*/
|
||||
PVStructurePtr deserializeStructureAndCreatePVStructure(ByteBuffer* payloadBuffer, DeserializableControl* control);
|
||||
|
||||
/**
|
||||
* Serialize status.
|
||||
* TODO optimize duplicates
|
||||
* @param buffer data buffer.
|
||||
* @param control serializaiton control instance.
|
||||
* @param status status to serialize.
|
||||
*/
|
||||
void serializeStatus(ByteBuffer* buffer, SerializableControl* control, Status* status);
|
||||
|
||||
/**
|
||||
* Serialize status.
|
||||
* TODO optimize duplicates
|
||||
* @param buffer data buffer.
|
||||
*/
|
||||
Status* deserializeStatus(ByteBuffer* buffer, DeserializableControl* control);
|
||||
|
||||
private:
|
||||
registryMap_t _registry;
|
||||
registryMap_t::iterator _registryIter;
|
||||
registryMap_t::reverse_iterator _registryRIter;
|
||||
short _outgoingIdPointer;
|
||||
short _direction;
|
||||
Mutex _mutex;
|
||||
|
||||
/**
|
||||
* PVField factory.
|
||||
*/
|
||||
static PVDataCreate* _pvDataCreate;
|
||||
|
||||
/**
|
||||
* Status factory.
|
||||
*/
|
||||
static StatusCreate* _statusCreate;
|
||||
|
||||
/**
|
||||
* Field factory.
|
||||
*/
|
||||
static FieldCreate* _fieldCreate;
|
||||
|
||||
bool registryContainsValue(FieldConstPtr field, short& key);
|
||||
bool compareFields(FieldConstPtr field1, FieldConstPtr field2);
|
||||
static void checkBufferAndSerializeControl(ByteBuffer* buffer, SerializableControl* control);
|
||||
static void checkBufferAndDeserializeControl(ByteBuffer* buffer, DeserializableControl* control);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INTROSPECTIONREGISTRY_H */
|
||||
@@ -6,6 +6,10 @@ PROD_HOST += testChannelAccessFactory
|
||||
testChannelAccessFactory_SRCS += testChannelAccessFactory.cpp
|
||||
testChannelAccessFactory_LIBS += pvData pvAccess Com
|
||||
|
||||
PROD_HOST += testCreateRequest
|
||||
testCreateRequest_SRCS += testCreateRequest.cpp
|
||||
testCreateRequest_LIBS += pvData pvAccess Com
|
||||
|
||||
PROD_HOST += testMockClient
|
||||
testMockClient_SRCS = testMockClient.cpp MockClientImpl.cpp
|
||||
testMockClient_LIBS = pvData pvAccess Com
|
||||
|
||||
@@ -8,250 +8,9 @@
|
||||
#include <lock.h>
|
||||
#include <standardPVField.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
using std::string;
|
||||
|
||||
class CreateRequestFactory {
|
||||
private:
|
||||
|
||||
static void trim(std::string& str)
|
||||
{
|
||||
std::string::size_type pos = str.find_last_not_of(' ');
|
||||
if(pos != std::string::npos) {
|
||||
str.erase(pos + 1);
|
||||
pos = str.find_first_not_of(' ');
|
||||
if(pos != std::string::npos) str.erase(0, pos);
|
||||
}
|
||||
else str.erase(str.begin(), str.end());
|
||||
}
|
||||
|
||||
static int findMatchingBrace(string& request, int index, int numOpen) {
|
||||
size_t openBrace = request.find('{', index+1);
|
||||
size_t closeBrace = request.find('}', index+1);
|
||||
if(openBrace == std::string::npos && closeBrace == std::string::npos) return std::string::npos;
|
||||
if (openBrace != std::string::npos) {
|
||||
if(openBrace<closeBrace) return findMatchingBrace(request,openBrace,numOpen+1);
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
if(numOpen==1) return closeBrace;
|
||||
return findMatchingBrace(request,closeBrace,numOpen-1);
|
||||
}
|
||||
|
||||
static bool createFieldRequest(PVStructure* pvParent,std::string request,bool fieldListOK,Requester* requester) {
|
||||
trim(request);
|
||||
if(request.length()<=0) return true;
|
||||
size_t comma = request.find(',');
|
||||
size_t openBrace = request.find('{');
|
||||
size_t openBracket = request.find('[');
|
||||
if(openBrace != std::string::npos || openBracket != std::string::npos) fieldListOK = false;
|
||||
if(openBrace != std::string::npos && (comma==std::string::npos || comma>openBrace)) {
|
||||
//find matching brace
|
||||
size_t closeBrace = findMatchingBrace(request,openBrace+1,1);
|
||||
if(closeBrace==std::string::npos) {
|
||||
requester->message(request + "mismatched { }", errorMessage);
|
||||
return false;
|
||||
}
|
||||
String fieldName = request.substr(0,openBrace);
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0);
|
||||
createFieldRequest(pvStructure,request.substr(openBrace+1,closeBrace-openBrace-1),false,requester);
|
||||
pvParent->appendPVField(pvStructure);
|
||||
if(request.length()>closeBrace+1) {
|
||||
if(request.at(closeBrace+1) != ',') {
|
||||
requester->message(request + "misssing , after }", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createFieldRequest(pvParent,request.substr(closeBrace+2),false,requester)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(openBracket==std::string::npos && fieldListOK) {
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvParent, "fieldList", pvString));
|
||||
pvStringField->put(request);
|
||||
pvParent->appendPVField(pvStringField);
|
||||
return true;
|
||||
}
|
||||
if(openBracket!=std::string::npos && (comma==std::string::npos || comma>openBracket)) {
|
||||
size_t closeBracket = request.find(']');
|
||||
if(closeBracket==std::string::npos) {
|
||||
requester->message(request + "option does not have matching []", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createLeafFieldRequest(pvParent,request.substr(0, closeBracket+1),requester)) return false;
|
||||
if(request.rfind(',')>closeBracket) {
|
||||
int nextComma = request.find(',', closeBracket);
|
||||
if(!createFieldRequest(pvParent,request.substr(nextComma+1),false,requester)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(comma!=std::string::npos) {
|
||||
if(!createLeafFieldRequest(pvParent,request.substr(0, comma),requester)) return false;
|
||||
return createFieldRequest(pvParent,request.substr(comma+1),false,requester);
|
||||
}
|
||||
return createLeafFieldRequest(pvParent,request,requester);
|
||||
}
|
||||
|
||||
static bool createLeafFieldRequest(PVStructure* pvParent,String request,Requester* requester) {
|
||||
size_t openBracket = request.find('[');
|
||||
String fullName = request;
|
||||
if(openBracket != std::string::npos) fullName = request.substr(0,openBracket);
|
||||
size_t indLast = fullName.rfind('.');
|
||||
String fieldName = fullName;
|
||||
if(indLast>1 && indLast != std::string::npos) fieldName = fullName.substr(indLast+1);
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(pvParent, fieldName, 0);
|
||||
PVStructure* pvLeaf = getPVDataCreate()->createPVStructure(pvStructure,"leaf", 0);
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvLeaf, "source", pvString));
|
||||
pvStringField->put(fullName);
|
||||
pvLeaf->appendPVField(pvStringField);
|
||||
if(openBracket != std::string::npos) {
|
||||
size_t closeBracket = request.find(']');
|
||||
if(closeBracket==std::string::npos) {
|
||||
requester->message("option does not have matching []", errorMessage);
|
||||
return false;
|
||||
}
|
||||
if(!createRequestOptions(pvLeaf,request.substr(openBracket+1, closeBracket-openBracket-1),requester)) return false;
|
||||
}
|
||||
pvStructure->appendPVField(pvLeaf);
|
||||
pvParent->appendPVField(pvStructure);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool createRequestOptions(PVStructure* pvParent,std::string request,Requester* requester) {
|
||||
trim(request);
|
||||
if(request.length()<=1) return true;
|
||||
|
||||
std::string token;
|
||||
std::istringstream iss(request);
|
||||
while (getline(iss, token, ','))
|
||||
{
|
||||
size_t equalsPos = token.find('=');
|
||||
size_t equalsRPos = token.rfind('=');
|
||||
if (equalsPos != equalsRPos)
|
||||
{
|
||||
requester->message("illegal option ", errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
PVString* pvStringField = static_cast<PVString*>(getPVDataCreate()->createPVScalar(pvParent, token.substr(0, equalsPos), pvString));
|
||||
pvStringField->put(token.substr(equalsPos+1));
|
||||
pvParent->appendPVField(pvStringField);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a request structure for the create calls in Channel.
|
||||
* See the package overview documentation for details.
|
||||
* @param request The field request. See the package overview documentation for details.
|
||||
* @param requester The requester;
|
||||
* @return The request structure if an invalid request was given.
|
||||
*/
|
||||
static PVStructure* createRequest(String request, Requester* requester)
|
||||
{
|
||||
static String emptyString;
|
||||
if (!request.empty()) trim(request);
|
||||
if (request.empty())
|
||||
{
|
||||
return getPVDataCreate()->createPVStructure(0, emptyString, 0);
|
||||
}
|
||||
|
||||
size_t offsetRecord = request.find("record[");
|
||||
size_t offsetField = request.find("field(");
|
||||
size_t offsetPutField = request.find("putField(");
|
||||
size_t offsetGetField = request.find("getField(");
|
||||
|
||||
PVStructure* pvStructure = getPVDataCreate()->createPVStructure(0, emptyString, 0);
|
||||
if (offsetRecord != std::string::npos) {
|
||||
size_t offsetBegin = request.find('[', offsetRecord);
|
||||
size_t offsetEnd = request.find(']', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("record[ does not have matching ]", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "record", 0);
|
||||
if(!createRequestOptions(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),requester))
|
||||
{
|
||||
// TODO is this ok?
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("field( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "field", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetPutField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetPutField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("putField( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "putField", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (offsetGetField != std::string::npos) {
|
||||
size_t offsetBegin = request.find('(', offsetGetField);
|
||||
size_t offsetEnd = request.find(')', offsetBegin);
|
||||
if(offsetEnd == std::string::npos) {
|
||||
delete pvStructure;
|
||||
requester->message("getField( does not have matching )", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
PVStructure* pvStruct = getPVDataCreate()->createPVStructure(pvStructure, "getField", 0);
|
||||
if(!createFieldRequest(pvStruct,request.substr(offsetBegin+1, offsetEnd-offsetBegin-1),true,requester))
|
||||
{
|
||||
delete pvStruct;
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
pvStructure->appendPVField(pvStruct);
|
||||
}
|
||||
if (pvStructure->getStructure()->getNumberFields()==0) {
|
||||
if(!createFieldRequest(pvStructure,request,true,requester))
|
||||
{
|
||||
delete pvStructure;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return pvStructure;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static volatile int64 mockChannelProcess_totalConstruct = 0;
|
||||
static volatile int64 mockChannelProcess_totalDestruct = 0;
|
||||
static Mutex *mockChannelProcess_globalMutex = 0;
|
||||
@@ -1302,7 +1061,6 @@ class ChannelProcessRequesterImpl : public ChannelProcessRequester
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
MockClientContext* context = new MockClientContext();
|
||||
@@ -1363,116 +1121,3 @@ int main(int argc,char *argv[])
|
||||
getShowConstructDestruct()->constuctDestructTotals(stdout);
|
||||
return(0);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class RequesterImpl : public Requester {
|
||||
public:
|
||||
|
||||
virtual String getRequesterName()
|
||||
{
|
||||
return "RequesterImpl";
|
||||
};
|
||||
|
||||
virtual void message(String message,MessageType messageType)
|
||||
{
|
||||
std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
#include <epicsAssert.h>
|
||||
|
||||
static void testCreateRequest() {
|
||||
RequesterImpl requester;
|
||||
String out;
|
||||
String request = "";
|
||||
PVStructure* pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "alarm,timeStamp,power.value";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true]field(alarm,timeStamp,power.value)";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{power.value,power.alarm})";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value)";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm})";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm},"
|
||||
+ "ps0{"
|
||||
+ "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm},"
|
||||
+ "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}},"
|
||||
+ "ps1{"
|
||||
+ "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm},"
|
||||
+ "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}"
|
||||
+ "})";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "a{b{c{d}}}";
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm},"
|
||||
+ "ps0{"
|
||||
+ "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm},"
|
||||
+ "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}},"
|
||||
+ "ps1{"
|
||||
+ "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm},"
|
||||
+ "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}"
|
||||
+ ")";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = CreateRequestFactory::createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
testCreateRequest();
|
||||
|
||||
std::cout << "-----------------------------------------------------------------------" << std::endl;
|
||||
getShowConstructDestruct()->constuctDestructTotals(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
158
testApp/client/testCreateRequest.cpp
Normal file
158
testApp/client/testCreateRequest.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/* testCreateRequest.cpp */
|
||||
/* Author: Matej Sekoranja Date: 2010.12.27 */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pvAccess.h>
|
||||
#include <showConstructDestruct.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsAssert.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
|
||||
class RequesterImpl : public Requester {
|
||||
public:
|
||||
|
||||
virtual String getRequesterName()
|
||||
{
|
||||
return "RequesterImpl";
|
||||
};
|
||||
|
||||
virtual void message(String message,MessageType messageType)
|
||||
{
|
||||
std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void testCreateRequest() {
|
||||
printf("testCreateRequest... ");
|
||||
|
||||
RequesterImpl requester;
|
||||
String out;
|
||||
String request = "";
|
||||
PVStructure* pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "alarm,timeStamp,power.value";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true]field(alarm,timeStamp,power.value)";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{power.value,power.alarm})";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value)";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm})";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm},"
|
||||
+ "ps0{"
|
||||
+ "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm},"
|
||||
+ "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}},"
|
||||
+ "ps1{"
|
||||
+ "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm},"
|
||||
+ "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}"
|
||||
+ "})";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "a{b{c{d}}}";
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest);
|
||||
out.clear(); pvRequest->toString(&out); std::cout << out << std::endl;
|
||||
delete pvRequest;
|
||||
|
||||
request = "record[process=true,xxx=yyy]field(alarm,timeStamp[shareData=true],power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = String("record[process=true,xxx=yyy]")
|
||||
+ "putField(power.value)"
|
||||
+ "getField(alarm,timeStamp,power{power.value,power.alarm},"
|
||||
+ "current{current.value,current.alarm},voltage{voltage.value,voltage.alarm},"
|
||||
+ "ps0{"
|
||||
+ "ps0.alarm,ps0.timeStamp,power{ps0.power.value,ps0.power.alarm},"
|
||||
+ "current{ps0.current.value,ps0.current.alarm},voltage{ps0.voltage.value,ps0.voltage.alarm}},"
|
||||
+ "ps1{"
|
||||
+ "ps1.alarm,ps1.timeStamp,power{ps1.power.value,ps1.power.alarm},"
|
||||
+ "current{ps1.current.value,ps1.current.alarm},voltage{ps1.voltage.value,ps1.voltage.alarm}"
|
||||
+ ")";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = "record[process=true,power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = "field(power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = "putField(power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = "getField(power.value";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
request = "record[process=true=power.value]";
|
||||
std::cout << std::endl << "Error Expected for next call!!" << std::endl;
|
||||
pvRequest = getCreateRequest()->createRequest(request,&requester);
|
||||
assert(pvRequest==0);
|
||||
|
||||
printf("PASSED\n");
|
||||
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
testCreateRequest();
|
||||
|
||||
std::cout << "-----------------------------------------------------------------------" << std::endl;
|
||||
getShowConstructDestruct()->constuctDestructTotals(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ PROD_HOST += loggerTest
|
||||
loggerTest_SRCS += loggerTest.cpp
|
||||
loggerTest_LIBS += pvAccess pvData Com
|
||||
|
||||
PROD_HOST += introspectionRegisterTest
|
||||
introspectionRegisterTest_SRCS += introspectionRegistryTest.cpp
|
||||
introspectionRegisterTest_LIBS += pvAccess Com pvData
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
467
testApp/utils/introspectionRegistryTest.cpp
Normal file
467
testApp/utils/introspectionRegistryTest.cpp
Normal file
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* introspectionRegistryTest.cpp
|
||||
*
|
||||
* Created on: Dec 23, 2010
|
||||
* Author: Gasper Jansa
|
||||
*/
|
||||
|
||||
#include "introspectionRegistry.h"
|
||||
|
||||
#include <epicsAssert.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
class SerializableControlImpl : public SerializableControl,
|
||||
public NoDefaultMethods {
|
||||
public:
|
||||
virtual void flushSerializeBuffer() {
|
||||
}
|
||||
|
||||
virtual void ensureBuffer(int size) {
|
||||
}
|
||||
|
||||
SerializableControlImpl() {
|
||||
}
|
||||
|
||||
virtual ~SerializableControlImpl() {
|
||||
}
|
||||
};
|
||||
|
||||
class DeserializableControlImpl : public DeserializableControl,
|
||||
public NoDefaultMethods {
|
||||
public:
|
||||
virtual void ensureData(int size) {
|
||||
}
|
||||
|
||||
DeserializableControlImpl() {
|
||||
}
|
||||
|
||||
virtual ~DeserializableControlImpl() {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
static SerializableControl* flusher;
|
||||
static DeserializableControl* control;
|
||||
static ByteBuffer* buffer;
|
||||
|
||||
static PVDataCreate* pvDataCreate;
|
||||
static StatusCreate* statusCreate;
|
||||
static FieldCreate* fieldCreate;
|
||||
static StandardField *standardField;
|
||||
|
||||
static IntrospectionRegistry* registry;
|
||||
static IntrospectionRegistry* clientRegistry;
|
||||
static IntrospectionRegistry* serverRegistry;
|
||||
|
||||
vector<PVField*> pvFieldArray;
|
||||
|
||||
static string builder;
|
||||
|
||||
//helper methods
|
||||
ScalarConstPtr getScalar(string name)
|
||||
{
|
||||
ScalarConstPtr scalar = standardField->scalar(name,pvFloat);
|
||||
PVField *pvField = pvDataCreate->createPVField(0,scalar);
|
||||
pvFieldArray.push_back(pvField);
|
||||
return scalar;
|
||||
}
|
||||
|
||||
ScalarArrayConstPtr getScalarArray(string name)
|
||||
{
|
||||
ScalarArrayConstPtr scalarArray = standardField->scalarArray(name,pvFloat);
|
||||
PVField *pvField = pvDataCreate->createPVField(0,scalarArray);
|
||||
pvFieldArray.push_back(pvField);
|
||||
return scalarArray;
|
||||
}
|
||||
|
||||
StructureConstPtr getStructure(string name)
|
||||
{
|
||||
String properties("alarm");
|
||||
FieldConstPtr powerSupply[3];
|
||||
powerSupply[0] = standardField->scalar(
|
||||
String("voltage"),pvDouble,properties);
|
||||
PVField *pvField = pvDataCreate->createPVField(0,powerSupply[0]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
powerSupply[1] = standardField->scalar(
|
||||
String("power"),pvDouble,properties);
|
||||
pvField = pvDataCreate->createPVField(0,powerSupply[1]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
powerSupply[2] = standardField->scalar(
|
||||
String("current"),pvDouble,properties);
|
||||
pvField = pvDataCreate->createPVField(0,powerSupply[2]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
StructureConstPtr structure = standardField->structure(name,3,powerSupply);
|
||||
pvField = pvDataCreate->createPVField(0,structure);
|
||||
pvFieldArray.push_back(pvField);
|
||||
return structure;
|
||||
}
|
||||
|
||||
StructureArrayConstPtr getStructureArray(string name1, string name2)
|
||||
{
|
||||
String properties("alarm");
|
||||
FieldConstPtr powerSupply[3];
|
||||
powerSupply[0] = standardField->scalar(
|
||||
String("voltage"),pvDouble,properties);
|
||||
PVField *pvField = pvDataCreate->createPVField(0,powerSupply[0]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
powerSupply[1] = standardField->scalar(
|
||||
String("power"),pvDouble,properties);
|
||||
pvField = pvDataCreate->createPVField(0,powerSupply[1]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
powerSupply[2] = standardField->scalar(
|
||||
String("current"),pvDouble,properties);
|
||||
pvField = pvDataCreate->createPVField(0,powerSupply[2]);
|
||||
pvFieldArray.push_back(pvField);
|
||||
StructureConstPtr structure = standardField->structure(name1,3,powerSupply);
|
||||
StructureArrayConstPtr structureArray = standardField->structureArray(name2,structure);
|
||||
pvField = pvDataCreate->createPVField(0,structureArray);
|
||||
pvFieldArray.push_back(pvField);
|
||||
return structureArray;
|
||||
}
|
||||
|
||||
//test methods
|
||||
void testRegistryPutGet()
|
||||
{
|
||||
short id = 0;
|
||||
ScalarConstPtr scalarIn = getScalar("field1");
|
||||
registry->registerIntrospectionInterface(id,scalarIn);
|
||||
|
||||
id++;
|
||||
ScalarArrayConstPtr scalarArrayIn = getScalarArray("fieldArray1");
|
||||
registry->registerIntrospectionInterface(id,scalarArrayIn);
|
||||
|
||||
id++;
|
||||
StructureConstPtr structureIn = getStructure("struct1");
|
||||
registry->registerIntrospectionInterface(id,structureIn);
|
||||
|
||||
id++;
|
||||
StructureArrayConstPtr structureArrayIn = getStructureArray("struct1","structArray1");
|
||||
registry->registerIntrospectionInterface(id,structureArrayIn);
|
||||
|
||||
id = 0;
|
||||
ScalarConstPtr scalarOut = static_cast<ScalarConstPtr>(registry->getIntrospectionInterface(id));
|
||||
assert(scalarIn == scalarOut);
|
||||
|
||||
id++;
|
||||
ScalarArrayConstPtr scalarArrayOut = static_cast<ScalarArrayConstPtr>(registry->getIntrospectionInterface(id));
|
||||
assert(scalarArrayIn == scalarArrayOut);
|
||||
|
||||
id++;
|
||||
StructureConstPtr structureOut = static_cast<StructureConstPtr>(registry->getIntrospectionInterface(id));
|
||||
assert(structureIn == structureOut);
|
||||
|
||||
id++;
|
||||
StructureArrayConstPtr structureArrayOut = static_cast<StructureArrayConstPtr>(registry->getIntrospectionInterface(id));
|
||||
assert(structureArrayIn == structureArrayOut);
|
||||
|
||||
bool existing;
|
||||
id = registry->registerIntrospectionInterface(static_cast<FieldConstPtr>(scalarIn),existing);
|
||||
assert(existing == true);
|
||||
assert(id == 0);
|
||||
|
||||
id = registry->registerIntrospectionInterface(static_cast<FieldConstPtr>(scalarArrayIn),existing);
|
||||
assert(existing == true);
|
||||
assert(id == 1);
|
||||
|
||||
id = registry->registerIntrospectionInterface(static_cast<FieldConstPtr>(structureIn),existing);
|
||||
assert(existing == true);
|
||||
assert(id == 2);
|
||||
|
||||
id = registry->registerIntrospectionInterface(static_cast<FieldConstPtr>(structureArrayIn),existing);
|
||||
assert(existing == true);
|
||||
assert(id == 3);
|
||||
|
||||
//should exist
|
||||
ScalarConstPtr scalarInNew = getScalar("field1");
|
||||
id = registry->registerIntrospectionInterface(static_cast<FieldConstPtr>(scalarInNew),existing);
|
||||
assert(existing == true);
|
||||
assert(id == 0);
|
||||
|
||||
scalarOut = static_cast<ScalarConstPtr>(registry->getIntrospectionInterface(id));
|
||||
assert(scalarIn == scalarOut);
|
||||
}
|
||||
|
||||
void testRegistryReset()
|
||||
{
|
||||
registry->reset();
|
||||
|
||||
short id = 0;
|
||||
try //there is no elements so exception will be thrown
|
||||
{
|
||||
static_cast<ScalarConstPtr>(registry->getIntrospectionInterface(id));
|
||||
}
|
||||
catch(EpicsException& e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void serialize(FieldConstPtr field, IntrospectionRegistry* registry)
|
||||
{
|
||||
buffer->clear();
|
||||
registry->serialize(field,buffer,flusher);
|
||||
//should be in registry
|
||||
bool existing;
|
||||
registry->registerIntrospectionInterface(field,existing);
|
||||
assert(existing == true);
|
||||
}
|
||||
|
||||
FieldConstPtr deserialize(IntrospectionRegistry* registry)
|
||||
{
|
||||
FieldConstPtr field = registry->deserialize(buffer,control);
|
||||
PVField *pvField = pvDataCreate->createPVField(0,field);
|
||||
pvFieldArray.push_back(pvField);
|
||||
//should be in registry
|
||||
bool existing;
|
||||
registry->registerIntrospectionInterface(field,existing);
|
||||
assert(existing == true);
|
||||
return field;
|
||||
}
|
||||
|
||||
void checkTypeCode(int8 typeCodeIn)
|
||||
{
|
||||
int8 typeCode = buffer->getByte();
|
||||
assert(typeCode == typeCodeIn);
|
||||
buffer->rewind();
|
||||
}
|
||||
|
||||
void testSerializeCommon(FieldConstPtr serverField1, FieldConstPtr clientField2)
|
||||
{
|
||||
//server serializes field 1
|
||||
serialize(serverField1,serverRegistry);
|
||||
|
||||
//full should be serialized
|
||||
buffer->flip();
|
||||
checkTypeCode(IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE);
|
||||
|
||||
//client deserializes 1
|
||||
FieldConstPtr clientField1 = deserialize(clientRegistry);
|
||||
assert(serverField1->getFieldName() == clientField1->getFieldName());
|
||||
assert(serverField1->getType() == clientField1->getType());
|
||||
|
||||
//client serializes the same field
|
||||
serialize(serverField1,clientRegistry);
|
||||
|
||||
//only id should be serialized
|
||||
buffer->flip();
|
||||
checkTypeCode(IntrospectionRegistry::ONLY_ID_TYPE_CODE);
|
||||
|
||||
//server deserializes the same field
|
||||
serverField1 = deserialize(serverRegistry);
|
||||
assert(serverField1->getFieldName() == clientField1->getFieldName());
|
||||
assert(serverField1->getType() == clientField1->getType());
|
||||
|
||||
//client requests new field
|
||||
serialize(clientField2,clientRegistry);
|
||||
|
||||
//full should be serialized
|
||||
buffer->flip();
|
||||
checkTypeCode(IntrospectionRegistry::FULL_WITH_ID_TYPE_CODE);
|
||||
|
||||
//server deserializes new field
|
||||
FieldConstPtr serverField2 = deserialize(serverRegistry);
|
||||
assert(serverField2->getFieldName() == clientField2->getFieldName());
|
||||
assert(serverField2->getType() == clientField2->getType());
|
||||
}
|
||||
|
||||
void testSerialize()
|
||||
{
|
||||
clientRegistry->reset();
|
||||
serverRegistry->reset();
|
||||
stringstream ss;
|
||||
string name1,name2,name3,name4;
|
||||
|
||||
for(int i = 0, j = 0; i < 1 ; i++, j++)
|
||||
{
|
||||
name1.clear();
|
||||
name2.clear();
|
||||
ss.str("");
|
||||
ss << j;
|
||||
name1 = "field" + ss.str();
|
||||
ss.str("");
|
||||
j++;
|
||||
ss << j;
|
||||
name2 = "field" + ss.str();
|
||||
testSerializeCommon(static_cast<FieldConstPtr>(getScalar(name1)),static_cast<FieldConstPtr>(getScalar(name2)));
|
||||
|
||||
name1.clear();
|
||||
name2.clear();
|
||||
ss.str("");
|
||||
ss << j;
|
||||
name1 = "fieldArray" + ss.str();
|
||||
ss.str("");
|
||||
j++;
|
||||
ss << j;
|
||||
name2 = "fieldArray" + ss.str();
|
||||
testSerializeCommon(static_cast<FieldConstPtr>(getScalarArray(name1)),static_cast<FieldConstPtr>(getScalarArray(name2)));
|
||||
|
||||
name1.clear();
|
||||
name2.clear();
|
||||
ss.str("");
|
||||
ss << j;
|
||||
name1 = "structure" + ss.str();
|
||||
ss.str("");
|
||||
j++;
|
||||
ss << j;
|
||||
name2 = "structure" + ss.str();
|
||||
testSerializeCommon(static_cast<FieldConstPtr>(getStructure(name1)),static_cast<FieldConstPtr>(getStructure(name2)));
|
||||
|
||||
name1.clear();
|
||||
name2.clear();
|
||||
name3.clear();
|
||||
name4.clear();
|
||||
ss.str("");
|
||||
ss << j;
|
||||
name1 = "structure" + ss.str();
|
||||
name2 = "structureArray" + ss.str();
|
||||
ss.str("");
|
||||
j++;
|
||||
ss << j;
|
||||
name3 = "structure" + ss.str();
|
||||
name4 = "structureArray" + ss.str();
|
||||
testSerializeCommon(static_cast<FieldConstPtr>(getStructureArray(name1,name2)),static_cast<FieldConstPtr>(getStructureArray(name3,name4)));
|
||||
}
|
||||
|
||||
serverRegistry->printKeysAndValues("server");
|
||||
//clientRegistry->printKeysAndValues("client");
|
||||
}
|
||||
|
||||
void testSerializeFull()
|
||||
{
|
||||
buffer->clear();
|
||||
ScalarConstPtr scalarIn = getScalar("field1");
|
||||
IntrospectionRegistry::serializeFull(static_cast<FieldConstPtr>(scalarIn),buffer,flusher);
|
||||
buffer->flip();
|
||||
ScalarConstPtr scalarOut = static_cast<ScalarConstPtr>(IntrospectionRegistry::deserializeFull(buffer,control));
|
||||
PVField *pvField = pvDataCreate->createPVField(0,scalarOut);
|
||||
pvFieldArray.push_back(pvField);
|
||||
assert(scalarIn->getFieldName() == scalarOut->getFieldName());
|
||||
assert(scalarIn->getType() == scalarOut->getType());
|
||||
|
||||
buffer->clear();
|
||||
ScalarArrayConstPtr scalarArrayIn = getScalarArray("fieldArray1");
|
||||
IntrospectionRegistry::serializeFull(static_cast<FieldConstPtr>(scalarArrayIn),buffer,flusher);
|
||||
buffer->flip();
|
||||
ScalarArrayConstPtr scalarArrayOut = static_cast<ScalarArrayConstPtr>(IntrospectionRegistry::deserializeFull(buffer,control));
|
||||
pvField = pvDataCreate->createPVField(0,scalarArrayOut);
|
||||
pvFieldArray.push_back(pvField);
|
||||
assert(scalarArrayIn->getFieldName() == scalarArrayOut->getFieldName());
|
||||
assert(scalarArrayIn->getType() == scalarArrayOut->getType());
|
||||
|
||||
buffer->clear();
|
||||
StructureConstPtr structureIn = getStructure("struct1");
|
||||
IntrospectionRegistry::serializeFull(static_cast<FieldConstPtr>(structureIn),buffer,flusher);
|
||||
buffer->flip();
|
||||
StructureConstPtr structureOut = static_cast<StructureConstPtr>(IntrospectionRegistry::deserializeFull(buffer,control));
|
||||
pvField = pvDataCreate->createPVField(0,structureOut);
|
||||
pvFieldArray.push_back(pvField);
|
||||
assert(structureIn->getFieldName() == structureOut->getFieldName());
|
||||
assert(structureIn->getType() == structureOut->getType());
|
||||
|
||||
buffer->clear();
|
||||
StructureArrayConstPtr structureArrayIn = getStructureArray("struct1","structArray1");
|
||||
IntrospectionRegistry::serializeFull(static_cast<FieldConstPtr>(structureArrayIn),buffer,flusher);
|
||||
buffer->flip();
|
||||
StructureArrayConstPtr structureArrayOut = static_cast<StructureArrayConstPtr>(IntrospectionRegistry::deserializeFull(buffer,control));
|
||||
pvField = pvDataCreate->createPVField(0,structureArrayOut);
|
||||
pvFieldArray.push_back(pvField);
|
||||
assert(structureArrayIn->getFieldName() == structureArrayOut->getFieldName());
|
||||
assert(structureArrayIn->getType() == structureArrayOut->getType());
|
||||
}
|
||||
|
||||
void testSerializePVRequest()
|
||||
{
|
||||
buffer->clear();
|
||||
registry->reset();
|
||||
PVStructurePtr pvStructureIn = pvDataCreate->createPVStructure(NULL,getStructure("structure1"));
|
||||
registry->serializePVRequest(buffer,flusher,pvStructureIn);
|
||||
|
||||
buffer->flip();
|
||||
PVStructurePtr pvStructureOut = registry->deserializePVRequest(buffer,control);
|
||||
assert(*pvStructureIn == *pvStructureOut);
|
||||
delete pvStructureIn;
|
||||
delete pvStructureOut;
|
||||
}
|
||||
|
||||
void testDeserializeStructureAndCreatePVStructure()
|
||||
{
|
||||
buffer->clear();
|
||||
registry->reset();
|
||||
StructureConstPtr structureIn = getStructure("structure1");
|
||||
serialize(structureIn,registry);
|
||||
|
||||
buffer->flip();
|
||||
PVStructurePtr pvStructureOut = registry->deserializeStructureAndCreatePVStructure(buffer,control);
|
||||
StructureConstPtr structureOut = pvStructureOut->getStructure();
|
||||
assert(structureIn->getFieldName() == structureOut->getFieldName());
|
||||
assert(structureIn->getType() == structureOut->getType());
|
||||
delete pvStructureOut;
|
||||
}
|
||||
|
||||
void testSerializeStatus()
|
||||
{
|
||||
buffer->clear();
|
||||
registry->reset();
|
||||
Status* statusIn = statusCreate->getStatusOK();
|
||||
registry->serializeStatus(buffer,flusher,statusIn);
|
||||
|
||||
buffer->flip();
|
||||
Status* statusOut= registry->deserializeStatus(buffer,control);
|
||||
assert(statusIn->getType() == statusOut->getType());
|
||||
delete statusOut;
|
||||
//TODO why are in and out on the same address?
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
//TODO something is wrong with freeing structure and structure array, should be checked.
|
||||
|
||||
pvDataCreate = getPVDataCreate();
|
||||
statusCreate = getStatusCreate();
|
||||
fieldCreate = getFieldCreate();
|
||||
standardField = getStandardField();
|
||||
|
||||
flusher = new SerializableControlImpl();
|
||||
control = new DeserializableControlImpl();
|
||||
buffer = new ByteBuffer(1<<16);
|
||||
registry = new IntrospectionRegistry(true);
|
||||
clientRegistry = new IntrospectionRegistry(false);
|
||||
serverRegistry = new IntrospectionRegistry(true);
|
||||
|
||||
|
||||
testRegistryPutGet();
|
||||
testRegistryReset();
|
||||
testSerialize();
|
||||
testSerializeFull();
|
||||
testDeserializeStructureAndCreatePVStructure();
|
||||
testSerializeStatus();
|
||||
|
||||
registry->reset();
|
||||
clientRegistry->reset();
|
||||
serverRegistry->reset();
|
||||
for (unsigned int i=0; i < pvFieldArray.size(); i++)
|
||||
{
|
||||
delete pvFieldArray[i];
|
||||
}
|
||||
pvFieldArray.clear();
|
||||
|
||||
if(flusher) delete flusher;
|
||||
if(control) delete control;
|
||||
if(buffer) delete buffer;
|
||||
if(registry) delete registry;
|
||||
if(clientRegistry) delete clientRegistry;
|
||||
if(serverRegistry) delete serverRegistry;
|
||||
cout << "DONE" << endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user