Refine search
/** * Relay buffers from the given {@link Publisher} until the total * {@linkplain DataBuffer#readableByteCount() byte count} reaches * the given maximum byte count, or until the publisher is complete. * @param publisher the publisher to filter * @param maxByteCount the maximum byte count * @return a flux whose maximum byte count is {@code maxByteCount} */ public static Flux<DataBuffer> takeUntilByteCount(Publisher<DataBuffer> publisher, long maxByteCount) { Assert.notNull(publisher, "Publisher must not be null"); Assert.isTrue(maxByteCount >= 0, "'maxByteCount' must be a positive number"); return Flux.defer(() -> { AtomicLong countDown = new AtomicLong(maxByteCount); return Flux.from(publisher) .map(buffer -> { long remainder = countDown.addAndGet(-buffer.readableByteCount()); if (remainder < 0) { int length = buffer.readableByteCount() + (int) remainder; return buffer.slice(0, length); } else { return buffer; } }) .takeUntil(buffer -> countDown.get() <= 0); }); // no doOnDiscard necessary, as this method does not drop buffers }
@Override protected byte[] decodeDataBuffer(DataBuffer dataBuffer, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { byte[] result = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(result); DataBufferUtils.release(dataBuffer); if (logger.isDebugEnabled()) { logger.debug(Hints.getLogPrefix(hints) + "Read " + result.length + " bytes"); } return result; }
private Flux<DataBuffer> getRegionPrefix(DataBufferFactory bufferFactory, byte[] startBoundary, byte[] contentType, ResourceRegion region) { return Flux.defer(() -> Flux.just( bufferFactory.allocateBuffer(startBoundary.length).write(startBoundary), bufferFactory.allocateBuffer(contentType.length).write(contentType), bufferFactory.wrap(ByteBuffer.wrap(getContentRangeHeader(region)))) ); }
private static String bufferToString(DataBuffer buffer, Charset charset) { byte[] bytes = new byte[buffer.readableByteCount()]; buffer.read(bytes); return new String(bytes, charset); }
/** * Find the given delimiter in the given data buffer. * @return the index of the delimiter, or -1 if not found. */ private static int indexOf(DataBuffer dataBuffer, byte[] delimiter) { for (int i = dataBuffer.readPosition(); i < dataBuffer.writePosition(); i++) { int dataBufferPos = i; int delimiterPos = 0; while (delimiterPos < delimiter.length) { if (dataBuffer.getByte(dataBufferPos) != delimiter[delimiterPos]) { break; } else { dataBufferPos++; if (dataBufferPos == dataBuffer.writePosition() && delimiterPos != delimiter.length - 1) { return -1; } } delimiterPos++; } if (delimiterPos == delimiter.length) { return i - dataBuffer.readPosition(); } } return -1; }
/** * Return the response body aggregated and converted to a String using the * charset of the Content-Type response or otherwise as "UTF-8". */ public Mono<String> getBodyAsString() { Charset charset = getCharset(); return Flux.from(getBody()) .reduce(this.bufferFactory.allocateBuffer(), (previous, current) -> { previous.write(current); DataBufferUtils.release(current); return previous; }) .map(buffer -> dumpString(buffer, charset)); }
@Override @SuppressWarnings({"rawtypes", "unchecked"}) // on JDK 9 where XMLEventReader is Iterator<Object> public Flux<XMLEvent> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { Flux<DataBuffer> flux = Flux.from(inputStream); if (this.useAalto) { AaltoDataBufferToXmlEvent aaltoMapper = new AaltoDataBufferToXmlEvent(); return flux.flatMap(aaltoMapper) .doFinally(signalType -> aaltoMapper.endOfInput()); } else { Mono<DataBuffer> singleBuffer = DataBufferUtils.join(flux); return singleBuffer. flatMapMany(dataBuffer -> { try { InputStream is = dataBuffer.asInputStream(); Iterator eventReader = inputFactory.createXMLEventReader(is); return Flux.fromIterable((Iterable<XMLEvent>) () -> eventReader) .doFinally(t -> DataBufferUtils.release(dataBuffer)); } catch (XMLStreamException ex) { return Mono.error(ex); } }); } }
Assert.isTrue(maxByteCount >= 0, "'maxByteCount' must be a positive number"); return Flux.defer(() -> { AtomicLong countDown = new AtomicLong(maxByteCount); return Flux.from(publisher) .skipUntil(buffer -> { long remainder = countDown.addAndGet(-buffer.readableByteCount()); return remainder < 0; }) if (remainder < 0) { countDown.set(0); int start = buffer.readableByteCount() + (int)remainder; int length = (int) -remainder; return buffer.slice(start, length);
@Test public void decodeSplitChunks() { Flux<DataBuffer> input = Flux.just(this.testMsg1, this.testMsg2) .flatMap(msg -> Mono.defer(() -> { DataBuffer buffer = this.bufferFactory.allocateBuffer(); try { msg.writeDelimitedTo(buffer.asOutputStream()); return Mono.just(buffer); } catch (IOException e) { release(buffer); return Mono.error(e); } })) .flatMap(buffer -> { int len = buffer.readableByteCount() / 2; Flux<DataBuffer> result = Flux.just( DataBufferUtils.retain(buffer.slice(0, len)), DataBufferUtils .retain(buffer.slice(len, buffer.readableByteCount() - len)) ); release(buffer); return result; }); testDecode(input, Msg.class, step -> step .expectNext(this.testMsg1) .expectNext(this.testMsg2) .verifyComplete()); }
@Override public Flux<DataBuffer> encode(Publisher<? extends byte[]> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { return Flux.from(inputStream).map(bytes -> { DataBuffer dataBuffer = bufferFactory.wrap(bytes); if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) { String logPrefix = Hints.getLogPrefix(hints); logger.debug(logPrefix + "Writing " + dataBuffer.readableByteCount() + " bytes"); } return dataBuffer; }); }
DataBuffer buffer = dataBufferFactory.allocateBuffer(1024); OutputStream outputStream = buffer.asOutputStream(); Class<?> clazz = ClassUtils.getUserClass(value); marshaller.marshal(value, outputStream); release = false; return Flux.just(buffer); return Flux.error(new EncodingException( "Could not marshal " + value.getClass() + " to XML", ex)); return Flux.error(new CodecException("Invalid JAXB configuration", ex)); DataBufferUtils.release(buffer);
@Override @Test public void decode() { Flux<DataBuffer> input = Flux.just(this.testMsg1, this.testMsg2) .flatMap(msg -> Mono.defer(() -> { DataBuffer buffer = this.bufferFactory.allocateBuffer(); try { msg.writeDelimitedTo(buffer.asOutputStream()); return Mono.just(buffer); } catch (IOException e) { release(buffer); return Mono.error(e); } })); testDecodeAll(input, Msg.class, step -> step .expectNext(this.testMsg1) .expectNext(this.testMsg2) .verifyComplete()); }
@Override public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) { return response.writeWith(Flux.just("h", "e", "l", "l", "o") .delayElements(Duration.ofMillis(100)) .publishOn(asyncGroup) .collect(dataBufferFactory::allocateBuffer, (buffer, str) -> buffer.write(str.getBytes()))); } }
/** * Apply {@link Flux#reduce(Object, BiFunction) reduce} on the body, count * the number of bytes produced, release data buffers without writing, and * set the {@literal Content-Length} header. */ @Override public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { return Flux.from(body) .reduce(0, (current, buffer) -> { int next = current + buffer.readableByteCount(); DataBufferUtils.release(buffer); return next; }) .doOnNext(count -> getHeaders().setContentLength(count)) .then(); }
@Override public Flux<DataBuffer> content() { byte[] bytes = this.content.getBytes(getCharset()); DataBuffer buffer = getBufferFactory().allocateBuffer(bytes.length); buffer.write(bytes); return Flux.just(buffer); }
@Test public void writeWith() throws Exception { TestServerHttpResponse response = new TestServerHttpResponse(); response.writeWith(Flux.just(wrap("a"), wrap("b"), wrap("c"))).block(); assertTrue(response.statusCodeWritten); assertTrue(response.headersWritten); assertTrue(response.cookiesWritten); assertEquals(3, response.body.size()); assertEquals("a", new String(response.body.get(0).asByteBuffer().array(), StandardCharsets.UTF_8)); assertEquals("b", new String(response.body.get(1).asByteBuffer().array(), StandardCharsets.UTF_8)); assertEquals("c", new String(response.body.get(2).asByteBuffer().array(), StandardCharsets.UTF_8)); }
@Override public Publisher<? extends XMLEvent> apply(DataBuffer dataBuffer) { try { this.streamReader.getInputFeeder().feedInput(dataBuffer.asByteBuffer()); List<XMLEvent> events = new ArrayList<>(); while (true) { if (this.streamReader.next() == AsyncXMLStreamReader.EVENT_INCOMPLETE) { // no more events with what currently has been fed to the reader break; } else { XMLEvent event = this.eventAllocator.allocate(this.streamReader); events.add(event); if (event.isEndDocument()) { break; } } } return Flux.fromIterable(events); } catch (XMLStreamException ex) { return Mono.error(ex); } finally { DataBufferUtils.release(dataBuffer); } }
private Flux<TokenBuffer> tokenize(DataBuffer dataBuffer) { byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); try { this.inputFeeder.feedInput(bytes, 0, bytes.length); return parseTokenBufferFlux(); } catch (JsonProcessingException ex) { return Flux.error(new DecodingException( "JSON decoding error: " + ex.getOriginalMessage(), ex)); } catch (IOException ex) { return Flux.error(ex); } }
private Flux<DataBuffer> toDataBuffers(String s, int length, Charset charset) { byte[] bytes = s.getBytes(charset); List<DataBuffer> dataBuffers = new ArrayList<>(); for (int i = 0; i < bytes.length; i += length) { DataBuffer dataBuffer = this.bufferFactory.allocateBuffer(length); dataBuffer.write(bytes, i, length); dataBuffers.add(dataBuffer); } return Flux.fromIterable(dataBuffers); }
@Override public Mono<String> getResourceVersion(Resource resource) { Flux<DataBuffer> flux = DataBufferUtils.read(resource, dataBufferFactory, StreamUtils.BUFFER_SIZE); return DataBufferUtils.join(flux) .map(buffer -> { byte[] result = new byte[buffer.readableByteCount()]; buffer.read(result); DataBufferUtils.release(buffer); return DigestUtils.md5DigestAsHex(result); }); }