
org.neo4j.bolt.v1.messaging.PackStreamMessageFormatV1 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-bolt Show documentation
Show all versions of neo4j-bolt Show documentation
The core of Neo4j Bolt Protocol, this contains the state machine for Bolt sessions.
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.bolt.v1.messaging;
import java.io.IOException;
import java.util.Map;
import org.neo4j.bolt.v1.messaging.message.Message;
import org.neo4j.bolt.v1.packstream.PackStream;
import org.neo4j.bolt.v1.runtime.spi.Record;
import org.neo4j.kernel.api.exceptions.Status;
import static org.neo4j.bolt.v1.runtime.internal.Neo4jError.codeFromString;
import static org.neo4j.bolt.v1.runtime.spi.Records.record;
public class PackStreamMessageFormatV1 implements MessageFormat
{
public static final int VERSION = 1;
@Override
public int version()
{
return VERSION;
}
public interface MessageTypes
{
byte MSG_INIT = 0x01;
byte MSG_ACK_FAILURE = 0x0E;
byte MSG_RESET = 0x0F;
byte MSG_RUN = 0x10;
byte MSG_DISCARD_ALL = 0x2F;
byte MSG_PULL_ALL = 0x3F;
byte MSG_RECORD = 0x71;
byte MSG_SUCCESS = 0x70;
byte MSG_IGNORED = 0x7E;
byte MSG_FAILURE = 0x7F;
}
static String messageTypeName( int type )
{
switch( type )
{
case MessageTypes.MSG_INIT: return "MSG_INIT";
case MessageTypes.MSG_ACK_FAILURE: return "MSG_ACK_FAILURE";
case MessageTypes.MSG_RESET: return "MSG_RESET";
case MessageTypes.MSG_RUN: return "MSG_RUN";
case MessageTypes.MSG_DISCARD_ALL: return "MSG_DISCARD_ALL";
case MessageTypes.MSG_PULL_ALL: return "MSG_PULL_ALL";
case MessageTypes.MSG_RECORD: return "MSG_RECORD";
case MessageTypes.MSG_SUCCESS: return "MSG_SUCCESS";
case MessageTypes.MSG_IGNORED: return "MSG_IGNORED";
case MessageTypes.MSG_FAILURE: return "MSG_FAILURE";
default: return "0x" + Integer.toHexString(type);
}
}
public static class Writer implements MessageFormat.Writer
{
public static final MessageBoundaryHook NO_OP = () -> { };
private final Neo4jPack.Packer packer;
private final MessageBoundaryHook onMessageComplete;
/**
* @param packer serializer to output channel
* @param onMessageComplete invoked for each message, after it's done writing to the output
*/
public Writer( Neo4jPack.Packer packer, MessageBoundaryHook onMessageComplete )
{
this.packer = packer;
this.onMessageComplete = onMessageComplete;
}
@Override
public Writer write( Message message ) throws IOException
{
message.dispatch( this );
return this;
}
@Override
public void handleRunMessage( String statement, Map params )
throws IOException
{
packer.packStructHeader( 2, MessageTypes.MSG_RUN );
packer.pack( statement );
packer.packRawMap( params );
onMessageComplete.onMessageComplete();
}
@Override
public void handlePullAllMessage()
throws IOException
{
packer.packStructHeader( 0, MessageTypes.MSG_PULL_ALL );
onMessageComplete.onMessageComplete();
}
@Override
public void handleDiscardAllMessage()
throws IOException
{
packer.packStructHeader( 0, MessageTypes.MSG_DISCARD_ALL );
onMessageComplete.onMessageComplete();
}
@Override
public void handleRecordMessage( Record item )
throws IOException
{
Object[] fields = item.fields();
packer.packStructHeader( 1, MessageTypes.MSG_RECORD );
packer.packListHeader( fields.length );
for ( Object field : fields )
{
packer.pack( field );
}
onMessageComplete.onMessageComplete();
}
@Override
public void handleSuccessMessage( Map metadata )
throws IOException
{
packer.packStructHeader( 1, MessageTypes.MSG_SUCCESS );
packer.packRawMap( metadata );
onMessageComplete.onMessageComplete();
}
@Override
public void handleFailureMessage( Status status, String message )
throws IOException
{
packer.packStructHeader( 1, MessageTypes.MSG_FAILURE );
packer.packMapHeader( 2 );
packer.pack( "code" );
packer.pack( status.code().serialize() );
packer.pack( "message" );
packer.pack( message );
onMessageComplete.onMessageComplete();
}
@Override
public void handleIgnoredMessage() throws IOException
{
packer.packStructHeader( 0, MessageTypes.MSG_IGNORED );
onMessageComplete.onMessageComplete();
}
@Override
public void handleInitMessage( String clientName, Map credentials ) throws IOException
{
packer.packStructHeader( 1, MessageTypes.MSG_INIT );
packer.pack( clientName );
packer.packRawMap( credentials );
onMessageComplete.onMessageComplete();
}
@Override
public void handleResetMessage() throws IOException
{
packer.packStructHeader( 0, MessageTypes.MSG_RESET );
onMessageComplete.onMessageComplete();
}
@Override
public void handleAckFailureMessage() throws IOException
{
packer.packStructHeader( 0, MessageTypes.MSG_ACK_FAILURE );
onMessageComplete.onMessageComplete();
}
@Override
public void flush() throws IOException
{
packer.flush();
}
}
public static class Reader implements MessageFormat.Reader
{
private final Neo4jPack.Unpacker unpacker;
public Reader( Neo4jPack.Unpacker unpacker )
{
this.unpacker = unpacker;
}
@Override
public boolean hasNext() throws IOException
{
return unpacker.hasNext();
}
/**
* Parse a single message into the given consumer.
*/
@Override
public void read( MessageHandler output ) throws IOException, E
{
try
{
unpacker.unpackStructHeader();
int type = (int) unpacker.unpackLong();
try
{
switch ( type )
{
case MessageTypes.MSG_RUN:
unpackRunMessage( output );
break;
case MessageTypes.MSG_DISCARD_ALL:
unpackDiscardAllMessage( output );
break;
case MessageTypes.MSG_PULL_ALL:
unpackPullAllMessage( output );
break;
case MessageTypes.MSG_RECORD:
unpackRecordMessage( output );
break;
case MessageTypes.MSG_SUCCESS:
unpackSuccessMessage( output );
break;
case MessageTypes.MSG_FAILURE:
unpackFailureMessage( output );
break;
case MessageTypes.MSG_IGNORED:
unpackIgnoredMessage( output );
break;
case MessageTypes.MSG_INIT:
unpackInitMessage( output );
break;
case MessageTypes.MSG_RESET:
output.handleResetMessage();
break;
case MessageTypes.MSG_ACK_FAILURE:
output.handleAckFailureMessage();
break;
default:
throw new BoltIOException( Status.Request.Invalid,
"0x" + Integer.toHexString(type) + " is not a valid message type." );
}
}
catch( PackStream.PackStreamException e )
{
throw new BoltIOException( Status.Request.InvalidFormat,
"Unable to read " + messageTypeName (type) + " message. " +
"Error was: " + e.getMessage(), e );
}
}
catch( PackStream.PackStreamException e )
{
throw new BoltIOException( Status.Request.InvalidFormat, "Unable to read message type. " +
"Error was: " + e.getMessage(), e );
}
}
private void unpackSuccessMessage( MessageHandler output )
throws E, IOException
{
Map map = unpacker.unpackMap();
output.handleSuccessMessage( map );
}
private void unpackFailureMessage( MessageHandler output )
throws E, IOException
{
Map map = unpacker.unpackMap();
String codeStr = map.containsKey( "code" ) ?
(String) map.get( "code" ) :
Status.General.UnknownError.name();
String msg = map.containsKey( "message" ) ?
(String) map.get( "message" ) :
"";
output.handleFailureMessage( codeFromString( codeStr ), msg );
}
private void unpackIgnoredMessage( MessageHandler output )
throws E
{
output.handleIgnoredMessage();
}
private void unpackRecordMessage( MessageHandler output )
throws E, IOException
{
long length = unpacker.unpackListHeader();
final Object[] fields = new Object[(int) length];
for ( int i = 0; i < length; i++ )
{
fields[i] = unpacker.unpack();
}
output.handleRecordMessage( record( fields ) );
}
private void unpackRunMessage( MessageHandler output )
throws E, IOException
{
String statement = unpacker.unpackString();
Map params = unpacker.unpackMap();
output.handleRunMessage( statement, params );
}
private void unpackDiscardAllMessage( MessageHandler output )
throws E, IOException
{
output.handleDiscardAllMessage();
}
private void unpackPullAllMessage( MessageHandler output )
throws E, IOException
{
output.handlePullAllMessage();
}
private void unpackInitMessage( MessageHandler output ) throws IOException, E
{
String clientName = unpacker.unpackString();
Map credentials = unpacker.unpackMap();
output.handleInitMessage( clientName, credentials );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy