Skip to content

Commit b48ff6b

Browse files
committed
feat: BOLT protocol first version
Issue #3249
1 parent 2ed2162 commit b48ff6b

36 files changed

+4530
-0
lines changed

bolt/pom.xml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
17+
SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
18+
SPDX-License-Identifier: Apache-2.0
19+
-->
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
25+
<parent>
26+
<groupId>com.arcadedb</groupId>
27+
<artifactId>arcadedb-parent</artifactId>
28+
<version>26.2.1-SNAPSHOT</version>
29+
<relativePath>../pom.xml</relativePath>
30+
</parent>
31+
32+
<artifactId>arcadedb-bolt</artifactId>
33+
<packaging>jar</packaging>
34+
<name>ArcadeDB BOLT Protocol</name>
35+
<description>Neo4j BOLT wire protocol implementation for ArcadeDB</description>
36+
37+
<properties>
38+
<neo4j-driver.version>5.27.0</neo4j-driver.version>
39+
</properties>
40+
41+
<dependencies>
42+
<dependency>
43+
<groupId>com.arcadedb</groupId>
44+
<artifactId>arcadedb-server</artifactId>
45+
<version>${project.parent.version}</version>
46+
<scope>provided</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.neo4j.driver</groupId>
50+
<artifactId>neo4j-java-driver</artifactId>
51+
<version>${neo4j-driver.version}</version>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.arcadedb</groupId>
56+
<artifactId>arcadedb-test-utils</artifactId>
57+
<version>${project.parent.version}</version>
58+
<scope>test</scope>
59+
</dependency>
60+
</dependencies>
61+
<build>
62+
<plugins>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-shade-plugin</artifactId>
66+
</plugin>
67+
</plugins>
68+
</build>
69+
70+
</project>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
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+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.bolt;
20+
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.DataInputStream;
23+
import java.io.IOException;
24+
import java.io.InputStream;
25+
26+
/**
27+
* Handles chunked message framing for BOLT protocol input.
28+
* Messages are received as: [chunk_size (2 bytes)][chunk_data]...[0x00 0x00]
29+
*/
30+
public class BoltChunkedInput {
31+
private final DataInputStream in;
32+
33+
public BoltChunkedInput(final InputStream in) {
34+
this.in = new DataInputStream(in);
35+
}
36+
37+
/**
38+
* Read a complete message by dechunking.
39+
* Reads chunks until a zero-length chunk is encountered.
40+
*/
41+
public byte[] readMessage() throws IOException {
42+
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
43+
44+
while (true) {
45+
// Read chunk size (2 bytes, big-endian)
46+
final int chunkSize = in.readUnsignedShort();
47+
48+
if (chunkSize == 0) {
49+
// End of message
50+
break;
51+
}
52+
53+
// Read chunk data
54+
final byte[] chunk = new byte[chunkSize];
55+
in.readFully(chunk);
56+
buffer.write(chunk);
57+
}
58+
59+
return buffer.toByteArray();
60+
}
61+
62+
/**
63+
* Read raw bytes directly (for handshake).
64+
*/
65+
public byte[] readRaw(final int length) throws IOException {
66+
final byte[] data = new byte[length];
67+
in.readFully(data);
68+
return data;
69+
}
70+
71+
/**
72+
* Read raw int (for handshake).
73+
*/
74+
public int readRawInt() throws IOException {
75+
return in.readInt();
76+
}
77+
78+
/**
79+
* Read raw unsigned short (for chunk sizes).
80+
*/
81+
public int readRawShort() throws IOException {
82+
return in.readUnsignedShort();
83+
}
84+
85+
/**
86+
* Check if data is available.
87+
*/
88+
public int available() throws IOException {
89+
return in.available();
90+
}
91+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
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+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.bolt;
20+
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.DataOutputStream;
23+
import java.io.IOException;
24+
import java.io.OutputStream;
25+
26+
/**
27+
* Handles chunked message framing for BOLT protocol.
28+
* Messages are sent as: [chunk_size (2 bytes)][chunk_data]...[0x00 0x00]
29+
*/
30+
public class BoltChunkedOutput {
31+
private static final int MAX_CHUNK_SIZE = 65535;
32+
33+
private final DataOutputStream out;
34+
35+
public BoltChunkedOutput(final OutputStream out) {
36+
this.out = new DataOutputStream(out);
37+
}
38+
39+
/**
40+
* Write a complete message with chunked framing.
41+
*/
42+
public void writeMessage(final byte[] messageData) throws IOException {
43+
int offset = 0;
44+
final int length = messageData.length;
45+
46+
while (offset < length) {
47+
final int chunkSize = Math.min(length - offset, MAX_CHUNK_SIZE);
48+
49+
// Write chunk header (2-byte size, big-endian)
50+
out.writeShort(chunkSize);
51+
52+
// Write chunk data
53+
out.write(messageData, offset, chunkSize);
54+
55+
offset += chunkSize;
56+
}
57+
58+
// Write end marker (two zero bytes)
59+
out.writeShort(0);
60+
out.flush();
61+
}
62+
63+
/**
64+
* Write raw bytes directly (for handshake).
65+
*/
66+
public void writeRaw(final byte[] data) throws IOException {
67+
out.write(data);
68+
out.flush();
69+
}
70+
71+
/**
72+
* Write raw int (for handshake version response).
73+
*/
74+
public void writeRawInt(final int value) throws IOException {
75+
out.writeInt(value);
76+
out.flush();
77+
}
78+
79+
public void flush() throws IOException {
80+
out.flush();
81+
}
82+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright © 2021-present Arcade Data Ltd (info@arcadedata.com)
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+
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd (info@arcadedata.com)
17+
* SPDX-License-Identifier: Apache-2.0
18+
*/
19+
package com.arcadedb.bolt;
20+
21+
import com.arcadedb.exception.ArcadeDBException;
22+
23+
/**
24+
* Exception for BOLT protocol errors.
25+
*/
26+
public class BoltException extends ArcadeDBException {
27+
private final String errorCode;
28+
29+
public BoltException(final String message) {
30+
super(message);
31+
this.errorCode = "Neo.DatabaseError.General.UnknownError";
32+
}
33+
34+
public BoltException(final String errorCode, final String message) {
35+
super(message);
36+
this.errorCode = errorCode;
37+
}
38+
39+
public BoltException(final String message, final Throwable cause) {
40+
super(message, cause);
41+
this.errorCode = "Neo.DatabaseError.General.UnknownError";
42+
}
43+
44+
public BoltException(final String errorCode, final String message, final Throwable cause) {
45+
super(message, cause);
46+
this.errorCode = errorCode;
47+
}
48+
49+
public String getErrorCode() {
50+
return errorCode;
51+
}
52+
53+
// Common Neo4j error codes
54+
public static final String AUTHENTICATION_ERROR = "Neo.ClientError.Security.Unauthorized";
55+
public static final String SYNTAX_ERROR = "Neo.ClientError.Statement.SyntaxError";
56+
public static final String SEMANTIC_ERROR = "Neo.ClientError.Statement.SemanticError";
57+
public static final String DATABASE_ERROR = "Neo.DatabaseError.General.UnknownError";
58+
public static final String TRANSACTION_ERROR = "Neo.ClientError.Transaction.TransactionNotFound";
59+
public static final String FORBIDDEN_ERROR = "Neo.ClientError.Security.Forbidden";
60+
public static final String PROTOCOL_ERROR = "Neo.ClientError.Request.Invalid";
61+
}

0 commit comments

Comments
 (0)