C++ Class Mapped Google Protocol Buffer Message

  1. 摘要
Google Protocol Buffer 是一个优秀的基于二进制的网络消息编解码框架。应用于项目时,可以节省不少的人力资源、开发时间和程序BUG。但其不足之处是protobuf编译器生成的C++消息类(或者Java等其他语言的消息类)冗余数据过多,需要依赖于protobuf的编解码库,一般情况下都不能用于作为业务逻辑对象。因此大部分情况下,程序都需要另外独立定义业务逻辑对象,并且使用protobuf定义相应(不一定100%相同)的消息,并手写代码,在protobuf消息对象和C++/Java业务对象之间进行转换。

protobuf消息还有另外一个缺点,是数据类型不够丰富,特别是指针,map集合不支持,你支持继承。通过required、optional属性的扩展可以让其支持指针,通过多字段,也可以让其支持map集合。

因在工程中,有太多的,太过于相似的转换代码,因此才有想法写一个C++类与google protobuf消息直接进行转换的工具。当然一次为蓝本,还可以转换为Java、C#等其他语言。当然转换后的代码不可能100%的可以直接工作,但是可以肯定的是已经完成了99%的工作,就剩下1%一点点的手动修改即可。

关于继承的映射。基类消息作为子类消息的第一个字段,明白字段名称为base;

  1. 数据类型映射规则
编号 C++数据类型 限制 protobuf数据类型 备注
1 bool required bool  
2 (unsigned)  char required uint32  or int32 protobuf 不支持char类型,建议使用int替代
3 (unsigned) short required uint32  or int32 protobuf 不支持short类型,建议使用int替代
4 (unsigned) int required sfixed32 or fixed32  
5 (unsigned) long required sfixed32 or fixed32 建议使用 int替代
6 std::string required bytes bytes可以更好的支持中文,protobuf string只支持asscii
不要使用char * ,char[] 等,使用std::string 替代
7 类对象 required 子message  自定义类,而不是系统类对象,需要包含在同一个文件里面,
再次没有递归处理其他包含的头文件。后续可能支持
类被映射为一个消息(只映射一次)
并再次映射为消息的成员(子消息)
8 指针类型,支持2种指针:
shared_ptr
weak_ptr
optional  根据T的实际类型进行映射 T的类型为上面 编号1~7中的任意一种。
9 集合类型,包含一下几种:
std::vector
std::list
std::set
std::multiset
required
repeated
bool include_${filename}字段
根据T的实际类型进行映射
包含一个bool类型的include字段,用于指示消息传递的过程中是
否包含本字段(protobuf repeated 字段存在二义性
,在消息不包含repeated字段时,究竟时删除还是保留不变)
T的类型为上面 编号1~8中的任意一种。
10 map类型,包含2种:
std::map
std::multimap
optional
repeated
repeated
boo include_${filename}
reptead KEY ${filename}_key
reptead VALUE ${filename}_value
KEY和VALUE各自映射为一个字段。在传输过程中,
通过下标一一匹配.
KEY,VALUE的类型为上面 编号1~8中的任意一种。

3. 自动化工具
工具使用Scala BNF语法进行构建,对C++头文件进行词法语法分析(主要分析类的声明和枚举的定义),并提取类的相关信息用于生成代码。
4.工具测试结果。
 4.1 测试内容
#ifndef __FOCUS_ENTITY_H__
#define __FOCUS_ENTITY_H__




#include 
#include 
#include 

#include 
#include 
#include 

#ifdef N_ODB
#include 
#include 
#include "Focus3800B.h"
#include "EntityBuild.h"
#endif
using std::tr1::shared_ptr;
using std::tr1::enable_shared_from_this;
using std::tr1::weak_ptr;
using std::tr1::dynamic_pointer_cast;

class CFocusEntity;
class CFocusZone;
class CFocusTerminal;
class CFocusUser;

