use of org.apache.nifi.remote.exception.ProtocolException in project nifi by apache.
the class SocketClientProtocol method handshake.
public void handshake(final Peer peer, final String destinationId) throws IOException, HandshakeException {
if (handshakeComplete) {
throw new IllegalStateException("Handshake has already been completed");
}
commsIdentifier = UUID.randomUUID().toString();
logger.debug("{} handshaking with {}", this, peer);
final Map<HandshakeProperty, String> properties = new HashMap<>();
properties.put(HandshakeProperty.GZIP, String.valueOf(useCompression));
if (destinationId != null) {
properties.put(HandshakeProperty.PORT_IDENTIFIER, destinationId);
}
properties.put(HandshakeProperty.REQUEST_EXPIRATION_MILLIS, String.valueOf(timeoutMillis));
if (versionNegotiator.getVersion() >= 5) {
if (batchCount > 0) {
properties.put(HandshakeProperty.BATCH_COUNT, String.valueOf(batchCount));
}
if (batchSize > 0L) {
properties.put(HandshakeProperty.BATCH_SIZE, String.valueOf(batchSize));
}
if (batchMillis > 0L) {
properties.put(HandshakeProperty.BATCH_DURATION, String.valueOf(batchMillis));
}
}
final CommunicationsSession commsSession = peer.getCommunicationsSession();
commsSession.setTimeout(timeoutMillis);
final DataInputStream dis = new DataInputStream(commsSession.getInput().getInputStream());
final DataOutputStream dos = new DataOutputStream(commsSession.getOutput().getOutputStream());
dos.writeUTF(commsIdentifier);
if (versionNegotiator.getVersion() >= 3) {
dos.writeUTF(peer.getUrl());
transitUriPrefix = peer.getUrl();
if (!transitUriPrefix.endsWith("/")) {
transitUriPrefix = transitUriPrefix + "/";
}
}
logger.debug("Handshaking with properties {}", properties);
dos.writeInt(properties.size());
for (final Map.Entry<HandshakeProperty, String> entry : properties.entrySet()) {
dos.writeUTF(entry.getKey().name());
dos.writeUTF(entry.getValue());
}
dos.flush();
try {
handshakeResponse = Response.read(dis);
} catch (final ProtocolException e) {
throw new HandshakeException(e);
}
switch(handshakeResponse.getCode()) {
case PORT_NOT_IN_VALID_STATE:
case UNKNOWN_PORT:
case PORTS_DESTINATION_FULL:
break;
case PROPERTIES_OK:
readyForFileTransfer = true;
break;
default:
logger.error("{} received unexpected response {} from {} when negotiating Codec", new Object[] { this, handshakeResponse, peer });
peer.close();
throw new HandshakeException("Received unexpected response " + handshakeResponse);
}
logger.debug("{} Finished handshake with {}", this, peer);
handshakeComplete = true;
}
use of org.apache.nifi.remote.exception.ProtocolException in project nifi by apache.
the class SocketClientProtocol method negotiateCodec.
@Override
public FlowFileCodec negotiateCodec(final Peer peer) throws IOException, ProtocolException {
if (!handshakeComplete) {
throw new IllegalStateException("Handshake has not been performed");
}
logger.debug("{} Negotiating Codec with {}", this, peer);
final CommunicationsSession commsSession = peer.getCommunicationsSession();
final DataInputStream dis = new DataInputStream(commsSession.getInput().getInputStream());
final DataOutputStream dos = new DataOutputStream(commsSession.getOutput().getOutputStream());
RequestType.NEGOTIATE_FLOWFILE_CODEC.writeRequestType(dos);
FlowFileCodec codec = new StandardFlowFileCodec();
try {
codec = (FlowFileCodec) RemoteResourceInitiator.initiateResourceNegotiation(codec, dis, dos);
} catch (HandshakeException e) {
throw new ProtocolException(e.toString());
}
logger.debug("{} negotiated FlowFileCodec {} with {}", new Object[] { this, codec, commsSession });
return codec;
}
use of org.apache.nifi.remote.exception.ProtocolException in project nifi by apache.
the class SiteToSiteRestApiClient method initiateTransaction.
public String initiateTransaction(final TransferDirection direction, final String portId) throws IOException {
final String portType = TransferDirection.RECEIVE.equals(direction) ? "output-ports" : "input-ports";
logger.debug("initiateTransaction handshaking portType={}, portId={}", portType, portId);
final HttpPost post = createPost("/data-transfer/" + portType + "/" + portId + "/transactions");
post.setHeader("Accept", "application/json");
post.setHeader(HttpHeaders.PROTOCOL_VERSION, String.valueOf(transportProtocolVersionNegotiator.getVersion()));
setHandshakeProperties(post);
final HttpResponse response;
if (TransferDirection.RECEIVE.equals(direction)) {
response = initiateTransactionForReceive(post);
} else {
response = initiateTransactionForSend(post);
}
final int responseCode = response.getStatusLine().getStatusCode();
logger.debug("initiateTransaction responseCode={}", responseCode);
String transactionUrl;
switch(responseCode) {
case RESPONSE_CODE_CREATED:
EntityUtils.consume(response.getEntity());
transactionUrl = readTransactionUrl(response);
if (isEmpty(transactionUrl)) {
throw new ProtocolException("Server returned RESPONSE_CODE_CREATED without Location header");
}
final Header transportProtocolVersionHeader = response.getFirstHeader(HttpHeaders.PROTOCOL_VERSION);
if (transportProtocolVersionHeader == null) {
throw new ProtocolException("Server didn't return confirmed protocol version");
}
final Integer protocolVersionConfirmedByServer = Integer.valueOf(transportProtocolVersionHeader.getValue());
logger.debug("Finished version negotiation, protocolVersionConfirmedByServer={}", protocolVersionConfirmedByServer);
transportProtocolVersionNegotiator.setVersion(protocolVersionConfirmedByServer);
final Header serverTransactionTtlHeader = response.getFirstHeader(HttpHeaders.SERVER_SIDE_TRANSACTION_TTL);
if (serverTransactionTtlHeader == null) {
throw new ProtocolException("Server didn't return " + HttpHeaders.SERVER_SIDE_TRANSACTION_TTL);
}
serverTransactionTtl = Integer.parseInt(serverTransactionTtlHeader.getValue());
break;
default:
try (InputStream content = response.getEntity().getContent()) {
throw handleErrResponse(responseCode, content);
}
}
logger.debug("initiateTransaction handshaking finished, transactionUrl={}", transactionUrl);
return transactionUrl;
}
use of org.apache.nifi.remote.exception.ProtocolException in project nifi by apache.
the class AbstractTransaction method receive.
@Override
public final DataPacket receive() throws IOException {
try {
try {
if (state != TransactionState.DATA_EXCHANGED && state != TransactionState.TRANSACTION_STARTED) {
throw new IllegalStateException("Cannot receive data from " + peer + " because Transaction State is " + state);
}
if (direction == TransferDirection.SEND) {
throw new IllegalStateException("Attempting to receive data from " + peer + " but started a SEND Transaction");
}
// if we already know there's no data, just return null
if (!dataAvailable) {
return null;
}
// if we have already received a packet, check if another is available.
if (transfers > 0) {
// Determine if Peer will send us data or has no data to send us
final Response dataAvailableCode = readTransactionResponse();
switch(dataAvailableCode.getCode()) {
case CONTINUE_TRANSACTION:
logger.debug("{} {} Indicates Transaction should continue", this, peer);
this.dataAvailable = true;
break;
case FINISH_TRANSACTION:
logger.debug("{} {} Indicates Transaction should finish", this, peer);
this.dataAvailable = false;
break;
default:
throw new ProtocolException("Got unexpected response from " + peer + " when asking for data: " + dataAvailableCode);
}
}
// if no data available, return null
if (!dataAvailable) {
return null;
}
logger.debug("{} Receiving data from {}", this, peer);
final InputStream is = peer.getCommunicationsSession().getInput().getInputStream();
final InputStream dataIn = compress ? new CompressionInputStream(is) : is;
final DataPacket packet = codec.decode(new CheckedInputStream(dataIn, crc));
if (packet == null) {
this.dataAvailable = false;
} else {
transfers++;
contentBytes += packet.getSize();
}
this.state = TransactionState.DATA_EXCHANGED;
return packet;
} catch (final IOException ioe) {
throw new IOException("Failed to receive data from " + peer + " due to " + ioe, ioe);
}
} catch (final Exception e) {
error();
throw e;
}
}
use of org.apache.nifi.remote.exception.ProtocolException in project nifi by apache.
the class AbstractTransaction method confirm.
@Override
public final void confirm() throws IOException {
try {
try {
if (state == TransactionState.TRANSACTION_STARTED && !dataAvailable && direction == TransferDirection.RECEIVE) {
// client requested to receive data but no data available. no need to confirm.
state = TransactionState.TRANSACTION_CONFIRMED;
return;
}
if (state != TransactionState.DATA_EXCHANGED) {
throw new IllegalStateException("Cannot confirm Transaction because state is " + state + "; Transaction can only be confirmed when state is " + TransactionState.DATA_EXCHANGED);
}
final CommunicationsSession commsSession = peer.getCommunicationsSession();
if (direction == TransferDirection.RECEIVE) {
if (dataAvailable) {
throw new IllegalStateException("Cannot complete transaction because the sender has already sent more data than client has consumed.");
}
// we received a FINISH_TRANSACTION indicator. Send back a CONFIRM_TRANSACTION message
// to peer so that we can verify that the connection is still open. This is a two-phase commit,
// which helps to prevent the chances of data duplication. Without doing this, we may commit the
// session and then when we send the response back to the peer, the peer may have timed out and may not
// be listening. As a result, it will re-send the data. By doing this two-phase commit, we narrow the
// Critical Section involved in this transaction so that rather than the Critical Section being the
// time window involved in the entire transaction, it is reduced to a simple round-trip conversation.
logger.trace("{} Sending CONFIRM_TRANSACTION Response Code to {}", this, peer);
final String calculatedCRC = String.valueOf(crc.getValue());
writeTransactionResponse(ResponseCode.CONFIRM_TRANSACTION, calculatedCRC);
final Response confirmTransactionResponse;
try {
confirmTransactionResponse = readTransactionResponse();
} catch (final IOException ioe) {
logger.error("Failed to receive response code from {} when expecting confirmation of transaction", peer);
if (eventReporter != null) {
eventReporter.reportEvent(Severity.ERROR, "Site-to-Site", "Failed to receive response code from " + peer + " when expecting confirmation of transaction");
}
throw ioe;
}
logger.trace("{} Received {} from {}", this, confirmTransactionResponse, peer);
switch(confirmTransactionResponse.getCode()) {
case CONFIRM_TRANSACTION:
break;
case BAD_CHECKSUM:
throw new IOException(this + " Received a BadChecksum response from peer " + peer);
default:
throw new ProtocolException(this + " Received unexpected Response from peer " + peer + " : " + confirmTransactionResponse + "; expected 'Confirm Transaction' Response Code");
}
state = TransactionState.TRANSACTION_CONFIRMED;
} else {
logger.debug("{} Sent FINISH_TRANSACTION indicator to {}", this, peer);
writeTransactionResponse(ResponseCode.FINISH_TRANSACTION);
final String calculatedCRC = String.valueOf(crc.getValue());
// we've sent a FINISH_TRANSACTION. Now we'll wait for the peer to send a 'Confirm Transaction' response
final Response transactionConfirmationResponse = readTransactionResponse();
if (transactionConfirmationResponse.getCode() == ResponseCode.CONFIRM_TRANSACTION) {
// Confirm checksum and echo back the confirmation.
logger.trace("{} Received {} from {}", this, transactionConfirmationResponse, peer);
final String receivedCRC = transactionConfirmationResponse.getMessage();
// CRC was not used before version 4
if (protocolVersion > 3) {
if (!receivedCRC.equals(calculatedCRC)) {
writeTransactionResponse(ResponseCode.BAD_CHECKSUM);
throw new IOException(this + " Sent data to peer " + peer + " but calculated CRC32 Checksum as " + calculatedCRC + " while peer calculated CRC32 Checksum as " + receivedCRC + "; canceling transaction and rolling back session");
}
}
writeTransactionResponse(ResponseCode.CONFIRM_TRANSACTION, "");
} else {
throw new ProtocolException("Expected to receive 'Confirm Transaction' response from peer " + peer + " but received " + transactionConfirmationResponse);
}
state = TransactionState.TRANSACTION_CONFIRMED;
}
} catch (final IOException ioe) {
throw new IOException("Failed to confirm transaction with " + peer + " due to " + ioe, ioe);
}
} catch (final Exception e) {
error();
throw e;
}
}
Aggregations