Skip to content

Commit 9ccd793

Browse files
committed
Gracefully handle non-contiguous Channel ids
1 parent 862d3ca commit 9ccd793

File tree

5 files changed

+20
-29
lines changed

5 files changed

+20
-29
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Unreleased
44

5+
* Gracefully handle non-contiguous Channel ids.
6+
57
### [v6.157](https://github.com/replicant4j/replicant/tree/v6.157) (2025-10-07) · [Full Changelog](https://github.com/replicant4j/replicant/compare/v6.156...v6.157)
68

79
Changes in this release:

client/src/main/java/replicant/SystemSchema.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,10 @@ public SystemSchema( final int id,
6767
"' passed an array of entities where entity at index " + index + " does not " +
6868
"have id matching index." );
6969
}
70-
apiInvariant( () -> Arrays.stream( channels ).allMatch( Objects::nonNull ),
71-
() -> "Replicant-0055: SystemSchema named '" + ( null == name ? "?" : name ) +
72-
"' passed an array of channels that has a null element" );
7370
for ( int i = 0; i < channels.length; i++ )
7471
{
7572
final int index = i;
76-
apiInvariant( () -> index == channels[ index ].getId(),
73+
apiInvariant( () -> null == channels[ index ] || index == channels[ index ].getId(),
7774
() -> "Replicant-0056: SystemSchema named '" + ( null == name ? "?" : name ) +
7875
"' passed an array of channels where channel at index " + index + " does not " +
7976
"have id matching index." );
@@ -173,6 +170,8 @@ public ChannelSchema getChannel( final int channelId )
173170
{
174171
apiInvariant( () -> channelId >= 0 && channelId < _channels.length,
175172
() -> "Replicant-0058: SystemSchema.getChannel(id) passed an id that is out of range." );
173+
apiInvariant( () -> null != _channels[channelId],
174+
() -> "Replicant-0008: SystemSchema.getChannel(id) attempted to access null channel." );
176175
}
177176
return _channels[ channelId ];
178177
}
@@ -183,6 +182,7 @@ public List<ChannelLinkSchema> getInwardChannelLinks( final int channelId, final
183182
return
184183
Stream
185184
.of( _channels )
185+
.filter( Objects::nonNull )
186186
.flatMap( channelSchema ->
187187
channelSchema
188188
.getEntities()
@@ -202,6 +202,7 @@ public List<ChannelLinkSchema> getInwardChannelLinks( final int channelId )
202202
return
203203
Stream
204204
.of( _channels )
205+
.filter( Objects::nonNull )
205206
.flatMap( channelSchema ->
206207
channelSchema
207208
.getEntities()

client/src/test/java/replicant/SystemSchemaTest.java

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ public void basicOperation()
1818
final EntitySchema entity2 =
1919
new EntitySchema( 1, ValueUtil.randomString(), String.class, ( i, d ) -> "", null, new ChannelLinkSchema[ 0 ] );
2020
final EntitySchema[] entities = new EntitySchema[]{ entity1, entity2 };
21-
final ChannelSchema channel1 = new ChannelSchema( 0,
21+
final ChannelSchema channel1 = new ChannelSchema( 1,
2222
ValueUtil.randomString(),
2323
null,
2424
ChannelSchema.FilterType.NONE,
2525
null,
2626
false,
2727
true,
2828
Collections.emptyList() );
29-
final ChannelSchema[] channels = { channel1 };
29+
final ChannelSchema[] channels = { null, channel1 };
3030
final SystemSchema systemSchema = new SystemSchema( id, name, channels, entities );
3131
assertEquals( systemSchema.getId(), id );
3232
assertEquals( systemSchema.getName(), name );
3333
assertEquals( systemSchema.getEntityCount(), 2 );
3434
assertEquals( systemSchema.getEntity( 0 ), entity1 );
3535
assertEquals( systemSchema.getEntity( 1 ), entity2 );
36-
assertEquals( systemSchema.getChannelCount(), 1 );
37-
assertEquals( systemSchema.getChannel( 0 ), channel1 );
36+
assertEquals( systemSchema.getChannelCount(), 2 );
37+
assertEquals( systemSchema.getChannel( 1 ), channel1 );
3838
assertEquals( systemSchema.toString(), name );
3939
}
4040

@@ -63,6 +63,7 @@ public void getEntity_BadIndex()
6363
@Test
6464
public void construct_nullEntity()
6565
{
66+
6667
final IllegalStateException exception =
6768
expectThrows( IllegalStateException.class,
6869
() -> new SystemSchema( ValueUtil.randomInt(),
@@ -73,19 +74,6 @@ public void construct_nullEntity()
7374
"Replicant-0053: SystemSchema named 'X' passed an array of entities that has a null element" );
7475
}
7576

76-
@Test
77-
public void construct_nullChannel()
78-
{
79-
final IllegalStateException exception =
80-
expectThrows( IllegalStateException.class,
81-
() -> new SystemSchema( ValueUtil.randomInt(),
82-
"X",
83-
new ChannelSchema[]{ null },
84-
new EntitySchema[]{} ) );
85-
assertEquals( exception.getMessage(),
86-
"Replicant-0055: SystemSchema named 'X' passed an array of channels that has a null element" );
87-
}
88-
8977
@Test
9078
public void construct_badEntityIndex()
9179
{

client/src/test/java/replicant/diagnostic_messages.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
"type": "INVARIANT",
3535
"messagePattern": "Unable to locate Connector by schemaId %s"
3636
},
37+
{
38+
"code": 8,
39+
"type": "API_INVARIANT",
40+
"messagePattern": "SystemSchema.getChannel(id) attempted to access null channel."
41+
},
3742
{
3843
"code": 9,
3944
"type": "API_INVARIANT",
@@ -239,11 +244,6 @@
239244
"type": "API_INVARIANT",
240245
"messagePattern": "SystemSchema named '%s' passed an array of entities where entity at index %s does not have id matching index."
241246
},
242-
{
243-
"code": 55,
244-
"type": "API_INVARIANT",
245-
"messagePattern": "SystemSchema named '%s' passed an array of channels that has a null element"
246-
},
247247
{
248248
"code": 56,
249249
"type": "API_INVARIANT",

server/src/main/java/replicant/server/transport/SchemaMetaData.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ public final class SchemaMetaData
1717

1818
public SchemaMetaData( @Nonnull final String name, @Nonnull final ChannelMetaData... channels )
1919
{
20-
assert Arrays.stream( channels ).allMatch( Objects::nonNull );
2120
for ( int i = 0; i < channels.length; i++ )
2221
{
2322
final ChannelMetaData channel = channels[ i ];
24-
if ( i != channel.getChannelId() )
23+
if ( null != channel && i != channel.getChannelId() )
2524
{
2625
final String message = "Channel at index " + i + " does not have channel id matching index: " + channel;
2726
throw new IllegalArgumentException( message );
@@ -30,7 +29,7 @@ public SchemaMetaData( @Nonnull final String name, @Nonnull final ChannelMetaDat
3029
_name = Objects.requireNonNull( name );
3130
_channels = channels;
3231
_instanceChannels =
33-
Stream.of( channels ).filter( ChannelMetaData::isInstanceGraph ).toArray( ChannelMetaData[]::new );
32+
Stream.of( channels ).filter( Objects::nonNull ).filter( ChannelMetaData::isInstanceGraph ).toArray( ChannelMetaData[]::new );
3433
}
3534

3635
@Nonnull
@@ -56,6 +55,7 @@ public ChannelMetaData getChannelMetaData( @Nonnull final ChannelAddress address
5655
@Nonnull
5756
public ChannelMetaData getChannelMetaData( final int channelId )
5857
{
58+
assert null != _channels[ channelId ];
5959
return _channels[ channelId ];
6060
}
6161

0 commit comments

Comments
 (0)