Skip to content

Commit 286693e

Browse files
authored
Foundational Changes for Driver and Bolt 4.1 (#698)
Prepare 4.1 branches for Bolt 4.1: - Adding Bolt Protocol V4.1 (currently identical to 4) - Refactoring protocol version to handle MAJOR.MINOR versions of the protocol
1 parent cc08efb commit 286693e

25 files changed

+388
-71
lines changed

driver/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<parent>
1414
<groupId>org.neo4j.driver</groupId>
1515
<artifactId>neo4j-java-driver-parent</artifactId>
16-
<version>4.0-SNAPSHOT</version>
16+
<version>4.1-SNAPSHOT</version>
1717
<relativePath>..</relativePath>
1818
</parent>
1919

driver/src/main/java/org/neo4j/driver/internal/async/connection/BoltProtocolUtil.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,32 @@
2020

2121
import io.netty.buffer.ByteBuf;
2222

23+
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
2324
import org.neo4j.driver.internal.messaging.v1.BoltProtocolV1;
2425
import org.neo4j.driver.internal.messaging.v2.BoltProtocolV2;
2526
import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3;
2627
import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
28+
import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41;
2729

2830
import static io.netty.buffer.Unpooled.copyInt;
2931
import static io.netty.buffer.Unpooled.unreleasableBuffer;
3032
import static java.lang.Integer.toHexString;
3133

3234
public final class BoltProtocolUtil
3335
{
34-
public static final int HTTP = 1213486160; //== 0x48545450 == "HTTP"
35-
3636
public static final int BOLT_MAGIC_PREAMBLE = 0x6060B017;
37-
public static final int NO_PROTOCOL_VERSION = 0;
37+
public static final BoltProtocolVersion NO_PROTOCOL_VERSION = new BoltProtocolVersion( 0 , 0 );
3838

3939
public static final int CHUNK_HEADER_SIZE_BYTES = 2;
4040

4141
public static final int DEFAULT_MAX_OUTBOUND_CHUNK_SIZE_BYTES = Short.MAX_VALUE / 2;
4242

4343
private static final ByteBuf HANDSHAKE_BUF = unreleasableBuffer( copyInt(
4444
BOLT_MAGIC_PREAMBLE,
45-
BoltProtocolV4.VERSION,
46-
BoltProtocolV3.VERSION,
47-
BoltProtocolV2.VERSION,
48-
BoltProtocolV1.VERSION ) ).asReadOnly();
45+
BoltProtocolV41.VERSION.toInt(),
46+
BoltProtocolV4.VERSION.toInt(),
47+
BoltProtocolV3.VERSION.toInt(),
48+
BoltProtocolV2.VERSION.toInt() ) ).asReadOnly();
4949

5050
private static final String HANDSHAKE_STRING = createHandshakeString();
5151

driver/src/main/java/org/neo4j/driver/internal/async/connection/ChannelAttributes.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.neo4j.driver.internal.BoltServerAddress;
2525
import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher;
26+
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
2627
import org.neo4j.driver.internal.util.ServerVersion;
2728

2829
import static io.netty.util.AttributeKey.newInstance;
@@ -31,7 +32,7 @@ public final class ChannelAttributes
3132
{
3233
private static final AttributeKey<String> CONNECTION_ID = newInstance( "connectionId" );
3334
private static final AttributeKey<String> POOL_ID = newInstance( "poolId" );
34-
private static final AttributeKey<Integer> PROTOCOL_VERSION = newInstance( "protocolVersion" );
35+
private static final AttributeKey<BoltProtocolVersion> PROTOCOL_VERSION = newInstance( "protocolVersion" );
3536
private static final AttributeKey<BoltServerAddress> ADDRESS = newInstance( "serverAddress" );
3637
private static final AttributeKey<ServerVersion> SERVER_VERSION = newInstance( "serverVersion" );
3738
private static final AttributeKey<Long> CREATION_TIMESTAMP = newInstance( "creationTimestamp" );
@@ -63,12 +64,12 @@ public static void setPoolId( Channel channel, String id )
6364
setOnce( channel, POOL_ID, id );
6465
}
6566

