Skip to content

Commit 7b5b661

Browse files
author
Jason Yellick
committed
[FAB-4103] Proto translator variably opaque comp
The proto translation framework introduced in FAB-4100 needs to be applied to messages with opaque fields. This is one of the key goals of proto translation, which prevents the protos as defined from being human readable. This CR adds a variably opaque proto msg handler to the proto translation framework. Documented further in api.go, but variably opaque fields differ from statically opaque ones, in that variably oapque fields may depend upon the contents of the proto being populated to determine type information at runtime and will be evaluated after the static ones. Change-Id: Iacbba1316f8e82dee68695aa98bf4c30a1a139da Signed-off-by: Jason Yellick <[email protected]>
1 parent 7fd6a90 commit 7b5b661

File tree

7 files changed

+432
-27
lines changed

7 files changed

+432
-27
lines changed

common/tools/protolator/api.go

+46
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ import (
2727
// opaque byte fields are represented as their expanded proto contents) and back once again
2828
// to standard proto messages.
2929
//
30+
// There are currently two different types of interfaces available for protos to implement:
31+
//
32+
// 1. StaticallyOpaque*FieldProto: These interfaces should be implemented by protos which have
33+
// opaque byte fields whose marshaled type is known at compile time. This is mostly true
34+
// for the signature oriented fields like the Envelope.Payload, or Header.ChannelHeader
35+
//
36+
// 2. VariablyOpaque*FieldProto: These interfaces are identical to the StaticallyOpaque*FieldProto
37+
// definitions, with the exception that they are guaranteed to be evaluated after the
38+
// StaticallyOpaque*FieldProto definitions. In particular, this allows for the type selection of
39+
// a VariablyOpaque*FieldProto to depend on data populated by the StaticallyOpaque*FieldProtos.
40+
// For example, the Payload.data field depends upon the Payload.Header.ChannelHeader.type field,
41+
// which is along a statically marshaled path.
42+
//
3043
///////////////////////////////////////////////////////////////////////////////////////////////////
3144

3245
// StaticallyOpaqueFieldProto should be implemented by protos which have bytes fields which
@@ -61,3 +74,36 @@ type StaticallyOpaqueSliceFieldProto interface {
6174
// type for the field name.
6275
StaticallyOpaqueSliceFieldProto(name string, index int) (proto.Message, error)
6376
}
77+
78+
// VariablyOpaqueFieldProto should be implemented by protos which have bytes fields which
79+
// are the marshaled value depends upon the other contents of the proto
80+
type VariablyOpaqueFieldProto interface {
81+
// VariablyOpaqueFields returns the field names which contain opaque data
82+
VariablyOpaqueFields() []string
83+
84+
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
85+
// type for the field name.
86+
VariablyOpaqueFieldProto(name string) (proto.Message, error)
87+
}
88+
89+
// VariablyOpaqueMapFieldProto should be implemented by protos which have maps to bytes fields
90+
// which are the marshaled value of a a message type determined by the other contents of the proto
91+
type VariablyOpaqueMapFieldProto interface {
92+
// VariablyOpaqueFields returns the field names which contain opaque data
93+
VariablyOpaqueMapFields() []string
94+
95+
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
96+
// type for the field name.
97+
VariablyOpaqueMapFieldProto(name string, key string) (proto.Message, error)
98+
}
99+
100+
// VariablyOpaqueSliceFieldProto should be implemented by protos which have maps to bytes fields
101+
// which are the marshaled value of a a message type determined by the other contents of the proto
102+
type VariablyOpaqueSliceFieldProto interface {
103+
// VariablyOpaqueFields returns the field names which contain opaque data
104+
VariablyOpaqueSliceFields() []string
105+
106+
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
107+
// type for the field name.
108+
VariablyOpaqueSliceFieldProto(name string, index int) (proto.Message, error)
109+
}

common/tools/protolator/json.go

+3
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ func jsonToMap(marshaled []byte) (map[string]interface{}, error) {
251251
// Factories listed lower, may depend on factories listed higher being
252252
// evaluated first.
253253
var fieldFactories = []protoFieldFactory{
254+
variablyOpaqueSliceFieldFactory{},
255+
variablyOpaqueMapFieldFactory{},
256+
variablyOpaqueFieldFactory{},
254257
staticallyOpaqueSliceFieldFactory{},
255258
staticallyOpaqueMapFieldFactory{},
256259
staticallyOpaqueFieldFactory{},

common/tools/protolator/testprotos/sample.go

+51
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,54 @@ func (som *StaticallyOpaqueMsg) StaticallyOpaqueSliceFieldProto(name string, ind
5757

5858
return &SimpleMsg{}, nil
5959
}
60+
61+
func typeSwitch(typeName string) (proto.Message, error) {
62+
switch typeName {
63+
case "SimpleMsg":
64+
return &SimpleMsg{}, nil
65+
case "NestedMsg":
66+
return &NestedMsg{}, nil
67+
case "StaticallyOpaqueMsg":
68+
return &StaticallyOpaqueMsg{}, nil
69+
case "VariablyOpaqueMsg":
70+
return &VariablyOpaqueMsg{}, nil
71+
default:
72+
return nil, fmt.Errorf("unknown message type: %s", typeName)
73+
}
74+
}
75+
76+
func (vom *VariablyOpaqueMsg) VariablyOpaqueFields() []string {
77+
return []string{"plain_opaque_field"}
78+
}
79+
80+
func (vom *VariablyOpaqueMsg) VariablyOpaqueFieldProto(name string) (proto.Message, error) {
81+
if name != vom.VariablyOpaqueFields()[0] {
82+
return nil, fmt.Errorf("not a statically opaque field: %s", name)
83+
}
84+
85+
return typeSwitch(vom.OpaqueType)
86+
}
87+
88+
func (vom *VariablyOpaqueMsg) VariablyOpaqueMapFields() []string {
89+
return []string{"map_opaque_field"}
90+
}
91+
92+
func (vom *VariablyOpaqueMsg) VariablyOpaqueMapFieldProto(name string, key string) (proto.Message, error) {
93+
if name != vom.VariablyOpaqueMapFields()[0] {
94+
return nil, fmt.Errorf("not a statically opaque field: %s", name)
95+
}
96+
97+
return typeSwitch(vom.OpaqueType)
98+
}
99+
100+
func (vom *VariablyOpaqueMsg) VariablyOpaqueSliceFields() []string {
101+
return []string{"slice_opaque_field"}
102+
}
103+
104+
func (vom *VariablyOpaqueMsg) VariablyOpaqueSliceFieldProto(name string, index int) (proto.Message, error) {
105+
if name != vom.VariablyOpaqueSliceFields()[0] {
106+
return nil, fmt.Errorf("not a statically opaque field: %s", name)
107+
}
108+
109+
return typeSwitch(vom.OpaqueType)
110+
}

common/tools/protolator/testprotos/sample.pb.go

+54-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/tools/protolator/testprotos/sample.proto

+10
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,18 @@ message NestedMsg {
3636
}
3737

3838
// StaticallyOpaqueMsg is designed to test the statically opaque message component
39+
// All fields are statically marshaled to the NestedMsg type
3940
message StaticallyOpaqueMsg {
4041
bytes plain_opaque_field = 1;
4142
map<string, bytes> map_opaque_field = 2;
4243
repeated bytes slice_opaque_field = 3;
4344
}
45+
46+
// VariablyOpaqueMsg is designed to test the staticaly opaque message component
47+
// The opaque type is determined by opaque_type
48+
message VariablyOpaqueMsg {
49+
string opaque_type = 1;
50+
bytes plain_opaque_field = 2;
51+
map<string, bytes> map_opaque_field = 3;
52+
repeated bytes slice_opaque_field = 4;
53+
}
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package protolator
18+
19+
import (
20+
"reflect"
21+
22+
"github.com/golang/protobuf/proto"
23+
)
24+
25+
type variablyOpaqueFieldFactory struct{}
26+
27+
func (soff variablyOpaqueFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool {
28+
opaqueProto, ok := msg.(VariablyOpaqueFieldProto)
29+
if !ok {
30+
return false
31+
}
32+
33+
return stringInSlice(fieldName, opaqueProto.VariablyOpaqueFields())
34+
}
35+
36+
func (soff variablyOpaqueFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) {
37+
opaqueProto := msg.(VariablyOpaqueFieldProto) // Type checked in Handles
38+
39+
return &plainField{
40+
baseField: baseField{
41+
msg: msg,
42+
name: fieldName,
43+
fType: mapStringInterfaceType,
44+
vType: bytesType,
45+
value: fieldValue,
46+
},
47+
populateFrom: func(v interface{}, dT reflect.Type) (reflect.Value, error) {
48+
return opaqueFrom(func() (proto.Message, error) { return opaqueProto.VariablyOpaqueFieldProto(fieldName) }, v, dT)
49+
},
50+
populateTo: func(v reflect.Value) (interface{}, error) {
51+
return opaqueTo(func() (proto.Message, error) { return opaqueProto.VariablyOpaqueFieldProto(fieldName) }, v)
52+
},
53+
}, nil
54+
}
55+
56+
type variablyOpaqueMapFieldFactory struct{}
57+
58+
func (soff variablyOpaqueMapFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool {
59+
opaqueProto, ok := msg.(VariablyOpaqueMapFieldProto)
60+
if !ok {
61+
return false
62+
}
63+
64+
return stringInSlice(fieldName, opaqueProto.VariablyOpaqueMapFields())
65+
}
66+
67+
func (soff variablyOpaqueMapFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) {
68+
opaqueProto := msg.(VariablyOpaqueMapFieldProto) // Type checked in Handles
69+
70+
return &mapField{
71+
baseField: baseField{
72+
msg: msg,
73+
name: fieldName,
74+
fType: mapStringInterfaceType,
75+
vType: fieldType,
76+
value: fieldValue,
77+
},
78+
populateFrom: func(key string, v interface{}, dT reflect.Type) (reflect.Value, error) {
79+
return opaqueFrom(func() (proto.Message, error) {
80+
return opaqueProto.VariablyOpaqueMapFieldProto(fieldName, key)
81+
}, v, dT)
82+
},
83+
populateTo: func(key string, v reflect.Value) (interface{}, error) {
84+
return opaqueTo(func() (proto.Message, error) {
85+
return opaqueProto.VariablyOpaqueMapFieldProto(fieldName, key)
86+
}, v)
87+
},
88+
}, nil
89+
}
90+
91+
type variablyOpaqueSliceFieldFactory struct{}
92+
93+
func (soff variablyOpaqueSliceFieldFactory) Handles(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) bool {
94+
opaqueProto, ok := msg.(VariablyOpaqueSliceFieldProto)
95+
if !ok {
96+
return false
97+
}
98+
99+
return stringInSlice(fieldName, opaqueProto.VariablyOpaqueSliceFields())
100+
}
101+
102+
func (soff variablyOpaqueSliceFieldFactory) NewProtoField(msg proto.Message, fieldName string, fieldType reflect.Type, fieldValue reflect.Value) (protoField, error) {
103+
opaqueProto := msg.(VariablyOpaqueSliceFieldProto) // Type checked in Handles
104+
105+
return &sliceField{
106+
baseField: baseField{
107+
msg: msg,
108+
name: fieldName,
109+
fType: mapStringInterfaceType,
110+
vType: fieldType,
111+
value: fieldValue,
112+
},
113+
populateFrom: func(index int, v interface{}, dT reflect.Type) (reflect.Value, error) {
114+
return opaqueFrom(func() (proto.Message, error) {
115+
return opaqueProto.VariablyOpaqueSliceFieldProto(fieldName, index)
116+
}, v, dT)
117+
},
118+
populateTo: func(index int, v reflect.Value) (interface{}, error) {
119+
return opaqueTo(func() (proto.Message, error) {
120+
return opaqueProto.VariablyOpaqueSliceFieldProto(fieldName, index)
121+
}, v)
122+
},
123+
}, nil
124+
}

0 commit comments

Comments
 (0)