use of org.apache.nifi.stream.io.ByteArrayOutputStream in project nifi by apache.
the class TestLeakyBucketThrottler method testDirectInterface.
@Test(timeout = 10000)
public void testDirectInterface() throws IOException, InterruptedException {
// throttle rate at 1 MB/sec
try (final LeakyBucketStreamThrottler throttler = new LeakyBucketStreamThrottler(1024 * 1024);
final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
// create 3 threads, each sending ~2 MB
final List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 3; i++) {
final Thread t = new WriterThread(i, throttler, baos);
threads.add(t);
}
final long start = System.currentTimeMillis();
for (final Thread t : threads) {
t.start();
}
for (final Thread t : threads) {
t.join();
}
final long elapsed = System.currentTimeMillis() - start;
throttler.close();
// To send 15 MB, it should have taken at least 5 seconds and no more than 7 seconds, to
// allow for busy-ness and the fact that we could write a tiny bit more than the limit.
assertTrue(elapsed > 5000);
assertTrue(elapsed < 7000);
// ensure bytes were copied out appropriately
assertEquals(3 * (2 * 1024 * 1024 + 1), baos.size());
assertEquals((byte) 'A', baos.toByteArray()[baos.size() - 1]);
}
}
use of org.apache.nifi.stream.io.ByteArrayOutputStream in project nifi by apache.
the class DataTransferResource method commitOutputPortTransaction.
@DELETE
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.APPLICATION_JSON)
@Path("output-ports/{portId}/transactions/{transactionId}")
@ApiOperation(value = "Commit or cancel the specified transaction", response = TransactionResultEntity.class, authorizations = { @Authorization(value = "Write - /data-transfer/output-ports/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful."), @ApiResponse(code = 503, message = "NiFi instance is not ready for serving request, or temporarily overloaded. Retrying the same request later may be successful") })
public Response commitOutputPortTransaction(@ApiParam(value = "The response code. Available values are CONFIRM_TRANSACTION(12) or CANCEL_TRANSACTION(15).", required = true) @QueryParam(RESPONSE_CODE) Integer responseCode, @ApiParam(value = "A checksum calculated at client side using CRC32 to check flow file content integrity. It must match with the value calculated at server side.", required = true) @QueryParam(CHECK_SUM) @DefaultValue(StringUtils.EMPTY) String checksum, @ApiParam(value = "The output port id.", required = true) @PathParam("portId") String portId, @ApiParam(value = "The transaction id.", required = true) @PathParam("transactionId") String transactionId, @Context HttpServletRequest req, @Context ServletContext context, InputStream inputStream) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
authorizeDataTransfer(lookup, ResourceType.OutputPort, portId);
});
final ValidateRequestResult validationResult = validateResult(req, portId, transactionId);
if (validationResult.errResponse != null) {
return validationResult.errResponse;
}
logger.debug("commitOutputPortTransaction request: portId={}, transactionId={}", portId, transactionId);
final int transportProtocolVersion = validationResult.transportProtocolVersion;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Peer peer = constructPeer(req, inputStream, out, portId, transactionId);
final TransactionResultEntity entity = new TransactionResultEntity();
try {
HttpFlowFileServerProtocol serverProtocol = initiateServerProtocol(req, peer, transportProtocolVersion);
String inputErrMessage = null;
if (responseCode == null) {
inputErrMessage = "responseCode is required.";
} else if (ResponseCode.CONFIRM_TRANSACTION.getCode() != responseCode && ResponseCode.CANCEL_TRANSACTION.getCode() != responseCode) {
inputErrMessage = "responseCode " + responseCode + " is invalid. ";
}
if (inputErrMessage != null) {
entity.setMessage(inputErrMessage);
entity.setResponseCode(ResponseCode.ABORT.getCode());
return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
}
if (ResponseCode.CANCEL_TRANSACTION.getCode() == responseCode) {
return cancelTransaction(transactionId, entity);
}
int flowFileSent = serverProtocol.commitTransferTransaction(peer, checksum);
entity.setResponseCode(ResponseCode.CONFIRM_TRANSACTION.getCode());
entity.setFlowFileSent(flowFileSent);
} catch (HandshakeException e) {
return responseCreator.handshakeExceptionResponse(e);
} catch (Exception e) {
HttpServerCommunicationsSession commsSession = (HttpServerCommunicationsSession) peer.getCommunicationsSession();
logger.error("Failed to process the request", e);
if (ResponseCode.BAD_CHECKSUM.equals(commsSession.getResponseCode())) {
entity.setResponseCode(commsSession.getResponseCode().getCode());
entity.setMessage(e.getMessage());
Response.ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST).entity(entity);
return noCache(builder).build();
}
return responseCreator.unexpectedErrorResponse(portId, transactionId, e);
}
return noCache(setCommonHeaders(Response.ok(entity), transportProtocolVersion, transactionManager)).build();
}
use of org.apache.nifi.stream.io.ByteArrayOutputStream in project nifi by apache.
the class DataTransferResource method receiveFlowFiles.
@POST
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.TEXT_PLAIN)
@Path("input-ports/{portId}/transactions/{transactionId}/flow-files")
@ApiOperation(value = "Transfer flow files to the input port", response = String.class, authorizations = { @Authorization(value = "Write - /data-transfer/input-ports/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful."), @ApiResponse(code = 503, message = "NiFi instance is not ready for serving request, or temporarily overloaded. Retrying the same request later may be successful") })
public Response receiveFlowFiles(@ApiParam(value = "The input port id.", required = true) @PathParam("portId") String portId, @PathParam("transactionId") String transactionId, @Context HttpServletRequest req, @Context ServletContext context, InputStream inputStream) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
authorizeDataTransfer(lookup, ResourceType.InputPort, portId);
});
final ValidateRequestResult validationResult = validateResult(req, portId, transactionId);
if (validationResult.errResponse != null) {
return validationResult.errResponse;
}
logger.debug("receiveFlowFiles request: portId={}", portId);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Peer peer = constructPeer(req, inputStream, out, portId, transactionId);
final int transportProtocolVersion = validationResult.transportProtocolVersion;
try {
HttpFlowFileServerProtocol serverProtocol = initiateServerProtocol(req, peer, transportProtocolVersion);
int numOfFlowFiles = serverProtocol.getPort().receiveFlowFiles(peer, serverProtocol);
logger.debug("finished receiving flow files, numOfFlowFiles={}", numOfFlowFiles);
if (numOfFlowFiles < 1) {
return Response.status(Response.Status.BAD_REQUEST).entity("Client should send request when there is data to send. There was no flow file sent.").build();
}
} catch (HandshakeException e) {
return responseCreator.handshakeExceptionResponse(e);
} catch (NotAuthorizedException e) {
return responseCreator.unauthorizedResponse(e);
} catch (BadRequestException | RequestExpiredException e) {
return responseCreator.badRequestResponse(e);
} catch (Exception e) {
return responseCreator.unexpectedErrorResponse(portId, e);
}
String serverChecksum = ((HttpServerCommunicationsSession) peer.getCommunicationsSession()).getChecksum();
return responseCreator.acceptedResponse(transactionManager, serverChecksum, transportProtocolVersion);
}
use of org.apache.nifi.stream.io.ByteArrayOutputStream in project nifi by apache.
the class DataTransferResource method createPortTransaction.
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("{portType}/{portId}/transactions")
@ApiOperation(value = "Create a transaction to the specified output port or input port", response = TransactionResultEntity.class, authorizations = { @Authorization(value = "Write - /data-transfer/{component-type}/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful."), @ApiResponse(code = 503, message = "NiFi instance is not ready for serving request, or temporarily overloaded. Retrying the same request later may be successful") })
public Response createPortTransaction(@ApiParam(value = "The port type.", required = true, allowableValues = "input-ports, output-ports") @PathParam("portType") String portType, @PathParam("portId") String portId, @Context HttpServletRequest req, @Context ServletContext context, @Context UriInfo uriInfo, InputStream inputStream) {
if (!PORT_TYPE_INPUT.equals(portType) && !PORT_TYPE_OUTPUT.equals(portType)) {
return responseCreator.wrongPortTypeResponse(portType, portId);
}
// authorize access
serviceFacade.authorizeAccess(lookup -> {
authorizeDataTransfer(lookup, PORT_TYPE_INPUT.equals(portType) ? ResourceType.InputPort : ResourceType.OutputPort, portId);
});
final ValidateRequestResult validationResult = validateResult(req, portId);
if (validationResult.errResponse != null) {
return validationResult.errResponse;
}
logger.debug("createPortTransaction request: clientId={}, portType={}, portId={}", portType, portId);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final String transactionId = transactionManager.createTransaction();
final Peer peer = constructPeer(req, inputStream, out, portId, transactionId);
final int transportProtocolVersion = validationResult.transportProtocolVersion;
try {
// Execute handshake.
initiateServerProtocol(req, peer, transportProtocolVersion);
TransactionResultEntity entity = new TransactionResultEntity();
entity.setResponseCode(ResponseCode.PROPERTIES_OK.getCode());
entity.setMessage("Handshake properties are valid, and port is running. A transaction is created:" + transactionId);
return responseCreator.locationResponse(uriInfo, portType, portId, transactionId, entity, transportProtocolVersion, transactionManager);
} catch (HandshakeException e) {
transactionManager.cancelTransaction(transactionId);
return responseCreator.handshakeExceptionResponse(e);
} catch (Exception e) {
transactionManager.cancelTransaction(transactionId);
return responseCreator.unexpectedErrorResponse(portId, e);
}
}
use of org.apache.nifi.stream.io.ByteArrayOutputStream in project nifi by apache.
the class DataTransferResource method commitInputPortTransaction.
@DELETE
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.APPLICATION_JSON)
@Path("input-ports/{portId}/transactions/{transactionId}")
@ApiOperation(value = "Commit or cancel the specified transaction", response = TransactionResultEntity.class, authorizations = { @Authorization(value = "Write - /data-transfer/input-ports/{uuid}") })
@ApiResponses(value = { @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), @ApiResponse(code = 401, message = "Client could not be authenticated."), @ApiResponse(code = 403, message = "Client is not authorized to make this request."), @ApiResponse(code = 404, message = "The specified resource could not be found."), @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful."), @ApiResponse(code = 503, message = "NiFi instance is not ready for serving request, or temporarily overloaded. Retrying the same request later may be successful") })
public Response commitInputPortTransaction(@ApiParam(value = "The response code. Available values are BAD_CHECKSUM(19), CONFIRM_TRANSACTION(12) or CANCEL_TRANSACTION(15).", required = true) @QueryParam(RESPONSE_CODE) Integer responseCode, @ApiParam(value = "The input port id.", required = true) @PathParam("portId") String portId, @ApiParam(value = "The transaction id.", required = true) @PathParam("transactionId") String transactionId, @Context HttpServletRequest req, @Context ServletContext context, InputStream inputStream) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
authorizeDataTransfer(lookup, ResourceType.InputPort, portId);
});
final ValidateRequestResult validationResult = validateResult(req, portId, transactionId);
if (validationResult.errResponse != null) {
return validationResult.errResponse;
}
logger.debug("commitInputPortTransaction request: portId={}, transactionId={}, responseCode={}", portId, transactionId, responseCode);
final int transportProtocolVersion = validationResult.transportProtocolVersion;
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Peer peer = constructPeer(req, inputStream, out, portId, transactionId);
final TransactionResultEntity entity = new TransactionResultEntity();
try {
HttpFlowFileServerProtocol serverProtocol = initiateServerProtocol(req, peer, transportProtocolVersion);
HttpServerCommunicationsSession commsSession = (HttpServerCommunicationsSession) peer.getCommunicationsSession();
// Pass the response code sent from the client.
String inputErrMessage = null;
if (responseCode == null) {
inputErrMessage = "responseCode is required.";
} else if (ResponseCode.BAD_CHECKSUM.getCode() != responseCode && ResponseCode.CONFIRM_TRANSACTION.getCode() != responseCode && ResponseCode.CANCEL_TRANSACTION.getCode() != responseCode) {
inputErrMessage = "responseCode " + responseCode + " is invalid. ";
}
if (inputErrMessage != null) {
entity.setMessage(inputErrMessage);
entity.setResponseCode(ResponseCode.ABORT.getCode());
return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
}
if (ResponseCode.CANCEL_TRANSACTION.getCode() == responseCode) {
return cancelTransaction(transactionId, entity);
}
commsSession.setResponseCode(ResponseCode.fromCode(responseCode));
try {
int flowFileSent = serverProtocol.commitReceiveTransaction(peer);
entity.setResponseCode(commsSession.getResponseCode().getCode());
entity.setFlowFileSent(flowFileSent);
} catch (IOException e) {
if (ResponseCode.BAD_CHECKSUM.getCode() == responseCode && e.getMessage().contains("Received a BadChecksum response")) {
// AbstractFlowFileServerProtocol throws IOException after it canceled transaction.
// This is a known behavior and if we return 500 with this exception,
// it's not clear if there is an issue at server side, or cancel operation has been accomplished.
// Above conditions can guarantee this is the latter case, we return 200 OK here.
entity.setResponseCode(ResponseCode.CANCEL_TRANSACTION.getCode());
return noCache(Response.ok(entity)).build();
} else {
return responseCreator.unexpectedErrorResponse(portId, transactionId, e);
}
}
} catch (HandshakeException e) {
return responseCreator.handshakeExceptionResponse(e);
} catch (Exception e) {
return responseCreator.unexpectedErrorResponse(portId, transactionId, e);
}
return noCache(setCommonHeaders(Response.ok(entity), transportProtocolVersion, transactionManager)).build();
}
Aggregations