66-
public static int protocolVersion( Channel channel )
67+
public static BoltProtocolVersion protocolVersion( Channel channel )
6768
{
6869
return get( channel, PROTOCOL_VERSION );
6970
}
7071

71-
public static void setProtocolVersion( Channel channel, int version )
72+
public static void setProtocolVersion( Channel channel, BoltProtocolVersion version )
7273
{
7374
setOnce( channel, PROTOCOL_VERSION, version );
7475
}

driver/src/main/java/org/neo4j/driver/internal/async/connection/HandshakeHandler.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import org.neo4j.driver.internal.logging.ChannelActivityLogger;
3131
import org.neo4j.driver.internal.messaging.BoltProtocol;
32+
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
3233
import org.neo4j.driver.internal.messaging.MessageFormat;
3334
import org.neo4j.driver.internal.util.ErrorUtil;
3435
import org.neo4j.driver.Logger;
@@ -37,8 +38,8 @@
3738
import org.neo4j.driver.exceptions.SecurityException;
3839
import org.neo4j.driver.exceptions.ServiceUnavailableException;
3940

40-
import static org.neo4j.driver.internal.async.connection.BoltProtocolUtil.HTTP;
4141
import static org.neo4j.driver.internal.async.connection.BoltProtocolUtil.NO_PROTOCOL_VERSION;
42+
import static org.neo4j.driver.internal.messaging.BoltProtocolVersion.isHttp;
4243

4344
public class HandshakeHandler extends ReplayingDecoder<Void>
4445
{
@@ -101,8 +102,8 @@ public void exceptionCaught( ChannelHandlerContext ctx, Throwable error )
101102
@Override
102103
protected void decode( ChannelHandlerContext ctx, ByteBuf in, List<Object> out )
103104
{
104-
int serverSuggestedVersion = in.readInt();
105-
log.debug( "S: [Bolt Handshake] %d", serverSuggestedVersion );
105+
BoltProtocolVersion serverSuggestedVersion = BoltProtocolVersion.fromRawBytes( in.readInt() );
106+
log.debug( "S: [Bolt Handshake] %s", serverSuggestedVersion );
106107

107108
// this is a one-time handler, remove it when protocol version has been read
108109
ctx.pipeline().remove( this );
@@ -118,7 +119,7 @@ protected void decode( ChannelHandlerContext ctx, ByteBuf in, List<Object> out )
118119
}
119120
}
120121

121-
private BoltProtocol protocolForVersion( int version )
122+
private BoltProtocol protocolForVersion( BoltProtocolVersion version )
122123
{
123124
try
124125
{
@@ -130,26 +131,26 @@ private BoltProtocol protocolForVersion( int version )
130131
}
131132
}
132133

133-
private void protocolSelected( int version, MessageFormat messageFormat, ChannelHandlerContext ctx )
134+
private void protocolSelected( BoltProtocolVersion version, MessageFormat messageFormat, ChannelHandlerContext ctx )
134135
{
135136
ChannelAttributes.setProtocolVersion( ctx.channel(), version );
136137
pipelineBuilder.build( messageFormat, ctx.pipeline(), logging );
137138
handshakeCompletedPromise.setSuccess();
138139
}
139140

140-
private void handleUnknownSuggestedProtocolVersion( int version, ChannelHandlerContext ctx )
141+
private void handleUnknownSuggestedProtocolVersion( BoltProtocolVersion version, ChannelHandlerContext ctx )
141142
{
142-
switch ( version )
143+
if ( NO_PROTOCOL_VERSION.equals( version ) )
143144
{
144-
case NO_PROTOCOL_VERSION:
145145
fail( ctx, protocolNoSupportedByServerError() );
146-
break;
147-
case HTTP:
146+
}
147+
else if ( isHttp( version ) )
148+
{
148149
fail( ctx, httpEndpointError() );
149-
break;
150-
default:
150+
}
151+
else
152+
{
151153
fail( ctx, protocolNoSupportedByDriverError( version ) );
152-
break;
153154
}
154155
}
155156

@@ -172,7 +173,7 @@ private static Throwable httpEndpointError()
172173
"(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)" );
173174
}
174175