inline shared_ptr toZone( const shared_ptr & en)
{
    return dynamic_pointer_cast(en);
}
inline shared_ptr toTerminal( const shared_ptr & en)
{
    return dynamic_pointer_cast(en);
}
inline shared_ptr toUser( const shared_ptr & en)
{
     return dynamic_pointer_cast(en);
}
enum MsgNumPCtoTer {
  terminal_config = 1,
  network_basic_config = 2,
  timenow_config = 3,
  video_source_config = 16,
  video_output_config = 17,
  video_option_config = 18,
  network_advanced_config = 19,
  compatibility_config = 20,
  network_dial_config = 21,
  fire_wall_config = 22,
  communication_config = 23,
  video_config = 24,
  e1_config = 25,
  web_config = 26,
  command_config = 27,
  camera_select = 256,
  camera_advance = 257,
  camera_advance_active = 258,
  camera_up = 259,
  camera_down = 260,
  camera_left = 261,
  camera_right = 262,
  camera_near = 263,
  camera_far = 264,
  floor_apply = 512,
  chair_apply = 513,
  chair_release = 514,
  chair_viewed = 515,
  timer_preview = 516,
  auto_switch_time = 517,
  broacast_local = 518,
  force_exit = 519,
  volume_set = 520,
  mute_in_set = 521,
  mute_out_set = 522,
  dualstream_set = 523,
  conf_call_set = 524,
  accept_in_call = 525,
  reject_in_call = 526,
  conf_drop = 527,
  phone_modify = 528,
  phone_add = 529,
  feec_apply = 530,
  phone_histroy_del = 531,
  picture_show = 532,
  near_key = 533,
  far_key = 534,
  OK_key = 535,
  Ping = 768,
  video_loop = 769,
  restore = 770,
  out_test = 771,
  login_console = 1024,
  logout_console = 1025,
  restart = 1281
};

#pragma db object polymorphic callback(dbevent) table("tblEntity")
class CFocusEntity : public enable_shared_from_this
{
    friend class odb::access;
public:
     CFocusEntity();
    virtual ~CFocusEntity();
    unsigned int GetId() const { return id_; }
    void SetId(unsigned int val) { id_ = val; }

    const std::string & GetName() const { return name_; }
    void SetName(const std::string & val) { name_ = val; }

    shared_ptr GetParent() const;
    void SetParent(const shared_ptr & val) { parent_ = val; }

    virtual void dbevent( odb::callback_event e, odb::database& db );
    virtual void dbevent( odb::callback_event e, odb::database& db ) const;

    bool persist();
    bool update();
    bool erase();
#ifdef N_ODB
    virtual shared_ptr CreateBuild() { return nullptr;}
#endif
    void SendIndication();

protected:

    void InternalSendIndcation();
private:
#pragma db id auto
    unsigned int id_;
  
    std::string  name_;
   
    weak_ptr parent_;
  
};

#pragma  db object  callback(dbevent) table("tblZone")
class CFocusZone : public CFocusEntity
{
    friend class odb::access;
public:
    CFocusZone();
    ~CFocusZone();

    void AddEntity( const shared_ptr & en);
    void DelEntity( const shared_ptr & en );


    void dbevent( odb::callback_event e, odb::database& db );
    void dbevent( odb::callback_event e, odb::database& db ) const;

    shared_ptr FindEntity( unsigned int id, bool recursive = false) ;
    shared_ptr FindEntity( const std::string & name, bool recursive = false) ;
#ifdef N_ODB
    void foreach( const std::function & ) > & callback  , bool recursive = false, bool isCallItself = false);
    virtual shared_ptr CreateBuild();

#endif    
    static void SetRootZone( const shared_ptr & rootZone_);

    static const shared_ptr & GetRootZone();
protected:
    static shared_ptr rootZone;
private:
#pragma db inverse(parent_)
    std::set< shared_ptr > members_;
		std::set< int > int_members_;    	
	  std::set< CFocusEntity > raw_members_;
	  	
	  std::map< int ,shared_ptr > map_members_;
		std::map< int ,int > map_int_members_;    	
	  std::map< int ,CFocusEntity > map_raw_members_;
	  	

#ifdef N_ODB
    mutable dv::CMutex members_mutex;
#endif

};

#pragma db object callback(dbevent) table("tblTerminal")
class CFocusTerminal : public CFocusEntity
{
    friend class odb::access;
public:
    CFocusTerminal();
    ~CFocusTerminal();

