diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java index d8d8b7e474..c0e054bcb2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/YamlMapFactoryBean.java @@ -108,15 +108,14 @@ public class YamlMapFactoryBean extends YamlProcessor implements FactoryBeanInvoked lazily the first time {@link #getObject()} is invoked in * case of a shared singleton; else, on each {@link #getObject()} call. + *

The default implementation returns the merged {@code Map} instance. * @return the object returned by this factory * @see #process(java.util.Map, MatchCallback) */ protected Map createMap() { - Map result = new LinkedHashMap<>(); process((properties, map) -> merge(result, map)); return result; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java index 569afaf840..fac9ad90ca 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/BufferingStompDecoder.java @@ -16,7 +16,6 @@ package org.springframework.messaging.simp.stomp; - import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; @@ -28,7 +27,6 @@ import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; - /** * An extension of {@link org.springframework.messaging.simp.stomp.StompDecoder} * that buffers content remaining in the input ByteBuffer after the parent @@ -45,6 +43,7 @@ import org.springframework.util.MultiValueMap; * * @author Rossen Stoyanchev * @since 4.0.3 + * @see StompDecoder */ public class BufferingStompDecoder { @@ -52,34 +51,104 @@ public class BufferingStompDecoder { private final int bufferSizeLimit; - private final Queue chunks = new LinkedBlockingQueue<>(); + private final Queue chunks = new LinkedBlockingQueue(); private volatile Integer expectedContentLength; + /** + * Create a new {@code BufferingStompDecoder} wrapping the given {@code StompDecoder}. + * @param stompDecoder the target decoder to wrap + * @param bufferSizeLimit the buffer size limit + */ public BufferingStompDecoder(StompDecoder stompDecoder, int bufferSizeLimit) { - Assert.notNull(stompDecoder, "'stompDecoder' is required"); - Assert.isTrue(bufferSizeLimit > 0, "Buffer size must be greater than 0"); + Assert.notNull(stompDecoder, "StompDecoder is required"); + Assert.isTrue(bufferSizeLimit > 0, "Buffer size limit must be greater than 0"); this.stompDecoder = stompDecoder; this.bufferSizeLimit = bufferSizeLimit; } /** - * Return the wrapped - * {@link org.springframework.messaging.simp.stomp.StompDecoder}. + * Return the wrapped {@link StompDecoder}. */ - public StompDecoder getStompDecoder() { + public final StompDecoder getStompDecoder() { return this.stompDecoder; } /** * Return the configured buffer size limit. */ - public int getBufferSizeLimit() { + public final int getBufferSizeLimit() { return this.bufferSizeLimit; } + + /** + * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a + * list of {@link Message}s. + *

If there was enough data to parse a "content-length" header, then the + * value is used to determine how much more data is needed before a new + * attempt to decode is made. + *

If there was not enough data to parse the "content-length", or if there + * is "content-length" header, every subsequent call to decode attempts to + * parse again with all available data. Therefore the presence of a "content-length" + * header helps to optimize the decoding of large messages. + * @param newBuffer a buffer containing new data to decode + * @return decoded messages or an empty list + * @throws StompConversionException raised in case of decoding issues + */ + public List> decode(ByteBuffer newBuffer) { + this.chunks.add(newBuffer); + checkBufferLimits(); + + if (this.expectedContentLength != null && getBufferSize() < this.expectedContentLength) { + return Collections.emptyList(); + } + + ByteBuffer bufferToDecode = assembleChunksAndReset(); + MultiValueMap headers = new LinkedMultiValueMap(); + List> messages = this.stompDecoder.decode(bufferToDecode, headers); + + if (bufferToDecode.hasRemaining()) { + this.chunks.add(bufferToDecode); + this.expectedContentLength = StompHeaderAccessor.getContentLength(headers); + } + + return messages; + } + + private ByteBuffer assembleChunksAndReset() { + ByteBuffer result; + if (this.chunks.size() == 1) { + result = this.chunks.remove(); + } + else { + result = ByteBuffer.allocate(getBufferSize()); + for (ByteBuffer partial : this.chunks) { + result.put(partial); + } + result.flip(); + } + this.chunks.clear(); + this.expectedContentLength = null; + return result; + } + + private void checkBufferLimits() { + if (this.expectedContentLength != null) { + if (this.expectedContentLength > this.bufferSizeLimit) { + throw new StompConversionException( + "STOMP 'content-length' header value " + this.expectedContentLength + + " exceeds configured buffer size limit " + this.bufferSizeLimit); + } + } + if (getBufferSize() > this.bufferSizeLimit) { + throw new StompConversionException("The configured STOMP buffer size limit of " + + this.bufferSizeLimit + " bytes has been exceeded"); + } + } + /** * Calculate the current buffer size. */ @@ -98,78 +167,4 @@ public class BufferingStompDecoder { return this.expectedContentLength; } - - /** - * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a - * list of {@link Message}s. - * - *

If there was enough data to parse a "content-length" header, then the - * value is used to determine how much more data is needed before a new - * attempt to decode is made. - * - *

If there was not enough data to parse the "content-length", or if there - * is "content-length" header, every subsequent call to decode attempts to - * parse again with all available data. Therefore the presence of a "content-length" - * header helps to optimize the decoding of large messages. - * - * @param newBuffer a buffer containing new data to decode - * - * @return decoded messages or an empty list - * @throws StompConversionException raised in case of decoding issues - */ - public List> decode(ByteBuffer newBuffer) { - - this.chunks.add(newBuffer); - - checkBufferLimits(); - - if (getExpectedContentLength() != null && getBufferSize() < this.expectedContentLength) { - return Collections.>emptyList(); - } - - ByteBuffer bufferToDecode = assembleChunksAndReset(); - - MultiValueMap headers = new LinkedMultiValueMap<>(); - List> messages = this.stompDecoder.decode(bufferToDecode, headers); - - if (bufferToDecode.hasRemaining()) { - this.chunks.add(bufferToDecode); - this.expectedContentLength = StompHeaderAccessor.getContentLength(headers); - } - - return messages; - } - - private void checkBufferLimits() { - if (getExpectedContentLength() != null) { - if (getExpectedContentLength() > getBufferSizeLimit()) { - throw new StompConversionException( - "The 'content-length' header " + getExpectedContentLength() + - " exceeds the configured message buffer size limit " + getBufferSizeLimit()); - } - } - if (getBufferSize() > getBufferSizeLimit()) { - throw new StompConversionException("The configured stomp frame buffer size limit of " + - getBufferSizeLimit() + " bytes has been exceeded"); - - } - } - - private ByteBuffer assembleChunksAndReset() { - ByteBuffer result; - if (this.chunks.size() == 1) { - result = this.chunks.remove(); - } - else { - result = ByteBuffer.allocate(getBufferSize()); - for (ByteBuffer partial : this.chunks) { - result.put(partial); - } - result.flip(); - } - this.chunks.clear(); - this.expectedContentLength = null; - return result; - } - } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompEncoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompEncoder.java index 4939b506ab..67e2088636 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompEncoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,8 +40,9 @@ import org.springframework.util.Assert; * @author Andy Wilkinson * @author Rossen Stoyanchev * @since 4.0 + * @see StompDecoder */ -public final class StompEncoder { +public class StompEncoder { private static final byte LF = '\n';