175-
private static Throwable protocolNoSupportedByDriverError( int suggestedProtocolVersion )
176+
private static Throwable protocolNoSupportedByDriverError( BoltProtocolVersion suggestedProtocolVersion )
176177
{
177178
return new ClientException(
178179
"Protocol error, server suggested unexpected protocol version: " + suggestedProtocolVersion );

driver/src/main/java/org/neo4j/driver/internal/messaging/BoltProtocol.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.neo4j.driver.internal.messaging.v2.BoltProtocolV2;
4040
import org.neo4j.driver.internal.messaging.v3.BoltProtocolV3;
4141
import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
42+
import org.neo4j.driver.internal.messaging.v41.BoltProtocolV41;
4243
import org.neo4j.driver.internal.spi.Connection;
4344

4445
import static org.neo4j.driver.internal.async.connection.ChannelAttributes.protocolVersion;
@@ -128,7 +129,7 @@ ResultCursorFactory runInUnmanagedTransaction(Connection connection, Query query
128129
* Returns the protocol version. It can be used for version specific error messages.
129130
* @return the protocol version.
130131
*/
131-
int version();
132+
BoltProtocolVersion version();
132133

133134
/**
134135
* Obtain an instance of the protocol for the given channel.
@@ -149,20 +150,27 @@ static BoltProtocol forChannel( Channel channel )
149150
* @return the protocol.
150151
* @throws ClientException when unable to find protocol with the given version.
151152
*/
152-
static BoltProtocol forVersion( int version )
153+
static BoltProtocol forVersion( BoltProtocolVersion version )
153154
{
154-
switch ( version )
155+
if ( BoltProtocolV1.VERSION.equals( version ) )
155156
{
156-
case BoltProtocolV1.VERSION:
157157
return BoltProtocolV1.INSTANCE;
158-
case BoltProtocolV2.VERSION:
158+
}
159+
else if ( BoltProtocolV2.VERSION.equals( version ) )
160+
{
159161
return BoltProtocolV2.INSTANCE;
160-
case BoltProtocolV3.VERSION:
162+
}
163+
else if ( BoltProtocolV3.VERSION.equals( version ) )
164+
{
161165
return BoltProtocolV3.INSTANCE;
162-
case BoltProtocolV4.VERSION:
166+
}
167+
else if ( BoltProtocolV4.VERSION.equals( version ) )
168+
{
163169
return BoltProtocolV4.INSTANCE;
164-
default:
165-
throw new ClientException( "Unknown protocol version: " + version );
170+
} else if ( BoltProtocolV41.VERSION.equals( version ) )
171+
{
172+
return BoltProtocolV41.INSTANCE;
166173
}
174+
throw new ClientException( "Unknown protocol version: " + version );
167175
}
168176
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2002-2020 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.internal.messaging;
20+
21+
import java.util.Objects;
22+
23+
public class BoltProtocolVersion implements Comparable<BoltProtocolVersion>
24+
{
25+
private final int majorVersion;
26+
private final int minorVersion;
27+
28+
public BoltProtocolVersion( int majorVersion, int minorVersion )
29+
{
30+
this.majorVersion = majorVersion;
31+
this.minorVersion = minorVersion;
32+
}
33+
34+
public static BoltProtocolVersion fromRawBytes( int rawVersion )
35+
{
36+
int major = rawVersion & 0x000000FF;
37+
int minor = ( rawVersion >> 8 ) & 0x000000FF;
38+
39+
return new BoltProtocolVersion( major, minor );
40+
}
41+
42+
public long getMinorVersion()
43+
{
44+
return minorVersion;
45+
}
46+
47+
public long getMajorVersion()
48+
{
49+
return majorVersion;
50+
}
51+
52+
public int toInt()
53+
{
54+
int shiftedMinor = minorVersion << 8;
55+
return shiftedMinor | majorVersion;
56+
}
57+
58+
/**
59+
* @return the version in format X.Y where X is the major version and Y is the minor version
60+
*/
61+
@Override
62+
public String toString()
63+
{
64+
return String.format( "%d.%d", majorVersion, minorVersion );
65+
}
66+
67+
@Override
68+
public int hashCode()
69+
{
70+
return Objects.hash( minorVersion, majorVersion );
71+
}
72+
73+
@Override
74+
public boolean equals( Object o )
75+
{
76+
if ( o == this )
77+
{
78+
return true;
79+
}
80+
else if ( !(o instanceof BoltProtocolVersion) )
81+
{
82+
return false;
83+
}
84+
else
85+
{
86+
BoltProtocolVersion other = (BoltProtocolVersion) o;
87+
return this.getMajorVersion() == other.getMajorVersion() && this.getMinorVersion() == other.getMinorVersion();
88+
}
89+
}
90+
91+
@Override
92+
public int compareTo( BoltProtocolVersion other )
93+
{
94+
int result = Integer.compare( majorVersion, other.majorVersion );
95+
96+
if ( result == 0 )
97+
{
98+
return Integer.compare( minorVersion, other.minorVersion );
99+
}
100+
101+
return result;
102+
}
103+
104+
public static boolean isHttp( BoltProtocolVersion protocolVersion )
105+
{
106+
// server would respond with `HTTP..` We read 4 bytes to figure out the version. The first two are not used
107+
// and therefore parse the `P` (80) for major and `T` (84) for minor.
108+
return protocolVersion.getMajorVersion() == 80 && protocolVersion.getMinorVersion() == 84;
109+
}
110+
}

driver/src/main/java/org/neo4j/driver/internal/messaging/request/MultiDatabaseUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020

2121
import org.neo4j.driver.exceptions.ClientException;
2222
import org.neo4j.driver.internal.DatabaseName;
23+
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
2324
import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
2425
import org.neo4j.driver.internal.spi.Connection;
2526
import org.neo4j.driver.internal.util.ServerVersion;
2627

2728
public final class MultiDatabaseUtil
2829
{
29-
public static void assertEmptyDatabaseName( DatabaseName databaseName, int boltVersion )
30+
public static void assertEmptyDatabaseName( DatabaseName databaseName, BoltProtocolVersion boltVersion )
3031
{
3132
if ( databaseName.databaseName().isPresent() )
3233
{
@@ -37,6 +38,7 @@ public static void assertEmptyDatabaseName( DatabaseName databaseName, int boltV
3738

3839
public static boolean supportsMultiDatabase( Connection connection )
3940
{
40-
return connection.serverVersion().greaterThanOrEqual( ServerVersion.v4_0_0 ) && connection.protocol().version() >= BoltProtocolV4.VERSION;
41+
return connection.serverVersion().greaterThanOrEqual( ServerVersion.v4_0_0 ) &&
42+
connection.protocol().version().compareTo( BoltProtocolV4.VERSION ) >= 0;
4143
}
4244
}

driver/src/main/java/org/neo4j/driver/internal/messaging/v1/BoltProtocolV1.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.neo4j.driver.internal.handlers.RollbackTxResponseHandler;
4747
import org.neo4j.driver.internal.handlers.RunResponseHandler;
4848
import org.neo4j.driver.internal.messaging.BoltProtocol;
49+
import org.neo4j.driver.internal.messaging.BoltProtocolVersion;
4950
import org.neo4j.driver.internal.messaging.Message;
5051
import org.neo4j.driver.internal.messaging.MessageFormat;
5152
import org.neo4j.driver.internal.messaging.request.InitMessage;
@@ -65,7 +66,7 @@
6566

6667
public class BoltProtocolV1 implements BoltProtocol
6768
{
68-
public static final int VERSION = 1;
69+
public static final BoltProtocolVersion VERSION = new BoltProtocolVersion( 1, 0 );
6970

7071
public static final BoltProtocol INSTANCE = new BoltProtocolV1();
7172

@@ -176,7 +177,7 @@ public ResultCursorFactory runInUnmanagedTransaction(Connection connection, Quer
176177
}
177178

178179
@Override
179-
public int version()
180+
public BoltProtocolVersion version()
180181
{
181182
return VERSION;
182183
}

0 commit comments

Comments
 (0)