    const std::string & GetAddress() const { return address_; }
    void SetAddress(const std::string & val) { address_ = val; }

    unsigned short GetPort() const { return port_; }
    void SetPort(unsigned short val) { port_ = val; }

    const std::string & GetUsername() const { return username_; }
    void SetUsername(const std::string & val) { username_ = val; }

    const std::string & GetPassword() const { return password_; }
    void SetPassword(const std::string & val) { password_ = val; }




    void dbevent( odb::callback_event e, odb::database& db );
    void dbevent( odb::callback_event e, odb::database& db ) const;

    void keepalive_init();

    

    void clear_status();

    void send_keepalive();

    void remote_login();

    void release_connect();

    bool IsOnline() const { return recv_service_ok_;}
#ifdef N_ODB
    void OnRecvMessage( T_Message &recvMsg );
   // bool IsDualEnable() const { return IsOnline () && dual_stream_status_ ;}
    bool IsLogin() const { return remote_login_ok_; }
    //bool IsAdmin() const { return remote_login_ok_ && adminstartor_ok_;}
    virtual shared_ptr CreateBuild();
    void SetDualEnable( DualLevel level );
    //bool IsInConfing() const { return conf_status_.ConfStatus > 0 ? true : false;}
    void SetCommand( unsigned long ulCommand);
    void DisConnect();
    const T_InformTerConfig & GetTerConfig() const { return ter_config_;}
    const T_InformSysStatus & GetSysStatus() const { return sys_status_;}
    const T_InformConfStatus & GetConfStatus() const { return conf_status_;}
    //const T_InformVideoConfig & GetVideoConfig() const { return video_config_; }
    const T_VideoOption & GetVideoOption() const { return video_option_; }
    const T_SetupSoftware & GetSoftwareVersion() const { return software_version_; }
    void clear_resource();
    bool CanSendMediaInfo() const { return is_recv_sys_status_;}

    unsigned int GetValveRecvRate() const { return valveRecvRate_; }
    void SetValveRecvRate(unsigned int val) { valveRecvRate_ = val; }

    unsigned int GetValveSendRate() const { return valveSendRate_; }
    void SetValveSendRate(unsigned int val) { valveSendRate_ = val; }

    unsigned int GetValveRecvFrame() const { return valveRecvFrame_; }
    void SetValveRecvFrame(unsigned int val) { valveRecvFrame_ = val; }

    unsigned int GetValveSendFrame() const { return valveSendFrame_; }
    void SetValveSendFrame(unsigned int val) { valveSendFrame_ = val; }

    unsigned int GetValveLostRate() const { return valveLostRate_; }
    void SetValveLostRate(unsigned int val) { valveLostRate_ = val; }
#endif
    const std::string & GetH323id() const { return h323id_; }
   // void SetH323id(std::string val) { h323id_ = val; }

    const std::string & GetE164() const { return e164_; }
    //void SetE164(std::string val) { e164_ = val; }
    unsigned int GetNo() const { return No_; }
    void SetNo(unsigned int val) { No_ = val; }

    const std::string & GetContacter() const { return contacter_; }
    void SetContacter(const std::string &  val) { contacter_ = val; }

    const std::string &  GetPhone() const { return phone_; }
    void SetPhone(const std::string &  val) { phone_ = val; }
private:
    std::string    address_;
   
    unsigned short port_;
    std::string username_;
    std::string password_;
    unsigned int No_;   
    std::string contacter_;   
    std::string phone_;
    unsigned int valveRecvRate_ ;
    unsigned int valveSendRate_;
    unsigned int valveRecvFrame_;
    unsigned int valveSendFrame_;
    unsigned int valveLostRate_;
  
#pragma db transient
    unsigned int connect_id_;
#pragma db transient
    unsigned int timer_id_;
#pragma db transient
    bool  recv_service_ok_;
#pragma db transient
    bool  remote_login_ok_;
#pragma db transient
    bool  adminstartor_ok_;
#pragma db transient
    bool dual_stream_status_;
#pragma db transient
    std::string h323id_;
  
#pragma db transient
    std::string e164_;
    
#ifdef N_ODB
    T_InformTerConfig ter_config_;
    T_InformSysStatus sys_status_;
    T_InformConfStatus conf_status_;
    T_VideoOption video_option_;
    T_Message     lastRecvMsg_;
    T_SetupSoftware software_version_;
    bool is_recv_sys_status_;
#endif
};

#pragma db object callback(dbevent) table("tblUser")
class CFocusUser : public CFocusEntity
{
    friend class odb::access;
public:
     CFocusUser();
    ~CFocusUser();

    const std::string & GetPassword() const { return password_; }
    void SetPassword(const std::string & val) { password_ = val; }

    void dbevent( odb::callback_event e, odb::database& db );
    void dbevent( odb::callback_event e, odb::database& db ) const;
#ifdef N_ODB
    virtual shared_ptr CreateBuild();
#endif
protected:
   
private:
    std::string password_;
};
#endif

4.2输出结果
package pbmsg;
 enum MsgNumPCtoTer
 {
terminal_config = 1;
network_basic_config = 2;
timenow_config = 3;
video_source_config = 16;
video_output_config = 17;
video_option_config = 18;
network_advanced_config = 19;
compatibility_config = 20;
network_dial_config = 21;
fire_wall_config = 22;
communication_config = 23;
video_config = 24;
e1_config = 25;
web_config = 26;
command_config = 27;
camera_select = 256;
camera_advance = 257;
camera_advance_active = 258;
camera_up = 259;
camera_down = 260;
camera_left = 261;
camera_right = 262;
camera_near = 263;
camera_far = 264;
floor_apply = 512;
chair_apply = 513;
chair_release = 514;
chair_viewed = 515;
timer_preview = 516;
auto_switch_time = 517;
broacast_local = 518;
force_exit = 519;
volume_set = 520;
mute_in_set = 521;
mute_out_set = 522;
dualstream_set = 523;
conf_call_set = 524;
accept_in_call = 525;
reject_in_call = 526;
conf_drop = 527;
phone_modify = 528;
phone_add = 529;
feec_apply = 530;
phone_histroy_del = 531;
picture_show = 532;
near_key = 533;
far_key = 534;
OK_key = 535;
Ping = 768;
video_loop = 769;
restore = 770;
out_test = 771;
login_console = 1024;
logout_console = 1025;
restart = 1281;
};

message CFocusEntity
{

optional fixed32 id = 1;
required bytes name = 2; 
optional CFocusEntity parent = 3;
};
      

message CFocusZone
{
required CFocusEntity base = 1;

optional bool include_members = 2;
repeated CFocusEntity members =3;
        

optional bool include_int_members = 4;
repeated sfixed32 int_members =5;
        

optional bool include_raw_members = 6;
repeated CFocusEntity raw_members =7;
        

optional bool include_map_members = 8;
repeated sfixed32 map_members_key =9;
repeated CFocusEntity map_members_value =10;
        

optional bool include_map_int_members = 11;
repeated sfixed32 map_int_members_key =12;
repeated sfixed32 map_int_members_value =13;
        

optional bool include_map_raw_members = 14;
repeated sfixed32 map_raw_members_key =15;
repeated CFocusEntity map_raw_members_value =16;
        
};
      

message CFocusTerminal
{
required CFocusEntity base = 1;
required bytes address = 2; 
optional uint32 port = 3;
required bytes username = 4; 
required bytes password = 5; 
optional fixed32 No = 6;
required bytes contacter = 7; 
required bytes phone = 8; 
optional fixed32 valveRecvRate = 9;
optional fixed32 valveSendRate = 10;
optional fixed32 valveRecvFrame = 11;
optional fixed32 valveSendFrame = 12;
optional fixed32 valveLostRate = 13;
optional fixed32 connect_id = 14;
optional fixed32 timer_id = 15;
optional bool recv_service_ok = 16;
optional bool remote_login_ok = 17;
optional bool adminstartor_ok = 18;
optional bool dual_stream_status = 19;
required bytes h323id = 20; 
required bytes e164 = 21; 
};
      

message CFocusUser
{
required CFocusEntity base = 1;
required bytes password = 2; 
};
      
    

Process finished with exit code 0


你可能感兴趣的:(C/C++/VC,java)