Merge with 2240b8485ef2182e083614fc304bfe7e1b6c771a

This commit is contained in:
miha_vitorovic
2010-12-27 14:02:31 +01:00
12 changed files with 1656 additions and 359 deletions

View File

@@ -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

View 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" };
}}

View File

@@ -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();
}}

View File

@@ -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>

View 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;
}
}}

View 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");
}
}
}}

View 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 */

View File

@@ -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

View File

@@ -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;
}

View 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;
}

View File

@@ -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

View 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;
}