
net.scattersphere.server.handler.stream.ConnectionReadHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scattersphere-core Show documentation
Show all versions of scattersphere-core Show documentation
Scattersphere Core library, used to run the main server.
The newest version!
/*
* Scattersphere
* Copyright 2014-2015, Scattersphere Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.scattersphere.server.handler.stream;
import net.scattersphere.data.DataSerializer;
import net.scattersphere.data.message.JobMessage;
import net.scattersphere.server.ClientConnection;
import net.scattersphere.server.handler.core.MessageHandler;
import net.scattersphere.server.handler.stream.message.StreamMessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vertx.java.core.Handler;
import org.vertx.java.core.buffer.Buffer;
import java.util.ArrayList;
import java.util.List;
/**
* This is the read handler, and is called when new data is received from an endpoint in the Streaming server.
*
* Created by kenji on 2/8/15.
*/
public class ConnectionReadHandler implements Handler {
private final ClientConnection client;
private Buffer currentBuffer;
private final List messageHandlers;
private final Logger LOG = LoggerFactory.getLogger(ConnectionReadHandler.class);
/**
* Instantiates a new read handler, receiving the {@link net.scattersphere.server.ClientConnection} container object.
*
* @param client {@link net.scattersphere.server.ClientConnection} object.
*/
public ConnectionReadHandler(ClientConnection client) {
this.client = client;
this.currentBuffer = new Buffer();
this.messageHandlers = new ArrayList<>();
messageHandlers.add(new StreamMessageHandler());
}
private void handleMessage(JobMessage message) {
// TODO: Lambda
for(MessageHandler handler : messageHandlers) {
if (handler.canHandle(message)) {
handler.handle(message, client);
return;
}
}
LOG.warn("Unknown command received from client at {}: {}", client.getEndpoint().remoteAddress(), message.getMessage());
}
/**
* Handles a read request from the client.
*
* As data is received, the header of the message must contain the number of bytes for the packet. The server will then
* wait and read data from the client. As the data is read in pieces, the packet is appended to an internal read buffer.
* Once the buffer meets or exceeds the expected payload size, the packet is trimmed, and deserialized.
*
* Once deserialized as a {@link net.scattersphere.data.message.JobMessage}, it is dispatched to an appropriate message handler. If the message was
* malformed, or the message could not be deserialized, no response is sent to the client. Rather, the server quietly
* logs the error or exception, and continues reading data from the client.
*
* Packet sizes cannot exceed that defined in {@code ClientConnection.MAX_PAYLOAD}. If this expected payload size is
* exceeded, the message is dropped, and the client is abruptly disconnected.
*
* @param buffer A {@link org.vertx.java.core.buffer.Buffer} of data from VertX.
*/
@Override
public void handle(Buffer buffer) {
byte data[] = null;
// TODO
// Go over this read code with a microscope. Check to see if there's any code in VertX that will handle
// this in a neater fashion.
if (client.getExpectedPayloadSize() == 0) {
int payloadSize = 0;
if (buffer.length() > DataSerializer.PACKET_HEADER_SIZE) {
data = buffer.getBytes();
payloadSize = DataSerializer.getPacketSize(data);
}
if (payloadSize > ClientConnection.MAX_PAYLOAD) {
LOG.debug("READ: unexpected payload size: sent={} max={}", payloadSize, ClientConnection.MAX_PAYLOAD);
client.getEndpoint().close();
return;
} else {
LOG.debug("READ: payloadSize={} appendedBufferSize={}", payloadSize, buffer.length());
}
byte[] newData = new byte[data.length - DataSerializer.PACKET_HEADER_SIZE];
System.arraycopy(data, DataSerializer.PACKET_HEADER_SIZE, newData, 0, data.length - DataSerializer.PACKET_HEADER_SIZE);
client.setExpectedPayloadSize(payloadSize);
client.getReadBuffer().setBytes(0, newData);
} else {
client.getReadBuffer().appendBuffer(buffer);
}
data = client.getReadBuffer().getBytes();
if (data.length >= client.getExpectedPayloadSize()) {
int newBufferLength = (int) (data.length - client.getExpectedPayloadSize());
byte[] newBuffer = null;
client.clearReadBuffer();
if (newBufferLength > 0) {
newBuffer = new byte[newBufferLength];
System.arraycopy(data, (int) client.getExpectedPayloadSize(), newBuffer, 0, newBufferLength);
client.getReadBuffer().setBytes(0, newBuffer);
LOG.debug("READ: appended read-ahead buffer: length={}", currentBuffer.length());
}
LOG.debug("READ: full packet received: length={}", client.getExpectedPayloadSize());
Object dataObject = DataSerializer.deserialize(data);
LOG.debug("Got message: {}", dataObject.getClass().getName());
if (dataObject instanceof JobMessage) {
JobMessage jMessage = (JobMessage) dataObject;
LOG.debug("READ: message requested: {}", jMessage);
handleMessage(jMessage);
} else {
LOG.warn("Unknown message received: " + dataObject.getClass().getName());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy