Skip to content

Commit ff66487

Browse files
committed
[Java] Support lookup of valueRef to an enum valid value for basic encoded fields of constant presence. Issue #529.
1 parent 84d449f commit ff66487

File tree

4 files changed

+172
-18
lines changed

4 files changed

+172
-18
lines changed

sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import uk.co.real_logic.sbe.ir.Token;
2323

2424
import java.io.UnsupportedEncodingException;
25-
import java.nio.ByteOrder;
2625
import java.util.ArrayList;
2726
import java.util.List;
2827

@@ -32,8 +31,7 @@
3231
public class IrGenerator
3332
{
3433
private final List<Token> tokenList = new ArrayList<>();
35-
private ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN;
36-
34+
private MessageSchema schema;
3735
/**
3836
* Generate a complete {@link uk.co.real_logic.sbe.ir.Ir} for a given schema.
3937
*
@@ -43,6 +41,8 @@ public class IrGenerator
4341
*/
4442
public Ir generate(final MessageSchema schema, final String namespace)
4543
{
44+
this.schema = schema;
45+
4646
final List<Token> headerTokens = generateForHeader(schema);
4747
final Ir ir = new Ir(
4848
schema.packageName(),
@@ -76,7 +76,6 @@ public Ir generate(final MessageSchema schema)
7676
private List<Token> generateForMessage(final MessageSchema schema, final long messageId)
7777
{
7878
tokenList.clear();
79-
byteOrder = schema.byteOrder();
8079

8180
final Message msg = schema.getMessage(messageId);
8281

@@ -91,7 +90,6 @@ private List<Token> generateForHeader(final MessageSchema schema)
9190
{
9291
tokenList.clear();
9392

94-
byteOrder = schema.byteOrder();
9593
add(schema.messageHeader(), 0, null);
9694

9795
return tokenList;
@@ -236,7 +234,7 @@ private void add(final CompositeType type, final int currOffset, final Field fie
236234

237235
if (elementType instanceof EncodedDataType)
238236
{
239-
add((EncodedDataType)elementType, offset, null);
237+
add((EncodedDataType)elementType, offset);
240238
}
241239
else if (elementType instanceof EnumType)
242240
{
@@ -263,7 +261,7 @@ private void add(final EnumType type, final int offset, final Field field)
263261
final Encoding.Builder encodingBuilder = new Encoding.Builder()
264262
.primitiveType(encodingType)
265263
.semanticType(semanticTypeOf(type, field))
266-
.byteOrder(byteOrder);
264+
.byteOrder(schema.byteOrder());
267265

268266
if (type.presence() == Presence.OPTIONAL)
269267
{
@@ -307,7 +305,7 @@ private void add(final EnumType.ValidValue value, final PrimitiveType encodingTy
307305
.deprecated(value.deprecated())
308306
.description(value.description())
309307
.encoding(new Encoding.Builder()
310-
.byteOrder(byteOrder)
308+
.byteOrder(schema.byteOrder())
311309
.primitiveType(encodingType)
312310
.constValue(value.primitiveValue())
313311
.build());
@@ -360,27 +358,69 @@ private void add(final SetType.Choice value, final PrimitiveType encodingType)
360358
.deprecated(value.deprecated())
361359
.encoding(new Encoding.Builder()
362360
.constValue(value.primitiveValue())
363-
.byteOrder(byteOrder)
361+
.byteOrder(schema.byteOrder())
364362
.primitiveType(encodingType)
365363
.build());
366364

367365
tokenList.add(builder.build());
368366
}
369367

370-
private void add(final EncodedDataType type, final int offset, final Field field)
368+
private void add(final EncodedDataType type, final int offset)
371369
{
372370
final Encoding.Builder encodingBuilder = new Encoding.Builder()
373371
.primitiveType(type.primitiveType())
374-
.byteOrder(byteOrder)
375-
.semanticType(semanticTypeOf(type, field))
372+
.byteOrder(schema.byteOrder())
376373
.characterEncoding(type.characterEncoding());
377374

378-
if (null != field)
375+
final Token.Builder tokenBuilder = new Token.Builder()
376+
.signal(Signal.ENCODING)
377+
.name(type.name())
378+
.referencedName(type.referencedName())
379+
.size(type.encodedLength())
380+
.description(type.description())
381+
.version(type.sinceVersion())
382+
.deprecated(type.deprecated())
383+
.offset(offset);
384+
385+
switch (type.presence())
379386
{
380-
encodingBuilder.epoch(field.epoch());
381-
encodingBuilder.timeUnit(field.timeUnit());
387+
case REQUIRED:
388+
encodingBuilder
389+
.presence(Encoding.Presence.REQUIRED)
390+
.minValue(type.minValue())
391+
.maxValue(type.maxValue());
392+
break;
393+
394+
case OPTIONAL:
395+
encodingBuilder
396+
.presence(Encoding.Presence.OPTIONAL)
397+
.minValue(type.minValue())
398+
.maxValue(type.maxValue())
399+
.nullValue(type.nullValue());
400+
break;
401+
402+
case CONSTANT:
403+
encodingBuilder
404+
.presence(Encoding.Presence.CONSTANT)
405+
.constValue(type.constVal());
406+
break;
382407
}
383408

409+
final Token token = tokenBuilder.encoding(encodingBuilder.build()).build();
410+
411+
tokenList.add(token);
412+
}
413+
414+
private void add(final EncodedDataType type, final int offset, final Field field)
415+
{
416+
final Encoding.Builder encodingBuilder = new Encoding.Builder()
417+
.primitiveType(type.primitiveType())
418+
.byteOrder(schema.byteOrder())
419+
.semanticType(semanticTypeOf(type, field))
420+
.characterEncoding(type.characterEncoding())
421+
.timeUnit(field.timeUnit())
422+
.epoch(field.epoch());
423+
384424
final Token.Builder tokenBuilder = new Token.Builder()
385425
.signal(Signal.ENCODING)
386426
.name(type.name())
@@ -391,12 +431,12 @@ private void add(final EncodedDataType type, final int offset, final Field field
391431
.deprecated(type.deprecated())
392432
.offset(offset);
393433

394-
if (null != field && !(field.type() instanceof CompositeType))
434+
if (field.type() instanceof CompositeType)
395435
{
396436
tokenBuilder.version(Math.max(field.sinceVersion(), type.sinceVersion()));
397437
}
398438

399-
switch (type.presence())
439+
switch (field.presence())
400440
{
401441
case REQUIRED:
402442
encodingBuilder
@@ -414,9 +454,11 @@ private void add(final EncodedDataType type, final int offset, final Field field
414454
break;
415455

416456
case CONSTANT:
457+
final String valueRef = field.valueRef();
458+
tokenBuilder.size(0);
417459
encodingBuilder
418460
.presence(Encoding.Presence.CONSTANT)
419-
.constValue(type.constVal());
461+
.constValue(valueRef != null ? lookupValueRef(valueRef) : type.constVal());
420462
break;
421463
}
422464

@@ -425,6 +467,18 @@ private void add(final EncodedDataType type, final int offset, final Field field
425467
tokenList.add(token);
426468
}
427469

470+
private PrimitiveValue lookupValueRef(final String valueRef)
471+
{
472+
final int periodIndex = valueRef.indexOf('.');
473+
final String valueRefType = valueRef.substring(0, periodIndex);
474+
final String validValueName = valueRef.substring(periodIndex + 1);
475+
476+
final EnumType enumType = (EnumType)schema.getType(valueRefType);
477+
final EnumType.ValidValue validValue = enumType.getValidValue(validValueName);
478+
479+
return validValue.primitiveValue();
480+
}
481+
428482
private static String semanticTypeOf(final Type type, final Field field)
429483
{
430484
final String typeSemanticType = null != type ? type.semanticType() : null;

sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ public Message getMessage(final long messageId)
131131
return messageByIdMap.get(messageId);
132132
}
133133

134+
/**
135+
* Get the {@link Type} for a given name.
136+
*
137+
* @param typeName to lookup.
138+
* @return the type if found otherwise null.
139+
*/
140+
public Type getType(final String typeName)
141+
{
142+
return typeByNameMap.get(typeName);
143+
}
144+
134145
/**
135146
* Get the {@link Collection} of {@link Message}s for this Schema.
136147
*
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2017 Real Logic Ltd.
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+
package uk.co.real_logic.sbe.ir;
17+
18+
import org.junit.Test;
19+
import uk.co.real_logic.sbe.xml.IrGenerator;
20+
import uk.co.real_logic.sbe.xml.MessageSchema;
21+
import uk.co.real_logic.sbe.xml.ParserOptions;
22+
23+
import static org.hamcrest.core.Is.is;
24+
import static org.junit.Assert.assertThat;
25+
import static uk.co.real_logic.sbe.TestUtil.getLocalResource;
26+
import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse;
27+
28+
public class ValueRefsTest
29+
{
30+
@Test
31+
public void shouldGenerateValueRefToEnum()
32+
throws Exception
33+
{
34+
final MessageSchema schema = parse(getLocalResource("value-ref-schema.xml"), ParserOptions.DEFAULT);
35+
final IrGenerator irg = new IrGenerator();
36+
final Ir ir = irg.generate(schema);
37+
38+
assertThat(ir.getMessage(1).get(2).encodedLength(), is(8));
39+
assertThat(ir.getMessage(2).get(2).encodedLength(), is(0));
40+
assertThat(ir.getMessage(3).get(2).encodedLength(), is(0));
41+
assertThat(ir.getMessage(4).get(2).encodedLength(), is(0));
42+
assertThat(ir.getMessage(5).get(2).encodedLength(), is(0));
43+
}
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
3+
package="composite.elements"
4+
id="3"
5+
version="0"
6+
semanticVersion="5.2"
7+
description="Unit Test"
8+
byteOrder="littleEndian">
9+
<types>
10+
<composite name="messageHeader" description="Message identifiers and length of message root">
11+
<type name="blockLength" primitiveType="uint16"/>
12+
<type name="templateId" primitiveType="uint16"/>
13+
<type name="schemaId" primitiveType="uint16"/>
14+
<type name="version" primitiveType="uint16"/>
15+
</composite>
16+
<enum name="TimeUnit" encodingType="uint8">
17+
<validValue name="second">0</validValue>
18+
<validValue name="millisecond">3</validValue>
19+
<validValue name="microsecond">6</validValue>
20+
<validValue name="nanosecond">9</validValue>
21+
</enum>
22+
<composite name="UTCTimestampNanos" description="UTC timestamp with nanosecond precision" semanticType="UTCTimestamp" >
23+
<type name="time" primitiveType="uint64" />
24+
<type name="unit" primitiveType="uint8" presence="constant" valueRef="TimeUnit.nanosecond"/>
25+
</composite>
26+
<type name="testConstantOne" primitiveType="uint8" presence="constant">7</type>
27+
<type name="testConstantTwo" primitiveType="uint8" presence="constant" valueRef="TimeUnit.nanosecond"/>
28+
</types>
29+
30+
<sbe:message name="MsgOne" id="1">
31+
<field name="timestampComposite" id="1" type="UTCTimestampNanos"/>
32+
</sbe:message>
33+
<sbe:message name="MsgTwo" id="2">
34+
<field name="timeUnitTypeOne" id="1" type="uint8" presence="constant" valueRef="TimeUnit.millisecond"/>
35+
</sbe:message>
36+
<sbe:message name="MsgThree" id="3">
37+
<field name="timeUnitTypeOne" id="1" type="TimeUnit" presence="constant" valueRef="TimeUnit.millisecond"/>
38+
</sbe:message>
39+
<sbe:message name="MsgFour" id="4">
40+
<field name="testConstantOneField" id="1" type="testConstantOne"/>
41+
</sbe:message>
42+
<sbe:message name="MsgFive" id="5">
43+
<field name="testConstantTwoField" id="1" type="testConstantTwo"/>
44+
</sbe:message>
45+
</sbe:messageSchema>

0 commit comments

Comments
 (0)