From 836708f0f258e87694e53e008eb99399f7e773af Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Fri, 29 Dec 2023 21:08:58 -0600 Subject: [PATCH] GH-7: Add checkstyle and javaformat plugins Fixes: #7 * Run `./gradlew format` * Updates from PR review suggestions --- build.gradle | 6 +- .../common/aws/s3/AmazonS3Configuration.java | 2 +- .../aws/s3/AmazonS3ConfigurationTests.java | 25 +- .../fn/common/config/ComponentCustomizer.java | 6 +- .../SpelExpressionConverterConfiguration.java | 8 +- ...ebeziumEngineBuilderAutoConfiguration.java | 96 ++-- .../common/debezium/DebeziumProperties.java | 23 +- .../EmbeddedEngineExecutorService.java | 17 +- ...ilderAutoConfigurationIntegrationTest.java | 121 ++-- ...umEngineBuilderAutoConfigurationTests.java | 10 +- .../common/file/FileConsumerProperties.java | 18 +- .../cloud/fn/common/file/FileReadingMode.java | 2 + .../cloud/fn/common/file/FileUtils.java | 36 +- .../file/remote/RemoteFileDeletingAdvice.java | 4 +- .../file/remote/RemoteFileRenamingAdvice.java | 6 +- .../ftp/FtpSessionFactoryProperties.java | 1 + .../file/remote/RemoteFileTestSupport.java | 12 +- .../fn/test/support/ftp/FtpTestSupport.java | 5 +- .../fn/test/support/sftp/SftpTestSupport.java | 13 +- .../WebsocketConsumerClientHandler.java | 1 + .../xmpp/XmppTestContainerSupport.java | 3 +- .../store/MetadataStoreAutoConfiguration.java | 2 +- .../store/MetadataStoreProperties.java | 15 +- .../MetadataStoreAutoConfigurationTests.java | 55 +- .../common/tcp/EncoderDecoderFactoryBean.java | 3 +- .../cloud/fn/common/tcp/Encoding.java | 2 + .../tcp/TcpConnectionFactoryProperties.java | 5 +- .../tensorflow/AbstractGraphRunner.java | 22 +- .../tensorflow/AutoCloseableSession.java | 1 + .../cloud/fn/common/tensorflow/Functions.java | 41 +- .../fn/common/tensorflow/GraphDefinition.java | 2 + .../fn/common/tensorflow/GraphRunner.java | 12 +- .../common/tensorflow/GraphRunnerMemory.java | 5 +- .../tensorflow/ProtoBufGraphDefinition.java | 13 +- .../tensorflow/deprecated/GraphicsUtils.java | 251 ++++++--- .../deprecated/JsonMapperFunction.java | 1 + .../deprecated/TensorFlowService.java | 17 +- .../tensorflow/util/AutoCloseables.java | 36 +- .../tensorflow/util/CachedModelExtractor.java | 9 +- .../tensorflow/util/ModelExtractor.java | 73 +-- .../common/tensorflow/EnrichFromMemory.java | 52 +- .../tensorflow/FunctionComposition.java | 18 +- ...ctionCompositionMultipleInputsOutputs.java | 36 +- .../tensorflow/ReleaseTensorParameters.java | 30 +- .../cloud/fn/common/twitter/Cursor.java | 2 + .../TwitterConnectionConfiguration.java | 32 +- .../twitter/TwitterConnectionProperties.java | 6 +- .../common/twitter/util/TwitterTestUtils.java | 7 +- .../XmppConnectionFactoryConfiguration.java | 10 +- .../xmpp/XmppConnectionFactoryProperties.java | 8 +- .../AnalyticsConsumerConfiguration.java | 107 ++-- .../AnalyticsConsumerProperties.java | 62 ++- .../AnalyticsConsumerParentTest.java | 2 + .../analytics/CountWithAmountTest.java | 8 +- .../fn/consumer/analytics/EmptyTagsTests.java | 11 +- .../analytics/ExpressionCounterNameTests.java | 5 +- .../fn/consumer/analytics/FixedTagsTests.java | 13 +- .../analytics/GaugeWithAmountTest.java | 8 +- .../analytics/LiteralTagExpressionsTests.java | 7 +- .../fn/consumer/analytics/NullTagsTests.java | 14 +- .../StockExchangeAnalyticsTests.java | 24 +- .../demo/StockExchangeAnalyticsExample.java | 46 +- .../CassandraConsumerConfiguration.java | 47 +- .../CassandraAppClusterConfiguration.java | 62 +-- .../cluster/CassandraClusterProperties.java | 3 +- .../cluster/TrustAllSSLContextFactory.java | 31 +- .../CassandraConsumerApplicationTests.java | 18 +- .../cassandra/CassandraContainerTest.java | 11 +- .../cassandra/CassandraEntityInsertTests.java | 22 +- .../cassandra/CassandraIngestInsertTests.java | 18 +- .../CassandraIngestNamedParamsTests.java | 20 +- .../cassandra/CassandraIngestUpdateTests.java | 20 +- .../fn/consumer/cassandra/domain/Book.java | 7 +- .../ElasticsearchConsumerConfiguration.java | 81 +-- .../ElasticsearchConsumerProperties.java | 30 +- ...ElasticsearchConsumerApplicationTests.java | 113 ++-- .../file/FileConsumerConfiguration.java | 3 +- .../consumer/file/FileConsumerProperties.java | 4 +- .../file/AbstractFileConsumerTests.java | 2 + .../fn/consumer/file/ExpressionTests.java | 12 +- .../cloud/fn/consumer/file/TextFileTests.java | 4 +- .../ftp/FtpConsumerConfiguration.java | 20 +- .../consumer/ftp/FtpConsumerProperties.java | 1 + .../ftp/FtpConsumerPropertiesTests.java | 22 +- .../fn/consumer/ftp/FtpConsumerTests.java | 11 +- .../DefaultInitializationScriptResource.java | 4 +- .../jdbc/JdbcConsumerConfiguration.java | 41 +- .../consumer/jdbc/JdbcConsumerProperties.java | 5 +- .../consumer/jdbc/ShorthandMapConverter.java | 16 +- .../jdbc/BatchInsertTimeoutTests.java | 7 +- .../jdbc/DataReceivedAsByteArrayTests.java | 4 +- .../jdbc/ExplicitTableCreationTests.java | 10 +- .../fn/consumer/jdbc/HeaderInsertTests.java | 8 +- .../jdbc/ImplicitTableCreationTests.java | 10 +- .../jdbc/JdbcConsumerApplicationTests.java | 1 + .../jdbc/JsonStringPayloadInsertTests.java | 18 +- .../consumer/jdbc/MapPayloadInsertTests.java | 15 +- .../fn/consumer/jdbc/SimpleMappingTests.java | 4 +- .../cloud/fn/consumer/jdbc/SpELTests.java | 4 +- .../UnqualifiableColumnExpressionTests.java | 8 +- .../fn/consumer/jdbc/VaryingInsertTests.java | 4 +- .../kafka/KafkaPublisherConfiguration.java | 36 +- .../kafka/KafkaPublisherProperties.java | 7 +- .../KafkaPublisherConfigurationTests.java | 135 +++-- .../log/LogConsumerConfiguration.java | 14 +- .../log/LogConsumerApplicationTests.java | 23 +- .../mongo/MongoDbConsumerProperties.java | 2 + .../MongoDbConsumerApplicationTests.java | 37 +- .../mongo/MongoDbTestContainerSupport.java | 4 +- .../consumer/mqtt/MqttConsumerProperties.java | 1 + .../fn/consumer/mqtt/MqttConsumerTests.java | 21 +- .../rabbit/RabbitConsumerConfiguration.java | 38 +- .../rabbit/RabbitConsumerProperties.java | 10 +- .../redis/RedisConsumerProperties.java | 6 +- .../redis/AbstractRedisConsumerTests.java | 1 + .../consumer/redis/RedisConsumerKeyTests.java | 9 +- .../redis/RedisConsumerQueueTests.java | 1 + .../redis/RedisConsumerTopicTests.java | 2 + .../redis/RedisTestContainerSupport.java | 5 +- .../rsocket/RsocketConsumerConfiguration.java | 17 +- .../rsocket/RsocketConsumerProperties.java | 1 + .../rsocket/RsocketConsumerTests.java | 33 +- .../s3/AwsS3ConsumerConfiguration.java | 28 +- .../consumer/s3/AwsS3ConsumerProperties.java | 5 +- .../s3/AbstractAwsS3ConsumerMockTests.java | 15 +- .../consumer/s3/AmazonS3UploadFileTests.java | 25 +- .../s3/AmazonS3UploadInputStreamTests.java | 27 +- .../sftp/SftpConsumerConfiguration.java | 25 +- .../consumer/sftp/SftpConsumerProperties.java | 5 +- ...tpConsumerSessionFactoryConfiguration.java | 6 +- .../sftp/SftpConsumerPropertiesTests.java | 15 +- .../fn/consumer/sftp/SftpConsumerTests.java | 13 +- .../tcp/TcpConsumerConfiguration.java | 10 +- .../consumer/tcp/TcpConsumerProperties.java | 1 + .../tcp/AbstractTcpConsumerTests.java | 11 +- .../cloud/fn/consumer/tcp/CRLFTests.java | 2 +- .../cloud/fn/consumer/tcp/L1Tests.java | 3 +- .../cloud/fn/consumer/tcp/L2Tests.java | 3 +- .../cloud/fn/consumer/tcp/L4Tests.java | 3 +- .../cloud/fn/consumer/tcp/LFTests.java | 3 +- .../cloud/fn/consumer/tcp/NULLTests.java | 3 +- .../cloud/fn/consumer/tcp/NotNioTests.java | 3 +- .../tcp/PropertiesPopulatedTests.java | 6 +- .../cloud/fn/consumer/tcp/RAWTests.java | 3 +- .../cloud/fn/consumer/tcp/STXETXTests.java | 1 + ...itterFriendshipsConsumerConfiguration.java | 61 +- .../TwitterFriendshipsConsumerProperties.java | 8 +- .../TwitterMessageConsumerConfiguration.java | 5 +- .../TwitterMessageConsumerProperties.java | 5 +- .../TwitterUpdateConsumerConfiguration.java | 6 +- .../TwitterUpdateConsumerProperties.java | 60 +- ...rUpdateSinkFunctionConfigurationTests.java | 8 +- .../WavefrontConsumerConfiguration.java | 1 + .../WavefrontConsumerProperties.java | 18 +- .../consumer/wavefront/WavefrontFormat.java | 70 +-- .../DirectConnectionWavefrontService.java | 3 + .../ProxyConnectionWavefrontService.java | 2 + .../wavefront/service/WavefrontService.java | 2 + .../WavefrontConsumerConfigurationTest.java | 18 +- .../WavefrontConsumerPropertiesTest.java | 17 +- .../wavefront/WavefrontFormatTest.java | 86 +-- .../DirectConnectionWavefrontServiceTest.java | 9 +- .../ProxyConnectionWavefrontServiceTest.java | 8 +- .../WavefrontServiceConditionTest.java | 84 ++- .../WebsocketConsumerConfiguration.java | 8 +- .../WebsocketConsumerProperties.java | 7 +- .../websocket/WebsocketConsumerServer.java | 21 +- .../WebsocketConsumerServerHandler.java | 15 +- .../WebsocketConsumerServerInitializer.java | 7 +- .../WebsocketConsumerTraceEndpoint.java | 4 +- .../trace/InMemoryTraceRepository.java | 6 +- .../fn/consumer/websocket/trace/Trace.java | 7 +- .../websocket/WebsocketConsumerTests.java | 22 +- .../xmpp/XmppConsumerConfiguration.java | 11 +- .../consumer/xmpp/XmppConsumerProperties.java | 1 - .../xmpp/XmppConsumerConfigurationTests.java | 71 ++- .../zeromq/ZeroMqConsumerConfiguration.java | 4 +- .../zeromq/ZeroMqConsumerProperties.java | 1 - .../ZeroMqConsumerConfigurationTests.java | 18 +- etc/checkstyle/checkstyle-header.txt | 17 + etc/checkstyle/checkstyle-suppressions.xml | 9 + etc/checkstyle/checkstyle.xml | 27 + .../AggregatorFunctionConfiguration.java | 33 +- .../AggregatorFunctionProperties.java | 3 +- ...ConfigurationEnvironmentPostProcessor.java | 21 +- .../aggregator/MessageStoreConfiguration.java | 27 +- .../AbstractAggregatorFunctionTests.java | 2 + ...psAndMongoMessageStoreAggregatorTests.java | 30 +- .../fn/aggregator/DefaultAggregatorTests.java | 20 +- .../JdbcMessageStoreAggregatorTests.java | 38 +- .../RedisMessageStoreAggregatorTests.java | 19 +- .../filter/FilterFunctionConfiguration.java | 4 +- .../FilterFunctionApplicationTests.java | 10 +- .../HeaderEnricherFunctionConfiguration.java | 4 +- .../HeaderEnricherFunctionProperties.java | 4 +- ...eaderEnricherFunctionApplicationTests.java | 7 +- .../HeaderFilterFunctionConfiguration.java | 4 +- .../HeaderFilterFunctionProperties.java | 7 +- ...lterFunctionApplicationDeleteAllTests.java | 11 +- .../HeaderFilterFunctionApplicationTests.java | 11 +- .../cloud/fn/header/filter/HeaderUtils.java | 2 + .../HttpRequestFunctionConfiguration.java | 14 +- ...tpRequestFunctionTestApplicationTests.java | 159 +++--- .../image/recognition/ImageRecognition.java | 191 ++++--- .../ImageRecognitionAugmenter.java | 3 +- .../recognition/RecognitionResponse.java | 3 + .../util/ImageNetReadableNamesWriter.java | 52 +- .../recognition/ImageRecognitionExample.java | 47 +- .../recognition/ImageRecognitionExample2.java | 22 +- .../fn/image/recognition/SavedModelTest.java | 22 +- .../ObjectDetectionImageAugmenter.java | 9 +- .../ObjectDetectionInputAdapter.java | 19 +- .../ObjectDetectionInputConverter.java | 5 +- .../ObjectDetectionOutputConverter.java | 63 ++- .../detection/ObjectDetectionService.java | 102 ++-- .../detection/ObjectDetectionService2.java | 48 +- .../detection/domain/ObjectDetection.java | 20 +- .../examples/ExampleInstanceSegmentation.java | 39 +- .../examples/ExampleObjectDetection.java | 44 +- .../detection/examples/SimpleExample.java | 27 +- .../java/functions/ByteArrayTextToString.java | 13 +- .../main/java/functions/JsonBytesToMap.java | 17 +- .../functions/ByteArrayTextToStringTests.java | 1 + .../segmentation/NativeImageUtils.java | 45 +- .../segmentation/SegmentationColorMap.java | 319 ++--------- .../segmentation/SemanticSegmentation.java | 224 +++++--- .../attic/SemanticSegmentationUtils.java | 56 +- .../fn/spel/SpelFunctionConfiguration.java | 4 +- .../fn/spel/SpelFunctionApplicationTests.java | 4 +- .../SplitterFunctionConfiguration.java | 5 +- .../splitter/SplitterFunctionProperties.java | 21 +- .../SplitterFunctionApplicationTests.java | 2 + .../CommandLineArgumentsMessageMapper.java | 1 + .../launch/request/KeyValueListParser.java | 4 +- .../launch/request/TaskLaunchRequest.java | 2 + ...askLaunchRequestFunctionConfiguration.java | 55 +- .../TaskLaunchRequestFunctionProperties.java | 4 +- .../TaskLaunchRequestMessageProcessor.java | 3 +- .../request/TaskLaunchRequestSupplier.java | 1 + .../launch/request/TaskNameMessageMapper.java | 1 + .../request/KeyValueListParserTests.java | 20 +- ...LaunchRequestFunctionApplicationTests.java | 75 ++- ...kLaunchRequestFunctionPropertiesTests.java | 1 + .../geo/TwitterGeoFunctionConfiguration.java | 8 +- .../geo/TwitterGeoFunctionProperties.java | 33 +- .../TwitterTrendFunctionConfiguration.java | 16 +- .../trend/TwitterTrendFunctionProperties.java | 17 +- .../TwitterUsersFunctionConfiguration.java | 6 +- .../users/TwitterUsersFunctionProperties.java | 20 +- .../twitter/geo/TwitterGeoFunctionTest.java | 121 ++-- .../trend/TwitterTrendFunctionTests.java | 50 +- .../users/TwitterUsersFunctionTests.java | 90 ++- gradle.properties | 1 - gradle/checkstyle-conventions.gradle | 19 + ...DebeziumReactiveConsumerConfiguration.java | 49 +- .../debezium/DebeziumSupplierProperties.java | 1 + ...iumReactiveConsumerConfigurationTests.java | 4 +- .../DebeziumSupplierIntegrationTest.java | 155 +++--- .../TestJdbcTemplateConfiguration.java | 6 +- .../file/FileSupplierConfiguration.java | 29 +- .../supplier/file/FileSupplierProperties.java | 6 +- .../file/DefaultFileSupplierTests.java | 55 +- .../fn/supplier/file/FileModeRefTests.java | 21 +- .../file/FilePayloadWithPatternTests.java | 21 +- .../file/FilePayloadWithRegexTests.java | 17 +- .../LinesAndMarkersAsJsonPayloadTests.java | 60 +- .../fn/supplier/file/LinesPayloadTests.java | 9 +- .../ftp/FtpSupplierConfiguration.java | 37 +- .../ftp/FtpSupplierPropertiesTests.java | 26 +- .../fn/supplier/ftp/FtpSupplierTests.java | 36 +- .../http/HttpSupplierConfiguration.java | 46 +- .../supplier/http/HttpSupplierProperties.java | 9 +- .../http/HttpSupplierApplicationTests.java | 139 ++--- .../jdbc/JdbcSupplierConfiguration.java | 8 +- .../jdbc/DefaultJdbcSupplierTests.java | 66 +-- .../jdbc/NonSplitJdbcSupplierTests.java | 4 +- .../jms/JmsSupplierConfiguration.java | 14 +- .../supplier/jms/JmsSupplierProperties.java | 1 + .../jms/AbstractJmsSupplierTests.java | 1 + .../jms/PropertiesPopulated1Tests.java | 20 +- .../jms/PropertiesPopulated2Tests.java | 13 +- .../jms/PropertiesPopulated3Tests.java | 23 +- .../kafka/KafkaSupplierConfiguration.java | 32 +- .../kafka/KafkaSupplierProperties.java | 4 +- .../fn/supplier/kafka/KafkaSupplierTests.java | 98 ++-- .../mail/MailSupplierConfiguration.java | 39 +- .../supplier/mail/MailSupplierProperties.java | 1 + .../mail/AbstractMailSupplierTests.java | 13 +- .../cloud/fn/supplier/mail/ImapFailTests.java | 17 +- .../fn/supplier/mail/ImapIdlePassTests.java | 18 +- .../cloud/fn/supplier/mail/ImapPassTests.java | 38 +- .../cloud/fn/supplier/mail/Pop3FailTests.java | 11 +- .../cloud/fn/supplier/mail/Pop3PassTests.java | 12 +- .../mongo/MongodbSupplierConfiguration.java | 13 +- .../MongodbSupplierApplicationTests.java | 36 +- .../mqtt/MqttSupplierConfiguration.java | 10 +- .../supplier/mqtt/MqttSupplierProperties.java | 3 +- .../fn/supplier/mqtt/MqttSupplierTests.java | 35 +- .../rabbit/RabbitSupplierConfiguration.java | 68 ++- .../rabbit/RabbitSupplierProperties.java | 3 +- .../s3/AwsS3SupplierConfiguration.java | 79 ++- .../supplier/s3/AwsS3SupplierProperties.java | 1 + .../s3/AbstractAwsS3SupplierMockTests.java | 50 +- .../s3/AmazonS3FilesTransferredTests.java | 25 +- .../s3/AmazonS3LinesTransferredTests.java | 29 +- .../fn/supplier/s3/AmazonS3ListOnlyTests.java | 41 +- .../sftp/SftpSupplierConfiguration.java | 158 +++--- .../SftpSupplierFactoryConfiguration.java | 17 +- .../supplier/sftp/SftpSupplierProperties.java | 29 +- .../fn/supplier/sftp/SftpSupplierRotator.java | 4 +- .../sftp/SftpSupplierApplicationTests.java | 523 ++++++++---------- .../syslog/SyslogSupplierConfiguration.java | 28 +- .../syslog/SyslogSupplierProperties.java | 6 +- .../syslog/AbstractSyslogSupplierTests.java | 10 +- .../cloud/fn/supplier/syslog/NotNioTests.java | 1 + .../syslog/PropertiesPopulatedTests.java | 6 +- .../fn/supplier/syslog/Tcp3164Tests.java | 11 +- .../fn/supplier/syslog/Tcp5424Tests.java | 11 +- .../supplier/syslog/TcpAndUdp3164Tests.java | 17 +- .../supplier/syslog/TcpAndUdp5424Tests.java | 16 +- .../fn/supplier/syslog/Udp3164Tests.java | 11 +- .../fn/supplier/syslog/Udp5424Tests.java | 11 +- .../tcp/TcpSupplierConfiguration.java | 10 +- .../tcp/AbstractTcpSupplierTests.java | 24 +- .../cloud/fn/supplier/tcp/CRLFTests.java | 1 + .../cloud/fn/supplier/tcp/L1Tests.java | 1 + .../cloud/fn/supplier/tcp/L2Tests.java | 1 + .../cloud/fn/supplier/tcp/L4Tests.java | 1 + .../cloud/fn/supplier/tcp/LFTests.java | 1 + .../cloud/fn/supplier/tcp/NULLTests.java | 1 + .../cloud/fn/supplier/tcp/NotNioTests.java | 1 + .../tcp/PropertiesPopulatedTests.java | 4 +- .../cloud/fn/supplier/tcp/RAWTests.java | 1 + .../cloud/fn/supplier/tcp/STXETXTests.java | 1 + .../cloud/fn/supplier/time/DateFormat.java | 6 +- .../time/TimeSupplierApplicationTests.java | 2 + .../supplier/time/VariationToSimpleTests.java | 5 +- ...itterFriendshipsSupplierConfiguration.java | 17 +- .../TwitterFriendshipsSupplierProperties.java | 19 +- .../TwitterMessageSupplierConfiguration.java | 20 +- .../TwitterMessageSupplierProperties.java | 2 +- .../status/search/SearchPagination.java | 57 +- .../TwitterSearchSupplierConfiguration.java | 15 +- .../TwitterSearchSupplierProperties.java | 33 +- .../TwitterStreamSupplierConfiguration.java | 77 ++- .../TwitterStreamSupplierProperties.java | 68 ++- .../status/search/SearchPaginationTests.java | 5 +- .../stream/TwitterStreamSupplierTests.java | 105 ++-- .../WebsocketSupplierConfiguration.java | 19 +- .../WebsocketSupplierProperties.java | 1 + .../websocket/WebsocketSupplierTests.java | 17 +- .../xmpp/XmppSupplierConfiguration.java | 3 +- .../supplier/xmpp/XmppSupplierProperties.java | 2 +- .../xmpp/XmppSupplierConfigurationTests.java | 44 +- .../zeromq/ZeroMqSupplierConfiguration.java | 2 +- .../zeromq/ZeroMqSupplierProperties.java | 5 +- .../ZeroMqSupplierConfigurationTests.java | 25 +- 357 files changed, 4396 insertions(+), 4571 deletions(-) create mode 100644 etc/checkstyle/checkstyle-header.txt create mode 100644 etc/checkstyle/checkstyle-suppressions.xml create mode 100644 etc/checkstyle/checkstyle.xml create mode 100644 gradle/checkstyle-conventions.gradle diff --git a/build.gradle b/build.gradle index e286cdf7..1fcc58f2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,12 @@ buildscript { ext.isCI = System.getenv('GITHUB_ACTION') + ext.javaFormatVersion = '0.0.40' } plugins { id 'base' id 'io.spring.dependency-management' version '1.1.4' + id "io.spring.javaformat" version "${javaFormatVersion}" apply false id 'com.github.spotbugs' version '6.0.4' id 'com.google.protobuf' version '0.9.4' apply false } @@ -58,12 +60,14 @@ allprojects { } + + configure(javaProjects) { subproject -> apply plugin: 'java-library' apply plugin: 'eclipse' apply plugin: 'idea' - apply from: "${rootDir}/publish-maven.gradle" + apply from: "${rootDir}/gradle/checkstyle-conventions.gradle" sourceSets { test { diff --git a/common/spring-aws-s3-common/src/main/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3Configuration.java b/common/spring-aws-s3-common/src/main/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3Configuration.java index 6f9f07e5..bf7335eb 100644 --- a/common/spring-aws-s3-common/src/main/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3Configuration.java +++ b/common/spring-aws-s3-common/src/main/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3Configuration.java @@ -33,7 +33,7 @@ * @author Artem Bilan */ @AutoConfiguration -@AutoConfigureAfter({S3AutoConfiguration.class, S3CrtAsyncClientAutoConfiguration.class}) +@AutoConfigureAfter({ S3AutoConfiguration.class, S3CrtAsyncClientAutoConfiguration.class }) public class AmazonS3Configuration { @Bean diff --git a/common/spring-aws-s3-common/src/test/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3ConfigurationTests.java b/common/spring-aws-s3-common/src/test/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3ConfigurationTests.java index ab1cf09c..b42bf1cd 100644 --- a/common/spring-aws-s3-common/src/test/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3ConfigurationTests.java +++ b/common/spring-aws-s3-common/src/test/java/org/springframework/cloud/fn/common/aws/s3/AmazonS3ConfigurationTests.java @@ -43,13 +43,9 @@ public class AmazonS3ConfigurationTests { private final ApplicationContextRunner runner = new ApplicationContextRunner() - .withConfiguration( - AutoConfigurations.of( - AwsAutoConfiguration.class, - S3AutoConfiguration.class, - S3CrtAsyncClientAutoConfiguration.class, - AmazonS3Configuration.class)) - .withUserConfiguration(TestConfiguration.class); + .withConfiguration(AutoConfigurations.of(AwsAutoConfiguration.class, S3AutoConfiguration.class, + S3CrtAsyncClientAutoConfiguration.class, AmazonS3Configuration.class)) + .withUserConfiguration(TestConfiguration.class); private static final String TEST_REGION_NAME = "eu-central-1"; @@ -61,22 +57,21 @@ public void testAmazonS3Configuration() { S3Utilities utilities = amazonS3.utilities(); Assertions.assertEquals(TEST_REGION_NAME, TestUtils.getPropertyValue(utilities, "region", Region.class).id()); - Assertions.assertTrue( - utilities.getUrl(GetUrlRequest.builder().bucket("b").key("k").build()).toString() - .startsWith("https://s3.eu-central-1.amazonaws.com")); + Assertions.assertTrue(utilities.getUrl(GetUrlRequest.builder().bucket("b").key("k").build()) + .toString() + .startsWith("https://s3.eu-central-1.amazonaws.com")); }); } @Test public void testAmazonS3ConfigurationForS3CompatibleStorage() { - runner.withPropertyValues( - "spring.cloud.aws.s3.endpoint=http://localhost:8080" - ).run(context -> { + runner.withPropertyValues("spring.cloud.aws.s3.endpoint=http://localhost:8080").run(context -> { S3Client amazonS3 = context.getBean(S3Client.class); Assertions.assertNotNull(amazonS3); S3Utilities utilities = amazonS3.utilities(); - Assertions.assertTrue(utilities.getUrl(GetUrlRequest.builder().bucket("b").key("k").build()).toString() - .startsWith("http://localhost:8080")); + Assertions.assertTrue(utilities.getUrl(GetUrlRequest.builder().bucket("b").key("k").build()) + .toString() + .startsWith("http://localhost:8080")); }); } diff --git a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/ComponentCustomizer.java b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/ComponentCustomizer.java index 3af872ae..fcd816c7 100644 --- a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/ComponentCustomizer.java +++ b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/ComponentCustomizer.java @@ -17,13 +17,11 @@ package org.springframework.cloud.fn.common.config; /** - * The customizer contract to apply to beans in the application context which - * type is matching to generic type of the instance of this interface. + * The customizer contract to apply to beans in the application context which type is + * matching to generic type of the instance of this interface. * * @param the target component (bean) type in the application context to customize. - * * @author Artem Bilan - * * @since 1.2.1 */ @FunctionalInterface diff --git a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java index a1f73150..28e910b2 100644 --- a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java +++ b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java @@ -42,14 +42,15 @@ public class SpelExpressionConverterConfiguration { /** - * Specific Application Context name to be used as Bean qualifier when the {@link EvaluationContext} is injected. + * Specific Application Context name to be used as Bean qualifier when the + * {@link EvaluationContext} is injected. */ public static final String INTEGRATION_EVALUATION_CONTEXT = "integrationEvaluationContext"; @Bean public static SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() { return (new SpelPropertyAccessorRegistrar()) - .add(Introspector.decapitalize(JsonPropertyAccessor.class.getSimpleName()), new JsonPropertyAccessor()); + .add(Introspector.decapitalize(JsonPropertyAccessor.class.getSimpleName()), new JsonPropertyAccessor()); } @Bean @@ -60,6 +61,7 @@ public Converter spelConverter() { } public static class SpelConverter implements Converter { + private SpelExpressionParser parser = new SpelExpressionParser(); @Autowired @@ -84,5 +86,7 @@ public Expression convert(String source) { String.format("Could not convert '%s' into a SpEL expression", source), var3); } } + } + } diff --git a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfiguration.java b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfiguration.java index 6e6c6656..854dde6e 100644 --- a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfiguration.java +++ b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfiguration.java @@ -46,16 +46,20 @@ /** * {@link EnableAutoConfiguration Auto-configuration} for {@link DebeziumEngine.Builder}. *

- * The builder provides a standalone engine configuration that talks with the source data system. + * The builder provides a standalone engine configuration that talks with the source data + * system. *

- * The application that runs the debezium engine assumes all responsibility for fault tolerance, scalability, and - * durability. Additionally, applications must specify how the engine can store its relational database schema history - * and offsets. By default, this information will be stored in memory and will thus be lost upon application restart. + * The application that runs the debezium engine assumes all responsibility for fault + * tolerance, scalability, and durability. Additionally, applications must specify how the + * engine can store its relational database schema history and offsets. By default, this + * information will be stored in memory and will thus be lost upon application restart. *

- * The {@link DebeziumEngine.Builder} auto-configuration is activated only if a Debezium Connector is available on the - * classpath and the debezium.properties.connector.class property is set. + * The {@link DebeziumEngine.Builder} auto-configuration is activated only if a Debezium + * Connector is available on the classpath and the + * debezium.properties.connector.class property is set. *

- * Properties prefixed with debezium.properties are passed through as native Debezium properties. + * Properties prefixed with debezium.properties are passed through as native + * Debezium properties. * * @author Christian Tzolov * @author Corneil du Plessis @@ -69,29 +73,31 @@ public class DebeziumEngineBuilderAutoConfiguration { private static final Log logger = LogFactory.getLog(DebeziumEngineBuilderAutoConfiguration.class); /** - * The fully-qualified class name of the commit policy type. The default is a periodic commit policy based upon time - * intervals. - * @param properties The 'debezium.properties.offset.flush.interval.ms' configuration is compulsory for the Periodic - * policy type. The ALWAYS and DEFAULT doesn't require additional configuration. + * The fully-qualified class name of the commit policy type. The default is a periodic + * commit policy based upon time intervals. + * @param properties The 'debezium.properties.offset.flush.interval.ms' configuration + * is compulsory for the Periodic policy type. The ALWAYS and DEFAULT doesn't require + * additional configuration. */ @Bean @ConditionalOnMissingBean public OffsetCommitPolicy offsetCommitPolicy(DebeziumProperties properties) { switch (properties.getOffsetCommitPolicy()) { - case PERIODIC: - return OffsetCommitPolicy.periodic(properties.getDebeziumNativeConfiguration()); - case ALWAYS: - return OffsetCommitPolicy.always(); - case DEFAULT: - default: - return NULL_OFFSET_COMMIT_POLICY; + case PERIODIC: + return OffsetCommitPolicy.periodic(properties.getDebeziumNativeConfiguration()); + case ALWAYS: + return OffsetCommitPolicy.always(); + case DEFAULT: + default: + return NULL_OFFSET_COMMIT_POLICY; } } /** - * Use the specified clock when needing to determine the current time. Defaults to {@link Clock#systemDefaultZone() - * system clock}, but you can override the Bean in your configuration with you {@link Clock implementation}. Returns + * Use the specified clock when needing to determine the current time. Defaults to + * {@link Clock#systemDefaultZone() system clock}, but you can override the Bean in + * your configuration with you {@link Clock implementation}. Returns * @return Clock for the system default zone. */ @Bean @@ -101,9 +107,10 @@ public Clock debeziumClock() { } /** - * When the engine's {@link DebeziumEngine#run()} method completes, call the supplied function with the results. - * @return Default completion callback that logs the completion status. The bean can be overridden in custom - * implementation. + * When the engine's {@link DebeziumEngine#run()} method completes, call the supplied + * function with the results. + * @return Default completion callback that logs the completion status. The bean can + * be overridden in custom implementation. */ @Bean @ConditionalOnMissingBean @@ -112,8 +119,9 @@ public CompletionCallback completionCallback() { } /** - * During the engine run, provides feedback about the different stages according to the completion state of each - * component running within the engine (connectors, tasks etc). The bean can be overridden in custom implementation. + * During the engine run, provides feedback about the different stages according to + * the completion state of each component running within the engine (connectors, tasks + * etc). The bean can be overridden in custom implementation. */ @Bean @ConditionalOnMissingBean @@ -135,29 +143,29 @@ public DebeziumEngine.Builder> debeziumEngineBuilder serializationFormatClass(properties.getHeaderFormat()), "Cannot find header format for " + properties.getProperties()); - return DebeziumEngine - .create(KeyValueHeaderChangeEventFormat.of(payloadFormat, payloadFormat, headerFormat)) - .using(properties.getDebeziumNativeConfiguration()) - .using(debeziumClock) - .using(completionCallback) - .using(connectorCallback) - .using((offsetCommitPolicy != NULL_OFFSET_COMMIT_POLICY) ? offsetCommitPolicy : null); + return DebeziumEngine.create(KeyValueHeaderChangeEventFormat.of(payloadFormat, payloadFormat, headerFormat)) + .using(properties.getDebeziumNativeConfiguration()) + .using(debeziumClock) + .using(completionCallback) + .using(connectorCallback) + .using((offsetCommitPolicy != NULL_OFFSET_COMMIT_POLICY) ? offsetCommitPolicy : null); } /** - * Converts the {@link DebeziumFormat} enum into Debezium {@link SerializationFormat} class. + * Converts the {@link DebeziumFormat} enum into Debezium {@link SerializationFormat} + * class. * @param debeziumFormat debezium format property. */ private Class> serializationFormatClass(DebeziumFormat debeziumFormat) { switch (debeziumFormat) { - case JSON: - return io.debezium.engine.format.JsonByteArray.class; - case AVRO: - return io.debezium.engine.format.Avro.class; - case PROTOBUF: - return io.debezium.engine.format.Protobuf.class; - default: - throw new IllegalArgumentException("Unknown debezium format: " + debeziumFormat); + case JSON: + return io.debezium.engine.format.JsonByteArray.class; + case AVRO: + return io.debezium.engine.format.Avro.class; + case PROTOBUF: + return io.debezium.engine.format.Protobuf.class; + default: + throw new IllegalArgumentException("Unknown debezium format: " + debeziumFormat); } } @@ -173,7 +181,8 @@ public void handle(boolean success, String message, Throwable error) { }; /** - * Callback function which informs users about the various stages a connector goes through during startup. + * Callback function which informs users about the various stages a connector goes + * through during startup. */ private static final ConnectorCallback DEFAULT_CONNECTOR_CALLBACK = new ConnectorCallback() { @@ -218,7 +227,8 @@ public boolean performCommit(long numberOfMessagesSinceLastCommit, Duration time }; /** - * Determine if Debezium connector is available. This either kicks in if any debezium connector is available. + * Determine if Debezium connector is available. This either kicks in if any debezium + * connector is available. */ @Order(Ordered.LOWEST_PRECEDENCE) static class OnDebeziumConnectorCondition extends AnyNestedCondition { diff --git a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumProperties.java b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumProperties.java index 23a2cf9b..ad956e24 100644 --- a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumProperties.java +++ b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/DebeziumProperties.java @@ -29,6 +29,7 @@ public class DebeziumProperties { public enum DebeziumFormat { + /** * JSON change event format. */ @@ -51,11 +52,12 @@ public enum DebeziumFormat { public final String contentType() { return contentType; } + }; /** - * Spring pass-trough wrapper for debezium configuration properties. All properties with a 'debezium.properties.*' - * prefix are native Debezium properties. + * Spring pass-trough wrapper for debezium configuration properties. All properties + * with a 'debezium.properties.*' prefix are native Debezium properties. */ private Map properties = new HashMap<>(); @@ -95,21 +97,24 @@ public void setHeaderFormat(DebeziumFormat headerFormat) { } public enum DebeziumOffsetCommitPolicy { + /** - * Commits offsets as frequently as possible. This may result in reduced performance, but it has the least - * potential for seeing source records more than once upon restart. + * Commits offsets as frequently as possible. This may result in reduced + * performance, but it has the least potential for seeing source records more than + * once upon restart. */ ALWAYS, /** - * Commits offsets no more than the specified time period. If the specified time is less than {@code 0} then the - * policy will behave as ALWAYS policy. Requires the 'debezium.properties.offset.flush.interval.ms' native - * property to be set. + * Commits offsets no more than the specified time period. If the specified time + * is less than {@code 0} then the policy will behave as ALWAYS policy. Requires + * the 'debezium.properties.offset.flush.interval.ms' native property to be set. */ PERIODIC, /** * Uses the default Debezium engine policy (PERIODIC). */ DEFAULT; + } public DebeziumOffsetCommitPolicy getOffsetCommitPolicy() { @@ -121,11 +126,13 @@ public void setOffsetCommitPolicy(DebeziumOffsetCommitPolicy offsetCommitPolicy) } /** - * Converts the Spring Framework "debezium.properties.*" properties into native Debezium configuration. + * Converts the Spring Framework "debezium.properties.*" properties into native + * Debezium configuration. */ public Properties getDebeziumNativeConfiguration() { Properties outProps = new java.util.Properties(); outProps.putAll(this.getProperties()); return outProps; } + } diff --git a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/EmbeddedEngineExecutorService.java b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/EmbeddedEngineExecutorService.java index 971e6cf0..37406fc8 100644 --- a/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/EmbeddedEngineExecutorService.java +++ b/common/spring-debezium-autoconfigure/src/main/java/org/springframework/cloud/fn/common/debezium/EmbeddedEngineExecutorService.java @@ -28,14 +28,16 @@ import org.springframework.context.SmartLifecycle; /** - * The Debezium Engine is designed to be submitted to an {@link Executor} or {@link ExecutorService} for execution by a - * single thread, and a running connector can be stopped either by calling {@link #stop()} from another thread or by - * interrupting the running thread (e.g., as is the case with {@link ExecutorService#shutdownNow()}). + * The Debezium Engine is designed to be submitted to an {@link Executor} or + * {@link ExecutorService} for execution by a single thread, and a running connector can + * be stopped either by calling {@link #stop()} from another thread or by interrupting the + * running thread (e.g., as is the case with {@link ExecutorService#shutdownNow()}). * - * The EmbeddedEngineExecutorService provides a sample ExecutorService implementation aligned with the Spring lifecycle. + * The EmbeddedEngineExecutorService provides a sample ExecutorService implementation + * aligned with the Spring lifecycle. * - * Note that the DebeziumReactiveConsumerConfiguration embeds an ExecutorService as part of the - * Supplier<Flux<Message<?>>> configuration. + * Note that the DebeziumReactiveConsumerConfiguration embeds an ExecutorService as part + * of the Supplier<Flux<Message<?>>> configuration. * * @author Christian Tzolov */ @@ -44,7 +46,9 @@ public class EmbeddedEngineExecutorService implements SmartLifecycle, AutoClosea private static final Log logger = LogFactory.getLog(EmbeddedEngineExecutorService.class); private final DebeziumEngine engine; + private final ExecutorService executor; + private final AtomicBoolean running = new AtomicBoolean(false); public EmbeddedEngineExecutorService(DebeziumEngine engine) { @@ -81,4 +85,5 @@ public void close() { public boolean isRunning() { return this.running.get(); } + } diff --git a/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationIntegrationTest.java b/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationIntegrationTest.java index fd39520f..014987d0 100644 --- a/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationIntegrationTest.java +++ b/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationIntegrationTest.java @@ -54,18 +54,21 @@ import static org.awaitility.Awaitility.await; /** - * This test illustrate how to leverage the DebeziumEngineAutoConfiguration to build a consumer function with a custom - * change event Consumer. + * This test illustrate how to leverage the DebeziumEngineAutoConfiguration to build a + * consumer function with a custom change event Consumer. * * @author Christian Tzolov */ @Tag("integration") @Testcontainers public class DebeziumEngineBuilderAutoConfigurationIntegrationTest { + private static final Log logger = LogFactory.getLog(DebeziumEngineBuilderAutoConfigurationIntegrationTest.class); private static final String DATABASE_NAME = "inventory"; + public static final String IMAGE_TAG = "2.3.0.Final"; + public static final String DEBEZIUM_EXAMPLE_MYSQL_IMAGE = "debezium/example-mysql:" + IMAGE_TAG; @TempDir @@ -73,70 +76,64 @@ public class DebeziumEngineBuilderAutoConfigurationIntegrationTest { @Container static GenericContainer debeziumMySQL = new GenericContainer<>(DEBEZIUM_EXAMPLE_MYSQL_IMAGE) - .withEnv("MYSQL_ROOT_PASSWORD", "debezium") - .withEnv("MYSQL_USER", "mysqluser") - .withEnv("MYSQL_PASSWORD", "mysqlpw") - .withExposedPorts(3306); + .withEnv("MYSQL_ROOT_PASSWORD", "debezium") + .withEnv("MYSQL_USER", "mysqluser") + .withEnv("MYSQL_PASSWORD", "mysqlpw") + .withExposedPorts(3306); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withUserConfiguration(DebeziumCustomConsumerApplication.class) - .withPropertyValues( - "spring.datasource.type=com.zaxxer.hikari.HikariDataSource", - - "debezium.properties.offset.storage=org.apache.kafka.connect.storage.FileOffsetBackingStore", - "debezium.properties.offset.storage.file.filename=" + anotherTempDir.getAbsolutePath() - + "offsets.dat", - "debezium.properties.offset.flush.interval.ms=60000", - - "debezium.properties.schema.history.internal=io.debezium.storage.file.history.FileSchemaHistory", // new - "debezium.properties.schema.history.internal.file.filename=" + anotherTempDir.getAbsolutePath() - + "schemahistory.dat", - - "debezium.properties.topic.prefix=my-topic", - - "debezium.properties.name=my-sql-connector", - "debezium.properties.connector.class=io.debezium.connector.mysql.MySqlConnector", - - "debezium.properties.database.user=debezium", - "debezium.properties.database.password=dbz", - "debezium.properties.database.hostname=localhost", - "debezium.properties.database.port=" + debeziumMySQL.getMappedPort(3306), - "debezium.properties.database.server.id=85744", - - // JdbcTemplate configuration - String.format("app.datasource.url=jdbc:mysql://localhost:%d/%s?enabledTLSProtocols=TLSv1.2", - debeziumMySQL.getMappedPort(3306), DATABASE_NAME), - "app.datasource.username=root", - "app.datasource.password=debezium", - "app.datasource.driver-class-name=com.mysql.cj.jdbc.Driver", - "app.datasource.type=com.zaxxer.hikari.HikariDataSource"); + .withUserConfiguration(DebeziumCustomConsumerApplication.class) + .withPropertyValues("spring.datasource.type=com.zaxxer.hikari.HikariDataSource", + + "debezium.properties.offset.storage=org.apache.kafka.connect.storage.FileOffsetBackingStore", + "debezium.properties.offset.storage.file.filename=" + anotherTempDir.getAbsolutePath() + "offsets.dat", + "debezium.properties.offset.flush.interval.ms=60000", + + "debezium.properties.schema.history.internal=io.debezium.storage.file.history.FileSchemaHistory", // new + "debezium.properties.schema.history.internal.file.filename=" + anotherTempDir.getAbsolutePath() + + "schemahistory.dat", + + "debezium.properties.topic.prefix=my-topic", + + "debezium.properties.name=my-sql-connector", + "debezium.properties.connector.class=io.debezium.connector.mysql.MySqlConnector", + + "debezium.properties.database.user=debezium", "debezium.properties.database.password=dbz", + "debezium.properties.database.hostname=localhost", + "debezium.properties.database.port=" + debeziumMySQL.getMappedPort(3306), + "debezium.properties.database.server.id=85744", + + // JdbcTemplate configuration + String.format("app.datasource.url=jdbc:mysql://localhost:%d/%s?enabledTLSProtocols=TLSv1.2", + debeziumMySQL.getMappedPort(3306), DATABASE_NAME), + "app.datasource.username=root", "app.datasource.password=debezium", + "app.datasource.driver-class-name=com.mysql.cj.jdbc.Driver", + "app.datasource.type=com.zaxxer.hikari.HikariDataSource"); @Test public void consumerTest() { logger.info("Temp dir: " + anotherTempDir.getAbsolutePath()); - contextRunner - .withPropertyValues( - // Flattering: - // https://debezium.io/documentation/reference/stable/transformations/event-flattening.html - "debezium.properties.transforms=unwrap", - "debezium.properties.transforms.unwrap.type=io.debezium.transforms.ExtractNewRecordState", - "debezium.properties.transforms.unwrap.drop.tombstones=false", - "debezium.properties.transforms.unwrap.delete.handling.mode=rewrite", - "debezium.properties.transforms.unwrap.add.fields=name,db") - .run(context -> { - JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class); - - DebeziumCustomConsumerApplication.TestDebeziumConsumer testConsumer = context - .getBean(DebeziumCustomConsumerApplication.TestDebeziumConsumer.class); - jdbcTemplate.update( - "insert into `customers`(`first_name`,`last_name`,`email`) " + - "VALUES('Test666', 'Test666', 'Test666@spring.org')"); - JdbcTestUtils.deleteFromTableWhere(jdbcTemplate, "customers", "first_name = ?", "Test666"); - - await().atMost(Duration.ofSeconds(30)).until(() -> (testConsumer.recordList.size() >= 52)); - }); + contextRunner.withPropertyValues( + // Flattering: + // https://debezium.io/documentation/reference/stable/transformations/event-flattening.html + "debezium.properties.transforms=unwrap", + "debezium.properties.transforms.unwrap.type=io.debezium.transforms.ExtractNewRecordState", + "debezium.properties.transforms.unwrap.drop.tombstones=false", + "debezium.properties.transforms.unwrap.delete.handling.mode=rewrite", + "debezium.properties.transforms.unwrap.add.fields=name,db") + .run(context -> { + JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class); + + DebeziumCustomConsumerApplication.TestDebeziumConsumer testConsumer = context + .getBean(DebeziumCustomConsumerApplication.TestDebeziumConsumer.class); + jdbcTemplate.update("insert into `customers`(`first_name`,`last_name`,`email`) " + + "VALUES('Test666', 'Test666', 'Test666@spring.org')"); + JdbcTestUtils.deleteFromTableWhere(jdbcTemplate, "customers", "first_name = ?", "Test666"); + + await().atMost(Duration.ofSeconds(30)).until(() -> (testConsumer.recordList.size() >= 52)); + }); } @SpringBootConfiguration @@ -157,16 +154,14 @@ public DataSourceProperties dataSourceProperties() { @Bean public HikariDataSource dataSource(DataSourceProperties dataSourceProperties) { - return dataSourceProperties.initializeDataSourceBuilder() - .type(HikariDataSource.class) - .build(); + return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); } @Bean public EmbeddedEngineExecutorService embeddedEngine(Consumer> changeEventConsumer, Builder> debeziumEngineBuilder) { DebeziumEngine> b = debeziumEngineBuilder.notifying(changeEventConsumer) - .build(); + .build(); return new EmbeddedEngineExecutorService(debeziumEngineBuilder.notifying(changeEventConsumer).build()); } @@ -196,7 +191,9 @@ public void accept(ChangeEvent changeEvent) { System.out.println("[Debezium Event]: " + changeEvent.toString()); } } + } + } } diff --git a/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationTests.java b/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationTests.java index 50840e8c..90391969 100644 --- a/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationTests.java +++ b/common/spring-debezium-autoconfigure/src/test/java/org/springframework/cloud/fn/common/debezium/DebeziumEngineBuilderAutoConfigurationTests.java @@ -33,7 +33,7 @@ public class DebeziumEngineBuilderAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DebeziumEngineBuilderAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(DebeziumEngineBuilderAutoConfiguration.class)); // We have the debezium connectors on the classpath by default. @@ -47,10 +47,10 @@ void noConnectorNoProperty() { @Test void noConnectorWithProperty() { this.contextRunner.withPropertyValues("debezium.properties.connector.class=Dummy") - .withClassLoader(new FilteredClassLoader("io.debezium.connector")) - .run((context) -> { - assertThat(context).doesNotHaveBean(DebeziumEngine.Builder.class); - }); + .withClassLoader(new FilteredClassLoader("io.debezium.connector")) + .run((context) -> { + assertThat(context).doesNotHaveBean(DebeziumEngine.Builder.class); + }); } @Test diff --git a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileConsumerProperties.java b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileConsumerProperties.java index 7d3cc19d..98935bdf 100644 --- a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileConsumerProperties.java +++ b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileConsumerProperties.java @@ -23,8 +23,7 @@ import org.springframework.validation.annotation.Validated; /** - * - * @author David Turanski + * @author David Turanski * @author Artem Bilan */ @ConfigurationProperties("file.consumer") @@ -32,22 +31,20 @@ public class FileConsumerProperties { /** - * The FileReadingMode to use for file reading sources. - * Values are 'ref' - The File object, - * 'lines' - a message per line, or - * 'contents' - the contents as bytes. + * The FileReadingMode to use for file reading sources. Values are 'ref' - The File + * object, 'lines' - a message per line, or 'contents' - the contents as bytes. */ private FileReadingMode mode = FileReadingMode.contents; /** - * Set to true to emit start of file/end of file marker messages before/after the data. - * Only valid with FileReadingMode 'lines'. + * Set to true to emit start of file/end of file marker messages before/after the + * data. Only valid with FileReadingMode 'lines'. */ private Boolean withMarkers = null; /** - * When 'fileMarkers == true', specify if they should be produced - * as FileSplitter.FileMarker objects or JSON. + * When 'fileMarkers == true', specify if they should be produced as + * FileSplitter.FileMarker objects or JSON. */ private boolean markersJson = true; @@ -80,4 +77,5 @@ public void setMarkersJson(boolean markersJson) { public boolean isWithMarkersValid() { return this.withMarkers == null || FileReadingMode.lines == this.mode; } + } diff --git a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileReadingMode.java b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileReadingMode.java index c6db428e..dabf5e5f 100644 --- a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileReadingMode.java +++ b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileReadingMode.java @@ -23,6 +23,7 @@ * @author David Turanski */ public enum FileReadingMode { + /** * ref mode. */ @@ -35,4 +36,5 @@ public enum FileReadingMode { * contents mode. */ contents; + } diff --git a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileUtils.java b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileUtils.java index 9a56618b..8fbe08c5 100644 --- a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileUtils.java +++ b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/FileUtils.java @@ -39,35 +39,35 @@ private FileUtils() { /** * Enhance an {@link IntegrationFlowBuilder} to add flow snippets, depending on * {@link FileConsumerProperties}. - * - * @param flowBuilder the flow builder. + * @param flowBuilder the flow builder. * @param fileConsumerProperties the properties. * @return the updated flow builder. */ public static IntegrationFlowBuilder enhanceFlowForReadingMode(IntegrationFlowBuilder flowBuilder, - FileConsumerProperties fileConsumerProperties) { + FileConsumerProperties fileConsumerProperties) { switch (fileConsumerProperties.getMode()) { case contents: flowBuilder.enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE)) - .transform(new FileToByteArrayTransformer()); + .transform(new FileToByteArrayTransformer()); break; case lines: Boolean withMarkers = fileConsumerProperties.getWithMarkers(); if (withMarkers == null) { withMarkers = false; } - flowBuilder.enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.TEXT_PLAIN_VALUE)) - .split(new FileSplitter(true, withMarkers, fileConsumerProperties.getMarkersJson())); + flowBuilder + .enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, + MimeTypeUtils.TEXT_PLAIN_VALUE)) + .split(new FileSplitter(true, withMarkers, fileConsumerProperties.getMarkersJson())); break; case ref: flowBuilder.enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE)); break; default: - throw new IllegalArgumentException(fileConsumerProperties.getMode().name() + - " is not a supported file reading mode."); + throw new IllegalArgumentException( + fileConsumerProperties.getMode().name() + " is not a supported file reading mode."); } return flowBuilder; } @@ -75,32 +75,32 @@ public static IntegrationFlowBuilder enhanceFlowForReadingMode(IntegrationFlowBu /** * Enhance an {@link IntegrationFlowBuilder} to add flow snippets, depending on * {@link FileConsumerProperties}; used for streaming sources. - * - * @param flowBuilder the flow builder. + * @param flowBuilder the flow builder. * @param fileConsumerProperties the properties. * @return the updated flow builder. */ public static IntegrationFlowBuilder enhanceStreamFlowForReadingMode(IntegrationFlowBuilder flowBuilder, - FileConsumerProperties fileConsumerProperties) { + FileConsumerProperties fileConsumerProperties) { switch (fileConsumerProperties.getMode()) { case contents: flowBuilder.enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE)) - .transform(new StreamTransformer()); + .transform(new StreamTransformer()); break; case lines: Boolean withMarkers = fileConsumerProperties.getWithMarkers(); if (withMarkers == null) { withMarkers = false; } - flowBuilder.enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, - MimeTypeUtils.TEXT_PLAIN_VALUE)) - .split(new FileSplitter(true, withMarkers, fileConsumerProperties.getMarkersJson())); + flowBuilder + .enrichHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, + MimeTypeUtils.TEXT_PLAIN_VALUE)) + .split(new FileSplitter(true, withMarkers, fileConsumerProperties.getMarkersJson())); break; case ref: default: - throw new IllegalArgumentException(fileConsumerProperties.getMode().name() + - " is not a supported file reading mode when streaming."); + throw new IllegalArgumentException(fileConsumerProperties.getMode().name() + + " is not a supported file reading mode when streaming."); } return flowBuilder; } diff --git a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileDeletingAdvice.java b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileDeletingAdvice.java index 67fd7f81..8d891987 100644 --- a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileDeletingAdvice.java +++ b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileDeletingAdvice.java @@ -41,8 +41,7 @@ public class RemoteFileDeletingAdvice implements MessageSourceMutator { * @param template the template. * @param remoteFileSeparator the separator. */ - public RemoteFileDeletingAdvice(RemoteFileTemplate template, - String remoteFileSeparator) { + public RemoteFileDeletingAdvice(RemoteFileTemplate template, String remoteFileSeparator) { this.template = template; this.remoteFileSeparator = remoteFileSeparator; } @@ -57,4 +56,5 @@ public Message afterReceive(@Nullable Message result, MessageSource sou } return result; } + } diff --git a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileRenamingAdvice.java b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileRenamingAdvice.java index 06181683..05490f93 100644 --- a/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileRenamingAdvice.java +++ b/common/spring-file-common/src/main/java/org/springframework/cloud/fn/common/file/remote/RemoteFileRenamingAdvice.java @@ -24,7 +24,6 @@ import org.springframework.lang.Nullable; import org.springframework.messaging.Message; - /** * A {@link MessageSourceMutator} that renames a remote file on success. * @@ -45,9 +44,7 @@ public class RemoteFileRenamingAdvice implements MessageSourceMutator { * @param remoteFileSeparator the separator. * @param newNameExp the SpEl expression for the new name. */ - public RemoteFileRenamingAdvice(RemoteFileTemplate template, - String remoteFileSeparator, - Expression newNameExp) { + public RemoteFileRenamingAdvice(RemoteFileTemplate template, String remoteFileSeparator, Expression newNameExp) { this.template = template; this.remoteFileSeparator = remoteFileSeparator; this.newName = newNameExp; @@ -66,4 +63,5 @@ public Message afterReceive(@Nullable Message result, MessageSource sou } return result; } + } diff --git a/common/spring-ftp-common/src/main/java/org/springframework/cloud/fn/common/ftp/FtpSessionFactoryProperties.java b/common/spring-ftp-common/src/main/java/org/springframework/cloud/fn/common/ftp/FtpSessionFactoryProperties.java index 5dc14558..2d711718 100644 --- a/common/spring-ftp-common/src/main/java/org/springframework/cloud/fn/common/ftp/FtpSessionFactoryProperties.java +++ b/common/spring-ftp-common/src/main/java/org/springframework/cloud/fn/common/ftp/FtpSessionFactoryProperties.java @@ -48,6 +48,7 @@ public class FtpSessionFactoryProperties { */ private String username; + /** * The password to use to connect to the server. */ diff --git a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/file/remote/RemoteFileTestSupport.java b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/file/remote/RemoteFileTestSupport.java index adf735c6..e814955c 100644 --- a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/file/remote/RemoteFileTestSupport.java +++ b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/file/remote/RemoteFileTestSupport.java @@ -80,13 +80,14 @@ public File getTargetLocalDirectory() { * localTarget/ * * - * The intent is tests retrieve from remoteSource and verify arrival in localTarget or send from localSource and verify - * arrival in remoteTarget. + * The intent is tests retrieve from remoteSource and verify arrival in localTarget or + * send from localSource and verify arrival in remoteTarget. *

- * Subclasses can change 'remote' in these names by overriding {@link #prefix()} or override this method completely to - * create a different structure. + * Subclasses can change 'remote' in these names by overriding {@link #prefix()} or + * override this method completely to create a different structure. *

- * While a single server exists for all tests, the directory structure is rebuilt for each test. + * While a single server exists for all tests, the directory structure is rebuilt for + * each test. * @throws IOException IO Exception. */ @BeforeEach @@ -151,4 +152,5 @@ public static void recursiveDelete(File file) { protected String prefix() { return "remote"; } + } diff --git a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/ftp/FtpTestSupport.java b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/ftp/FtpTestSupport.java index 0788f664..65e7b87c 100644 --- a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/ftp/FtpTestSupport.java +++ b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/ftp/FtpTestSupport.java @@ -79,14 +79,12 @@ private static final class TestUserManager implements UserManager { private TestUserManager(String homeDirectory) { this.testUser = new BaseUser(); - this.testUser.setAuthorities(Arrays.asList(new ConcurrentLoginPermission(1024, 1024), - new WritePermission(), + this.testUser.setAuthorities(Arrays.asList(new ConcurrentLoginPermission(1024, 1024), new WritePermission(), new TransferRatePermission(1024, 1024))); this.testUser.setHomeDirectory(homeDirectory); this.testUser.setName("TEST_USER"); } - @Override public User getUserByName(String s) throws FtpException { return this.testUser; @@ -126,4 +124,5 @@ public boolean isAdmin(String s) throws FtpException { } } + } diff --git a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/sftp/SftpTestSupport.java b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/sftp/SftpTestSupport.java index ead7a892..2c8b738a 100644 --- a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/sftp/SftpTestSupport.java +++ b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/sftp/SftpTestSupport.java @@ -58,8 +58,13 @@ public String prefix() { @BeforeAll public static void createServer() throws Exception { server = SshServer.setUpDefaultServer(); - server.setPasswordAuthenticator((username, password, session) -> - StringUtils.hasText(password) && !"badPassword".equals(password)); // fail if pub key validation failed + server.setPasswordAuthenticator( + (username, password, session) -> StringUtils.hasText(password) && !"badPassword".equals(password)); // fail + // if + // pub + // key + // validation + // failed server.setPublickeyAuthenticator((username, key, session) -> key.equals(decodePublicKey("id_rsa_pp.pub"))); server.setPort(0); server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("hostkey.ser").toPath())); @@ -67,8 +72,7 @@ public static void createServer() throws Exception { server.setFileSystemFactory(new VirtualFileSystemFactory(remoteTemporaryFolder)); server.start(); System.setProperty("sftp.factory.port", String.valueOf(server.getPort())); - System.setProperty("sftp.consumer.localDir", - localTemporaryFolder + File.separator + "localTarget"); + System.setProperty("sftp.consumer.localDir", localTemporaryFolder + File.separator + "localTarget"); } @AfterAll @@ -117,4 +121,5 @@ private static BigInteger decodeBigInt(ByteBuffer bb) { bb.get(bytes); return new BigInteger(bytes); } + } diff --git a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/websocket/WebsocketConsumerClientHandler.java b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/websocket/WebsocketConsumerClientHandler.java index 8a857d0f..a4983053 100644 --- a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/websocket/WebsocketConsumerClientHandler.java +++ b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/websocket/WebsocketConsumerClientHandler.java @@ -57,4 +57,5 @@ public void await() throws InterruptedException { public List getReceivedMessages() { return receivedMessages; } + } diff --git a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/xmpp/XmppTestContainerSupport.java b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/xmpp/XmppTestContainerSupport.java index e426765f..b3220c26 100644 --- a/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/xmpp/XmppTestContainerSupport.java +++ b/common/spring-function-test-support/src/main/java/org/springframework/cloud/fn/test/support/xmpp/XmppTestContainerSupport.java @@ -57,8 +57,7 @@ public interface XmppTestContainerSupport { /** * The container. */ - GenericContainer XMPP_CONTAINER = new GenericContainer<>("fishbowler/openfire:v4.7.0") - .withExposedPorts(5222) + GenericContainer XMPP_CONTAINER = new GenericContainer<>("fishbowler/openfire:v4.7.0").withExposedPorts(5222) .withClasspathResourceMapping("xmpp/conf", "/var/lib/openfire/conf", BindMode.READ_ONLY) .withCommand("-demoboot") .withStartupTimeout(Duration.ofSeconds(120)) diff --git a/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfiguration.java b/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfiguration.java index fa2b9fa6..7b20120a 100644 --- a/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfiguration.java +++ b/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfiguration.java @@ -47,7 +47,6 @@ * @author Artem Bilan * @author David Turanski * @author Corneil du Plessis - * * @since 2.0.2 */ @AutoConfiguration @@ -170,6 +169,7 @@ public ConcurrentMetadataStore dynamoDbMetadataStore(DynamoDbAsyncClient dynamoD @ConditionalOnProperty(prefix = "metadata.store", name = "type", havingValue = "jdbc") static class Jdbc { + @Bean @ConditionalOnMissingBean public ConcurrentMetadataStore jdbcMetadataStore(JdbcTemplate jdbcTemplate, diff --git a/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreProperties.java b/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreProperties.java index 85b0c4d9..ee46c27a 100644 --- a/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreProperties.java +++ b/common/spring-metadata-store-common/src/main/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreProperties.java @@ -32,19 +32,16 @@ */ @ConfigurationProperties("metadata.store") public class MetadataStoreProperties { + enum StoreType { - mongodb, - redis, - dynamodb, - jdbc, - zookeeper, - hazelcast, - memory + + mongodb, redis, dynamodb, jdbc, zookeeper, hazelcast, memory + } /** - * Indicates the type of metadata store to configure (default is 'memory'). - * You must include the corresponding Spring Integration dependency to use a persistent store. + * Indicates the type of metadata store to configure (default is 'memory'). You must + * include the corresponding Spring Integration dependency to use a persistent store. */ private StoreType type = StoreType.memory; diff --git a/common/spring-metadata-store-common/src/test/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfigurationTests.java b/common/spring-metadata-store-common/src/test/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfigurationTests.java index 107bdde3..d08f2ccf 100644 --- a/common/spring-metadata-store-common/src/test/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfigurationTests.java +++ b/common/spring-metadata-store-common/src/test/java/org/springframework/cloud/fn/common/metadata/store/MetadataStoreAutoConfigurationTests.java @@ -56,41 +56,30 @@ /** * @author Artem Bilan * @author Corneil du Plessis - * * @since 2.0.2 */ public class MetadataStoreAutoConfigurationTests { - private final static List> METADATA_STORE_CLASSES = - List.of( - RedisMetadataStore.class, - MongoDbMetadataStore.class, - JdbcMetadataStore.class, - ZookeeperMetadataStore.class, - HazelcastMetadataStore.class, - DynamoDbMetadataStore.class, - SimpleMetadataStore.class - ); + private final static List> METADATA_STORE_CLASSES = List.of( + RedisMetadataStore.class, MongoDbMetadataStore.class, JdbcMetadataStore.class, ZookeeperMetadataStore.class, + HazelcastMetadataStore.class, DynamoDbMetadataStore.class, SimpleMetadataStore.class); @ParameterizedTest @MethodSource public void testMetadataStore(Class classToInclude) { - ApplicationContextRunner contextRunner = - new ApplicationContextRunner() - .withUserConfiguration(TestConfiguration.class) - .withPropertyValues("metadata.store.type=" + - classToInclude.getSimpleName() - .replaceFirst("MetadataStore", "") - .toLowerCase() - .replaceFirst("simple", "memory")) - .withClassLoader(filteredClassLoaderBut(classToInclude)); - contextRunner - .run(context -> { - assertThat(context.getBeansOfType(MetadataStore.class)).hasSize(1); - - assertThat(context.getBeanNamesForType(classToInclude)) - .containsOnlyOnce(Introspector.decapitalize(classToInclude.getSimpleName())); - }); + ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(TestConfiguration.class) + .withPropertyValues("metadata.store.type=" + classToInclude.getSimpleName() + .replaceFirst("MetadataStore", "") + .toLowerCase() + .replaceFirst("simple", "memory")) + .withClassLoader(filteredClassLoaderBut(classToInclude)); + contextRunner.run(context -> { + assertThat(context.getBeansOfType(MetadataStore.class)).hasSize(1); + + assertThat(context.getBeanNamesForType(classToInclude)) + .containsOnlyOnce(Introspector.decapitalize(classToInclude.getSimpleName())); + }); } static List> testMetadataStore() { @@ -98,10 +87,9 @@ static List> testMetadataStore() { } private static FilteredClassLoader filteredClassLoaderBut(Class classToInclude) { - return new FilteredClassLoader( - METADATA_STORE_CLASSES.stream() - .filter(Predicate.isEqual(classToInclude).negate()) - .toArray(Class[]::new)); + return new FilteredClassLoader(METADATA_STORE_CLASSES.stream() + .filter(Predicate.isEqual(classToInclude).negate()) + .toArray(Class[]::new)); } @Configuration @@ -126,9 +114,8 @@ protected static class DynamoDbMockConfig { @Bean public static DynamoDbAsyncClient dynamoDB() { DynamoDbAsyncClient dynamoDb = mock(DynamoDbAsyncClient.class); - willReturn(CompletableFuture.completedFuture(DescribeTableResponse.builder().build())) - .given(dynamoDb) - .describeTable(ArgumentMatchers.>any()); + willReturn(CompletableFuture.completedFuture(DescribeTableResponse.builder().build())).given(dynamoDb) + .describeTable(ArgumentMatchers.>any()); return dynamoDb; } diff --git a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/EncoderDecoderFactoryBean.java b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/EncoderDecoderFactoryBean.java index 7cfe763c..3893c388 100644 --- a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/EncoderDecoderFactoryBean.java +++ b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/EncoderDecoderFactoryBean.java @@ -29,8 +29,7 @@ import org.springframework.util.Assert; /** - * Factory bean for an encoder/decoder based on - * {@link Encoding}. + * Factory bean for an encoder/decoder based on {@link Encoding}. * * @author Gary Russell * @author Christian Tzolov diff --git a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/Encoding.java b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/Encoding.java index d434ce54..da6ca116 100644 --- a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/Encoding.java +++ b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/Encoding.java @@ -21,6 +21,7 @@ * @author Christian Tzolov */ public enum Encoding { + /** * CRLF encoding. */ @@ -53,4 +54,5 @@ public enum Encoding { * L4 encoding. */ L4; + } diff --git a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/TcpConnectionFactoryProperties.java b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/TcpConnectionFactoryProperties.java index 6d011dc5..54f17298 100644 --- a/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/TcpConnectionFactoryProperties.java +++ b/common/spring-tcp-common/src/main/java/org/springframework/cloud/fn/common/tcp/TcpConnectionFactoryProperties.java @@ -34,8 +34,8 @@ public class TcpConnectionFactoryProperties { private int port = 1234; /** - * Perform a reverse DNS lookup on the remote IP Address; if false, - * just the IP address is included in the message headers. + * Perform a reverse DNS lookup on the remote IP Address; if false, just the IP + * address is included in the message headers. */ private boolean reverseLookup = false; @@ -93,4 +93,5 @@ public boolean isReverseLookup() { public void setReverseLookup(boolean reverseLookup) { this.reverseLookup = reverseLookup; } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AbstractGraphRunner.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AbstractGraphRunner.java index 2958df5e..1e273215 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AbstractGraphRunner.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AbstractGraphRunner.java @@ -34,8 +34,9 @@ public abstract class AbstractGraphRunner implements Function feedNames; @@ -45,8 +46,9 @@ public abstract class AbstractGraphRunner implements Function fetchNames; /** - * When set and the input takes a single feed, then the name of the input tensor is automatically mapped - * to the expected input name. E.g. no need to rename the input names explicitly. + * When set and the input takes a single feed, then the name of the input tensor is + * automatically mapped to the expected input name. E.g. no need to rename the input + * names explicitly. */ private boolean autoBinding; @@ -69,8 +71,8 @@ public Map> apply(Map> feeds) { } if (this.isAutoBinding() && (feeds.size() != 1)) { - throw new IllegalArgumentException("Feed auto-binding expects a " + - "single feed tensors but found: " + feeds); + throw new IllegalArgumentException( + "Feed auto-binding expects a " + "single feed tensors but found: " + feeds); } Session.Runner runner = this.doGetSession().runner(); @@ -127,8 +129,8 @@ public AbstractGraphRunner disableAutoBinding() { public AbstractGraphRunner enableAutoBinding() { if (this.getFeedNames().size() != 1) { - throw new IllegalArgumentException("Auto-binding is permitted for Graphs with single input feed, but " + - " found: " + this.getFeedNames()); + throw new IllegalArgumentException("Auto-binding is permitted for Graphs with single input feed, but " + + " found: " + this.getFeedNames()); } this.autoBinding = true; return this; @@ -136,7 +138,7 @@ public AbstractGraphRunner enableAutoBinding() { @Override public String toString() { - return String.format("(%s) -> (%s)", String.join(",", this.feedNames), - String.join(",", this.fetchNames)); + return String.format("(%s) -> (%s)", String.join(",", this.feedNames), String.join(",", this.fetchNames)); } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AutoCloseableSession.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AutoCloseableSession.java index 29ae1ab5..97177322 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AutoCloseableSession.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/AutoCloseableSession.java @@ -60,4 +60,5 @@ public void close() { protected void doClose() { } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/Functions.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/Functions.java index 0d2a2264..45a182c8 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/Functions.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/Functions.java @@ -33,26 +33,28 @@ private Functions() { } /** - * On every function call enrich the input tensorMap with an addition (tensorName, tensor) pair. - * + * On every function call enrich the input tensorMap with an addition (tensorName, + * tensor) pair. * @param tensorName tensor key to use in the map * @param tensor new Tensor to add to the map - * @return Returns a copy of the input tensorMap enriched with the provided (tensorName, tensor). + * @return Returns a copy of the input tensorMap enriched with the provided + * (tensorName, tensor). */ - public static Function>, Map>> enrichWith( - String tensorName, Tensor tensor) { + public static Function>, Map>> enrichWith(String tensorName, + Tensor tensor) { return tensorMap -> enrich(tensorMap, tensorName, tensor); } /** - * On function call retrieves a named tensor from the provided {@link GraphRunnerMemory} and uses it to enrich - * the input tensorMap. + * On function call retrieves a named tensor from the provided + * {@link GraphRunnerMemory} and uses it to enrich the input tensorMap. * @param memory GraphRunnerMemory to retrieve the tensor from * @param tensorName name of the tensor in GraphRunnerMemory to retrieve. - * @return Returns copy of the input tensorMap enriched with the tensor from the memory. + * @return Returns copy of the input tensorMap enriched with the tensor from the + * memory. */ - public static Function>, Map>> enrichFromMemory( - GraphRunnerMemory memory, String tensorName) { + public static Function>, Map>> enrichFromMemory(GraphRunnerMemory memory, + String tensorName) { return tensorMap -> enrich(tensorMap, tensorName, memory.getTensorMap().get(tensorName)); } @@ -64,10 +66,10 @@ private static Map> enrich(Map> inputTensorM /** * Renames the tensor names in the incoming tensorMap with the providing mappings. - * - * @param mapping Pairs of From and To names. E.g. fromName1, toName1, fromName2, toName2, ... fromNameN, toNameN - * Must be an even number. - * @return Map that renames the input tensorMap entries according to the mapping provided + * @param mapping Pairs of From and To names. E.g. fromName1, toName1, fromName2, + * toName2, ... fromNameN, toNameN Must be an even number. + * @return Map that renames the input tensorMap entries according to the mapping + * provided */ public static Function>, Map>> rename(String... mapping) { @@ -76,11 +78,10 @@ public static Function>, Map>> rename(St mappingMap.put(mapping[i], mapping[i + 1]); } - return tensorMap -> tensorMap.entrySet().stream() - .filter(e -> mappingMap.containsKey(e.getKey())) - .collect(Collectors.toMap( - kv -> mappingMap.get(kv.getKey()), - kv -> kv.getValue() - )); + return tensorMap -> tensorMap.entrySet() + .stream() + .filter(e -> mappingMap.containsKey(e.getKey())) + .collect(Collectors.toMap(kv -> mappingMap.get(kv.getKey()), kv -> kv.getValue())); } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphDefinition.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphDefinition.java index 1549df2f..a9d93649 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphDefinition.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphDefinition.java @@ -23,5 +23,7 @@ */ @FunctionalInterface public interface GraphDefinition { + void defineGraph(Ops tf); + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunner.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunner.java index e2df225d..684ac333 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunner.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunner.java @@ -24,13 +24,13 @@ import org.tensorflow.Session; import org.tensorflow.op.Ops; - /** * @author Christian Tzolov */ public class GraphRunner extends AbstractGraphRunner implements AutoCloseable { private SavedModelBundle savedModelBundle; + private AutoCloseableSession autoCloseableSession; public GraphRunner(List feedNames, String fetchedName) { @@ -49,7 +49,6 @@ public GraphRunner(List feedNames, List fetchedNames) { super(feedNames, fetchedNames); } - @Override public Session doGetSession() { @@ -69,8 +68,8 @@ public Session doGetSession() { } public GraphRunner withGraphDefinition(GraphDefinition graphDefinition) { - Validate.isTrue(this.savedModelBundle == null, "Either SavedModel or GraphDefinition can be set! " + - "SavedModelBundle is found: " + this.savedModelBundle); + Validate.isTrue(this.savedModelBundle == null, "Either SavedModel or GraphDefinition can be set! " + + "SavedModelBundle is found: " + this.savedModelBundle); this.autoCloseableSession = new AutoCloseableSession() { @Override @@ -83,8 +82,8 @@ protected void doGraphDefinition(Ops tf) { } public GraphRunner withSavedModel(String savedModelDir, String... tags) { - Validate.isTrue(this.autoCloseableSession == null, "Either SavedModel or GraphDefinition can be set! " + - "AutoCloseableSession is found: " + this.autoCloseableSession); + Validate.isTrue(this.autoCloseableSession == null, "Either SavedModel or GraphDefinition can be set! " + + "AutoCloseableSession is found: " + this.autoCloseableSession); this.savedModelBundle = SavedModelBundle.load(savedModelDir, tags); return this; } @@ -104,4 +103,5 @@ public void close() { this.autoCloseableSession.close(); } } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunnerMemory.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunnerMemory.java index 41a5acf8..3442cb41 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunnerMemory.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/GraphRunnerMemory.java @@ -26,7 +26,6 @@ import org.springframework.cloud.fn.common.tensorflow.util.AutoCloseables; - /** * Keeps all tensorMap input parameters. */ @@ -47,7 +46,7 @@ public Map> apply(Map> tensorMap) { @Override public void close() { AutoCloseables.all(this.tensorMap.get()); - //this.tensorMap.get().clear(); + // this.tensorMap.get().clear(); } -} +} diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/ProtoBufGraphDefinition.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/ProtoBufGraphDefinition.java index e79be4b1..dae5c07f 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/ProtoBufGraphDefinition.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/ProtoBufGraphDefinition.java @@ -58,12 +58,12 @@ public void defineGraph(Ops tf) { : new ModelExtractor().getModel(this.modelLocation); // Import the pre-trained model ((Graph) tf.scope().env()).importGraphDef(model); - //try { - // ((Graph) tf.scope().env()).importGraphDef(GraphDef.parseFrom(model)); - //} - //catch (InvalidProtocolBufferException e) { - // throw new RuntimeException(e); - //} + // try { + // ((Graph) tf.scope().env()).importGraphDef(GraphDef.parseFrom(model)); + // } + // catch (InvalidProtocolBufferException e) { + // throw new RuntimeException(e); + // } Graph graph = ((Graph) tf.scope().env()); Iterator ops = graph.operations(); @@ -71,4 +71,5 @@ public void defineGraph(Ops tf) { System.out.println(ops.next().name()); } } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/GraphicsUtils.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/GraphicsUtils.java index d1e7a64f..f699b604 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/GraphicsUtils.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/GraphicsUtils.java @@ -38,10 +38,10 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; - /** - * Utility class used to provide some handy image manipulation functions. Among others it can provide contrast colors - * for image annotation labels and bounding boxes as well as functionality to draw later. + * Utility class used to provide some handy image manipulation functions. Among others it + * can provide contrast colors for image annotation labels and bounding boxes as well as + * functionality to draw later. * * @author Christian Tzolov */ @@ -70,295 +70,434 @@ private GraphicsUtils() { */ public static final int TITLE_OFFSET = 3; - /** * Predefined contrasting colors used when drawing multiple objects in the same image. */ public static final Color aliceblue = new Color(240, 248, 255); /* color */ + /** Color. **/ public static final Color antiquewhite = new Color(250, 235, 215); + /** Color. **/ public static final Color aqua = new Color(0, 255, 255); // color + /** Color. **/ public static final Color aquamarine = new Color(127, 255, 212); // color + /** Color. **/ public static final Color azure = new Color(240, 255, 255); // color + /** Color. **/ public static final Color beige = new Color(245, 245, 220); // color + /** Color. **/ public static final Color bisque = new Color(255, 228, 196); + /** Color. **/ public static final Color black = new Color(0, 0, 0); + /** Color. **/ public static final Color blanchedalmond = new Color(255, 255, 205); + /** Color. **/ public static final Color blue = new Color(0, 0, 255); + /** Color. **/ public static final Color blueviolet = new Color(138, 43, 226); + /** Color. **/ public static final Color brown = new Color(165, 42, 42); + /** Color. **/ public static final Color burlywood = new Color(222, 184, 135); + /** Color. **/ public static final Color cadetblue = new Color(95, 158, 160); + /** Color. **/ public static final Color chartreuse = new Color(127, 255, 0); + /** Color. **/ public static final Color chocolate = new Color(210, 105, 30); + /** Color. **/ public static final Color coral = new Color(255, 127, 80); + /** Color. **/ public static final Color cornflowerblue = new Color(100, 149, 237); + /** Color. **/ public static final Color cornsilk = new Color(255, 248, 220); + /** Color. **/ public static final Color crimson = new Color(220, 20, 60); + /** Color. **/ public static final Color cyan = new Color(0, 255, 255); + /** Color. **/ public static final Color darkblue = new Color(0, 0, 139); + /** Color. **/ public static final Color darkcyan = new Color(0, 139, 139); + /** Color. **/ public static final Color darkgoldenrod = new Color(184, 134, 11); + /** Color. **/ public static final Color darkgray = new Color(169, 169, 169); + /** Color. **/ public static final Color darkgreen = new Color(0, 100, 0); + /** Color. **/ public static final Color darkkhaki = new Color(189, 183, 107); + /** Color. **/ public static final Color darkmagenta = new Color(139, 0, 139); + /** Color. **/ public static final Color darkolivegreen = new Color(85, 107, 47); + /** Color. **/ public static final Color darkorange = new Color(255, 140, 0); + /** Color. **/ public static final Color darkorchid = new Color(153, 50, 204); + /** Color. **/ public static final Color darkred = new Color(139, 0, 0); + /** Color. **/ public static final Color darksalmon = new Color(233, 150, 122); + /** Color. **/ public static final Color darkseagreen = new Color(143, 188, 143); + /** Color. **/ public static final Color darkslateblue = new Color(72, 61, 139); + /** Color. **/ public static final Color darkslategray = new Color(47, 79, 79); + /** Color. **/ public static final Color darkturquoise = new Color(0, 206, 209); + /** Color. **/ public static final Color darkviolet = new Color(148, 0, 211); + /** Color. **/ public static final Color deeppink = new Color(255, 20, 147); + /** Color. **/ public static final Color deepskyblue = new Color(0, 191, 255); + /** Color. **/ public static final Color dimgray = new Color(105, 105, 105); + /** Color. **/ public static final Color dodgerblue = new Color(30, 144, 255); + /** Color. **/ public static final Color firebrick = new Color(178, 34, 34); + /** Color. **/ public static final Color floralwhite = new Color(255, 250, 240); + /** Color. **/ public static final Color forestgreen = new Color(34, 139, 34); + /** Color. **/ public static final Color fuchsia = new Color(255, 0, 255); + /** Color. **/ public static final Color gainsboro = new Color(220, 220, 220); + /** Color. **/ public static final Color ghostwhite = new Color(248, 248, 255); + /** Color. **/ public static final Color gold = new Color(255, 215, 0); + /** Color. **/ public static final Color goldenrod = new Color(218, 165, 32); + /** Color. **/ public static final Color gray = new Color(128, 128, 128); + /** Color. **/ public static final Color green = new Color(0, 128, 0); + /** Color. **/ public static final Color greenyellow = new Color(173, 255, 47); + /** Color. **/ public static final Color honeydew = new Color(240, 255, 240); + /** Color. **/ public static final Color hotpink = new Color(255, 105, 180); + /** Color. **/ public static final Color indianred = new Color(205, 92, 92); + /** Color. **/ public static final Color indigo = new Color(75, 0, 130); + /** Color. **/ public static final Color ivory = new Color(255, 240, 240); + /** Color. **/ public static final Color khaki = new Color(240, 230, 140); + /** Color. **/ public static final Color lavender = new Color(230, 230, 250); + /** Color. **/ public static final Color lavenderblush = new Color(255, 240, 245); + /** Color. **/ public static final Color lawngreen = new Color(124, 252, 0); + /** Color. **/ public static final Color lemonchiffon = new Color(255, 250, 205); + /** Color. **/ public static final Color lightblue = new Color(173, 216, 230); + /** Color. **/ public static final Color lightcoral = new Color(240, 128, 128); + /** Color. **/ public static final Color lightcyan = new Color(224, 255, 255); + /** Color. **/ public static final Color lightgoldenrodyellow = new Color(250, 250, 210); + /** Color. **/ public static final Color lightgreen = new Color(144, 238, 144); + /** Color. **/ public static final Color lightgrey = new Color(211, 211, 211); + /** Color. **/ public static final Color lightpink = new Color(255, 182, 193); + /** Color. **/ public static final Color lightsalmon = new Color(255, 160, 122); + /** Color. **/ public static final Color lightseagreen = new Color(32, 178, 170); + /** Color. **/ public static final Color lightskyblue = new Color(135, 206, 250); + /** Color. **/ public static final Color lightslategray = new Color(119, 136, 153); + /** Color. **/ public static final Color lightsteelblue = new Color(176, 196, 222); + /** Color. **/ public static final Color lightyellow = new Color(255, 255, 224); + /** Color. **/ public static final Color lime = new Color(0, 255, 0); + /** Color. **/ public static final Color limegreen = new Color(50, 205, 50); + /** Color. **/ public static final Color linen = new Color(250, 240, 230); + /** Color. **/ public static final Color magenta = new Color(255, 0, 255); + /** Color. **/ public static final Color maroon = new Color(128, 0, 0); + /** Color. **/ public static final Color mediumaquamarine = new Color(102, 205, 170); + /** Color. **/ public static final Color mediumblue = new Color(0, 0, 205); + /** Color. **/ public static final Color mediumorchid = new Color(186, 85, 211); + /** Color. **/ public static final Color mediumpurple = new Color(147, 112, 219); + /** Color. **/ public static final Color mediumseagreen = new Color(60, 179, 113); + /** Color. **/ public static final Color mediumslateblue = new Color(123, 104, 238); + /** Color. **/ public static final Color mediumspringgreen = new Color(0, 250, 154); + /** Color. **/ public static final Color mediumturquoise = new Color(72, 209, 204); + /** Color. **/ public static final Color mediumvioletred = new Color(199, 21, 133); + /** Color. **/ public static final Color midnightblue = new Color(25, 25, 112); + /** Color. **/ public static final Color mintcream = new Color(245, 255, 250); + /** Color. **/ public static final Color mistyrose = new Color(255, 228, 225); + /** Color. **/ public static final Color mocassin = new Color(255, 228, 181); + /** Color. **/ public static final Color navajowhite = new Color(255, 222, 173); + /** Color. **/ public static final Color navy = new Color(0, 0, 128); + /** Color. **/ public static final Color oldlace = new Color(253, 245, 230); + /** Color. **/ public static final Color olive = new Color(128, 128, 0); + /** Color. **/ public static final Color olivedrab = new Color(107, 142, 35); + /** Color. **/ public static final Color orange = new Color(255, 165, 0); + /** Color. **/ public static final Color orangered = new Color(255, 69, 0); + /** Color. **/ public static final Color orchid = new Color(218, 112, 214); + /** Color. **/ public static final Color palegoldenrod = new Color(238, 232, 170); + /** Color. **/ public static final Color palegreen = new Color(152, 251, 152); + /** Color. **/ public static final Color paleturquoise = new Color(175, 238, 238); + /** Color. **/ public static final Color palevioletred = new Color(219, 112, 147); + /** Color. **/ public static final Color papayawhip = new Color(255, 239, 213); + /** Color. **/ public static final Color peachpuff = new Color(255, 218, 185); + /** Color. **/ public static final Color peru = new Color(205, 133, 63); + /** Color. **/ public static final Color pink = new Color(255, 192, 203); + /** Color. **/ public static final Color plum = new Color(221, 160, 221); + /** Color. **/ public static final Color powderblue = new Color(176, 224, 230); + /** Color. **/ public static final Color purple = new Color(128, 0, 128); + /** Color. **/ public static final Color red = new Color(255, 0, 0); + /** Color. **/ public static final Color rosybrown = new Color(188, 143, 143); + /** Color. **/ public static final Color royalblue = new Color(65, 105, 225); + /** Color. **/ public static final Color saddlebrown = new Color(139, 69, 19); + /** Color. **/ public static final Color salmon = new Color(250, 128, 114); + /** Color. **/ public static final Color sandybrown = new Color(244, 164, 96); + /** Color. **/ public static final Color seagreen = new Color(46, 139, 87); + /** Color. **/ public static final Color seashell = new Color(255, 245, 238); + /** Color. **/ public static final Color sienna = new Color(160, 82, 45); + /** Color. **/ public static final Color silver = new Color(192, 192, 192); + /** Color. **/ public static final Color skyblue = new Color(135, 206, 235); + /** Color. **/ public static final Color slateblue = new Color(106, 90, 205); + /** Color. **/ public static final Color slategray = new Color(112, 128, 144); + /** Color. **/ public static final Color snow = new Color(255, 250, 250); + /** Color. **/ public static final Color springgreen = new Color(0, 255, 127); + /** Color. **/ public static final Color steelblue = new Color(70, 138, 180); + /** Color. **/ public static final Color tan = new Color(210, 180, 140); + /** Color. **/ public static final Color teal = new Color(0, 128, 128); + /** Color. **/ public static final Color thistle = new Color(216, 191, 216); + /** Color. **/ public static final Color tomato = new Color(253, 99, 71); + /** Color. **/ public static final Color turquoise = new Color(64, 224, 208); + /** Color. **/ public static final Color violet = new Color(238, 130, 238); + /** Color. **/ public static final Color wheat = new Color(245, 222, 179); + /** Color. **/ public static final Color white = new Color(255, 255, 255); + /** Color. **/ public static final Color whitesmoke = new Color(245, 245, 245); + /** Color. **/ public static final Color yellow = new Color(255, 255, 0); + /** Color. **/ public static final Color yellowgreen = new Color(154, 205, 50); /** * Limbs color list. */ - public static final Color[] LIMBS_COLORS = new Color[] { - new Color(153, 0, 0), // 0 (1 -> 2) + public static final Color[] LIMBS_COLORS = new Color[] { new Color(153, 0, 0), // 0 (1 + // -> + // 2) new Color(153, 51, 0), // 1 (1 -> 5) new Color(153, 102, 0), // 2 (2 -> 3) new Color(153, 153, 0), // 3 (3 -> 4) @@ -383,42 +522,31 @@ private GraphicsUtils() { /** * Constants lists. */ - private static final Color[] CLASS_COLOR = new Color[] { - aliceblue, chartreuse, aqua, aquamarine, azure, beige, bisque, - blanchedalmond, blueviolet, burlywood, cadetblue, antiquewhite, - chocolate, coral, cornflowerblue, cornsilk, crimson, cyan, - darkcyan, darkgoldenrod, darkgray, darkkhaki, darkorange, - darkorchid, darksalmon, darkseagreen, darkturquoise, darkviolet, - deeppink, deepskyblue, dodgerblue, firebrick, floralwhite, - forestgreen, fuchsia, gainsboro, ghostwhite, gold, goldenrod, - salmon, tan, honeydew, hotpink, indianred, ivory, khaki, - lavender, lavenderblush, lawngreen, lemonchiffon, lightblue, - lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, lightgrey, - lightgreen, lightpink, lightsalmon, lightseagreen, lightskyblue, - lightslategray, lightslategray, lightsteelblue, lightyellow, lime, - limegreen, linen, magenta, mediumaquamarine, mediumorchid, - mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, - mediumturquoise, mediumvioletred, mintcream, mistyrose, mocassin, - navajowhite, oldlace, olive, olivedrab, orange, orangered, - orchid, palegoldenrod, palegreen, paleturquoise, palevioletred, - papayawhip, peachpuff, peru, pink, plum, powderblue, purple, - red, rosybrown, royalblue, saddlebrown, green, sandybrown, - seagreen, seashell, sienna, silver, skyblue, slateblue, - slategray, slategray, snow, springgreen, steelblue, greenyellow, - teal, thistle, tomato, turquoise, violet, wheat, white, - whitesmoke, yellow, yellowgreen - }; + private static final Color[] CLASS_COLOR = new Color[] { aliceblue, chartreuse, aqua, aquamarine, azure, beige, + bisque, blanchedalmond, blueviolet, burlywood, cadetblue, antiquewhite, chocolate, coral, cornflowerblue, + cornsilk, crimson, cyan, darkcyan, darkgoldenrod, darkgray, darkkhaki, darkorange, darkorchid, darksalmon, + darkseagreen, darkturquoise, darkviolet, deeppink, deepskyblue, dodgerblue, firebrick, floralwhite, + forestgreen, fuchsia, gainsboro, ghostwhite, gold, goldenrod, salmon, tan, honeydew, hotpink, indianred, + ivory, khaki, lavender, lavenderblush, lawngreen, lemonchiffon, lightblue, lightcoral, lightcyan, + lightgoldenrodyellow, lightgreen, lightgrey, lightgreen, lightpink, lightsalmon, lightseagreen, + lightskyblue, lightslategray, lightslategray, lightsteelblue, lightyellow, lime, limegreen, linen, magenta, + mediumaquamarine, mediumorchid, mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, + mediumturquoise, mediumvioletred, mintcream, mistyrose, mocassin, navajowhite, oldlace, olive, olivedrab, + orange, orangered, orchid, palegoldenrod, palegreen, paleturquoise, palevioletred, papayawhip, peachpuff, + peru, pink, plum, powderblue, purple, red, rosybrown, royalblue, saddlebrown, green, sandybrown, seagreen, + seashell, sienna, silver, skyblue, slateblue, slategray, slategray, snow, springgreen, steelblue, + greenyellow, teal, thistle, tomato, turquoise, violet, wheat, white, whitesmoke, yellow, yellowgreen }; /** * List of constants. */ - public static final Color[] CLASS_COLOR2 = new Color[] { - yellow, yellowgreen, turquoise, springgreen, skyblue, slateblue, red, violet, olivedrab, royalblue, - darkorange, mediumblue, deeppink, chartreuse, orchid, palegreen, aqua, orange, navy - }; + public static final Color[] CLASS_COLOR2 = new Color[] { yellow, yellowgreen, turquoise, springgreen, skyblue, + slateblue, red, violet, olivedrab, royalblue, darkorange, mediumblue, deeppink, chartreuse, orchid, + palegreen, aqua, orange, navy }; /** - * Return different color for each Id. It rotates when the ID exceeds the number of predefined colors. + * Return different color for each Id. It rotates when the ID exceeds the number of + * predefined colors. * @param id the unique id to pick color for. * @return a distinct color computed from the input #id */ @@ -427,17 +555,18 @@ public static Color getClassColor(int id) { } /** - * Augments the input image fromMemory a labeled rectangle (e.g. bounding box) fromMemory coordinates: (x1, y1, x2, y2). - * + * Augments the input image fromMemory a labeled rectangle (e.g. bounding box) + * fromMemory coordinates: (x1, y1, x2, y2). * @param image Input image to be augmented fromMemory labeled rectangle. - * @param cid Unique id used to select the color of the rectangle. Used only if the colorAgnostic is set to false. + * @param cid Unique id used to select the color of the rectangle. Used only if the + * colorAgnostic is set to false. * @param title rectangle title * @param x1 top left corner for the bounding box * @param y1 top left corner for the bounding box * @param x2 bottom right corner for the bounding box * @param y2 bottom right corner for the bounding box - * @param colorAgnostic If set to false the cid is used to select the bounding box color. Uses the - * AGNOSTIC_COLOR otherwise. + * @param colorAgnostic If set to false the cid is used to select the bounding box + * color. Uses the AGNOSTIC_COLOR otherwise. */ public static void drawBoundingBox(BufferedImage image, int cid, String title, int x1, int y1, int x2, int y2, boolean colorAgnostic) { @@ -459,8 +588,7 @@ public static void drawBoundingBox(BufferedImage image, int cid, String title, i Rectangle2D rect = fontMetrics.getStringBounds(title, g); g.setColor(labelColor); - g.fillRect(x1, y1 - fontMetrics.getAscent(), - (int) rect.getWidth() + 2 * TITLE_OFFSET, (int) rect.getHeight()); + g.fillRect(x1, y1 - fontMetrics.getAscent(), (int) rect.getWidth() + 2 * TITLE_OFFSET, (int) rect.getHeight()); g.setColor(getTextColor(labelColor)); g.drawString(title, x1 + TITLE_OFFSET, y1); @@ -472,13 +600,13 @@ public static void drawBoundingBox(BufferedImage image, int cid, String title, i * @return a text color, that contrast to the given background color. */ private static Color getTextColor(Color backGroundColor) { - double y = (299 * backGroundColor.getRed() + 587 * backGroundColor.getGreen() + - 114 * backGroundColor.getBlue()) / 1000; + double y = (299 * backGroundColor.getRed() + 587 * backGroundColor.getGreen() + 114 * backGroundColor.getBlue()) + / 1000; return y >= 128 ? Color.black : Color.white; } - public static BufferedImage createMaskImage(float[][] maskPixels, - int scaledWidth, int scaledHeight, Color maskColor) { + public static BufferedImage createMaskImage(float[][] maskPixels, int scaledWidth, int scaledHeight, + Color maskColor) { int maskWidth = maskPixels.length; int maskHeight = maskPixels[0].length; @@ -500,7 +628,6 @@ public static BufferedImage createMaskImage(float[][] maskPixels, /** * Converts an gray scale (e.g. value between 0 to 1) into ARGB. - * * @param grayScale - value between 0 and 1 * @param maskColor - desired mask color * @return Returns a ARGB color based on the grayscale and the mask colors @@ -518,14 +645,14 @@ private static int grayScaleToARGB(float grayScale, Color maskColor) { } private static float col(int channelColor, float grayScale) { - //return ((float) channelColor / 255) * grayScale; + // return ((float) channelColor / 255) * grayScale; return ((float) channelColor / 255); } public static BufferedImage toBufferedImage(Image img) { - //if (img instanceof BufferedImage) { - // return (BufferedImage) img; - //} + // if (img instanceof BufferedImage) { + // return (BufferedImage) img; + // } // Create a buffered image fromMemory transparency BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); @@ -540,22 +667,20 @@ public static BufferedImage toBufferedImage(Image img) { } public static BufferedImage overlayImages(BufferedImage bgImage, BufferedImage fgImage, int fgX, int fgY) { - // Foreground image width and height cannot be greater than background image width and height. - if (fgImage.getHeight() > bgImage.getHeight() - || fgImage.getWidth() > fgImage.getWidth()) { - throw new IllegalArgumentException( - "Foreground Image Is Bigger In One or Both Dimensions" - + "nCannot proceed fromMemory overlay." - + "nn Please use smaller Image for foreground"); + // Foreground image width and height cannot be greater than background image width + // and height. + if (fgImage.getHeight() > bgImage.getHeight() || fgImage.getWidth() > fgImage.getWidth()) { + throw new IllegalArgumentException("Foreground Image Is Bigger In One or Both Dimensions" + + "nCannot proceed fromMemory overlay." + "nn Please use smaller Image for foreground"); } - // Create a Graphics from the background image + // Create a Graphics from the background image Graphics2D g = bgImage.createGraphics(); - //Set Antialias Rendering + // Set Antialias Rendering g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - //Draw background image at location (0,0) + // Draw background image at location (0,0) g.drawImage(bgImage, 0, 0, null); // Draw foreground image at location (fgX,fgy) @@ -567,7 +692,6 @@ public static BufferedImage overlayImages(BufferedImage bgImage, BufferedImage f /** * Convert {@link BufferedImage} to byte array. - * * @param image the image to be converted * @param format the output image format * @return New array of bytes @@ -594,7 +718,6 @@ public static byte[] toImageByteArray(BufferedImage image, String format) { } /** - * * @param bufferedImage buffer to be converted in to raw array * @return flat byte array representing the buffered image */ diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/JsonMapperFunction.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/JsonMapperFunction.java index 62463bf1..a926c68b 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/JsonMapperFunction.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/JsonMapperFunction.java @@ -43,4 +43,5 @@ public String apply(Object o) { return "ERROR"; } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/TensorFlowService.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/TensorFlowService.java index fc750bfd..d31a2eef 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/TensorFlowService.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/deprecated/TensorFlowService.java @@ -14,7 +14,6 @@ * limitations under the License. */ - package org.springframework.cloud.fn.common.tensorflow.deprecated; import java.util.HashMap; @@ -42,7 +41,9 @@ public class TensorFlowService implements Function>, Map fetchedNames; + private final boolean autoCloseFeedTensors; public TensorFlowService(Resource modelLocation, List fetchedNames) { @@ -63,18 +64,19 @@ public TensorFlowService(Resource modelLocation, List fetchedNames, bool this.autoCloseFeedTensors = autoCloseFeedTensors; this.fetchedNames = fetchedNames; Graph graph = new Graph(); - byte[] model = cacheModel ? new CachedModelExtractor().getModel(modelLocation) : new ModelExtractor().getModel(modelLocation); + byte[] model = cacheModel ? new CachedModelExtractor().getModel(modelLocation) + : new ModelExtractor().getModel(modelLocation); graph.importGraphDef(model); this.session = new Session(graph); } /** - * Evaluates a pre-trained tensorflow model (encoded as {@link Graph}). Use the feeds parameter to feed in the - * model input data and fetch-names to specify the output tensors. - * + * Evaluates a pre-trained tensorflow model (encoded as {@link Graph}). Use the feeds + * parameter to feed in the model input data and fetch-names to specify the output + * tensors. * @param feeds Named map of input tensors. - * @return Returns the computed output tensors. The names of the output tensors is defined by the fetchedNames - * argument + * @return Returns the computed output tensors. The names of the output tensors is + * defined by the fetchedNames argument */ @Override public Map> apply(Map> feeds) { @@ -128,4 +130,5 @@ public void close() { this.session.close(); } } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/AutoCloseables.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/AutoCloseables.java index 68b4ce84..48fe78d2 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/AutoCloseables.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/AutoCloseables.java @@ -25,8 +25,8 @@ import org.slf4j.LoggerFactory; /** - * Utilities for AutoCloseable classes. - * Based on the Apache Drill AutoCloseables implementation. + * Utilities for AutoCloseable classes. Based on the Apache Drill AutoCloseables + * implementation. */ public final class AutoCloseables { @@ -45,7 +45,8 @@ public static AutoCloseable all(final Map... autoClo } /** - * Closes all autoCloseables if not null and suppresses exceptions by adding them to t. + * Closes all autoCloseables if not null and suppresses exceptions by adding them to + * t. * @param t the throwable to add suppressed exception to * @param autoCloseables the closeables to close */ @@ -54,7 +55,8 @@ public static void close(Throwable t, AutoCloseable... autoCloseables) { } /** - * Closes all autoCloseables if not null and suppresses exceptions by adding them to t. + * Closes all autoCloseables if not null and suppresses exceptions by adding them to + * t. * @param t the throwable to add suppressed exception to * @param autoCloseables the closeables to close */ @@ -68,7 +70,8 @@ public static void close(Throwable t, Collection autoCl } /** - * Closes all autoCloseables if not null and suppresses subsequent exceptions if more than one. + * Closes all autoCloseables if not null and suppresses subsequent exceptions if more + * than one. * @param autoCloseables the closeables to close */ public static void close(AutoCloseable... autoCloseables) throws Exception { @@ -76,7 +79,8 @@ public static void close(AutoCloseable... autoCloseables) throws Exception { } /** - * Closes all autoCloseables if not null and suppresses subsequent exceptions if more than one. + * Closes all autoCloseables if not null and suppresses subsequent exceptions if more + * than one. * @param autoCloseables the closeables to close */ public static void close(Iterable autoCloseables) throws Exception { @@ -102,7 +106,8 @@ public static void close(Iterable autoCloseables) throw } /** - * Closes all autoCloseables entry values if not null and suppresses subsequent exceptions if more than one. + * Closes all autoCloseables entry values if not null and suppresses subsequent + * exceptions if more than one. * @param closableMaps the closeables to close */ public static void close(Map... closableMaps) throws Exception { @@ -139,15 +144,14 @@ public static void close(Map... closableMaps) throws * @param closeables - array containing auto closeables */ public static void closeSilently(AutoCloseable... closeables) { - Arrays.stream(closeables).filter(Objects::nonNull) - .forEach(target -> { - try { - target.close(); - } - catch (Exception e) { - LOGGER.warn(String.format("Exception was thrown while closing auto closeable: %s", target), e); - } - }); + Arrays.stream(closeables).filter(Objects::nonNull).forEach(target -> { + try { + target.close(); + } + catch (Exception e) { + LOGGER.warn(String.format("Exception was thrown while closing auto closeable: %s", target), e); + } + }); } } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/CachedModelExtractor.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/CachedModelExtractor.java index f3414984..c76a1b93 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/CachedModelExtractor.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/CachedModelExtractor.java @@ -30,7 +30,9 @@ import org.springframework.core.io.Resource; /** - * Extends the {@link ModelExtractor} to allow keeping a local copy (cache) of the loaded model (protobuf) files. + * Extends the {@link ModelExtractor} to allow keeping a local copy (cache) of the loaded + * model (protobuf) files. + * * @author Christian Tzolov */ public class CachedModelExtractor extends ModelExtractor { @@ -76,8 +78,8 @@ public byte[] getModel(Resource modelResource) { String fileName = modelResource.getFilename(); String fragment = modelResource.getURI().getFragment(); - File cachedFile = StringUtils.isEmpty(fragment) ? new File(rootFolder, fileName) : - new File(rootFolder, fileName + "_" + fragment); + File cachedFile = StringUtils.isEmpty(fragment) ? new File(rootFolder, fileName) + : new File(rootFolder, fileName + "_" + fragment); if (cachedFile.exists()) { logger.info("Load model " + modelResource.toString() + " from cache: " + cacheRootDirectory); return IOUtils.toByteArray(new FileInputStream(cachedFile)); @@ -104,4 +106,5 @@ public void emptyModelCache() { rootFolder.mkdirs(); } } + } diff --git a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/ModelExtractor.java b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/ModelExtractor.java index 16502410..003d323e 100644 --- a/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/ModelExtractor.java +++ b/common/spring-tensorflow-common/src/main/java/org/springframework/cloud/fn/common/tensorflow/util/ModelExtractor.java @@ -43,15 +43,16 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; - /** - * Extracts a pre-trained (frozen) Tensorflow model URI into byte array. The 'http://', 'file://' and 'classpath://' - * URI schemas are supported. + * Extracts a pre-trained (frozen) Tensorflow model URI into byte array. The 'http://', + * 'file://' and 'classpath://' URI schemas are supported. * - * Models can be extract either from raw files or form compressed archives. When extracted from an archive the model - * file name can optionally be provided as an URI fragment. For example for resource: http://myarchive.tar.gz#model.pb - * the myarchive.tar.gz is traversed to uncompress and extract the model.pb file as byte array. - * If the file name is not provided as URI fragment then the first file in the archive with extension .pb is extracted. + * Models can be extract either from raw files or form compressed archives. When extracted + * from an archive the model file name can optionally be provided as an URI fragment. For + * example for resource: http://myarchive.tar.gz#model.pb the myarchive.tar.gz is + * traversed to uncompress and extract the model.pb file as byte array. If the file name + * is not provided as URI fragment then the first file in the archive with extension .pb + * is extracted. * * @author Christian Tzolov */ @@ -60,9 +61,10 @@ public class ModelExtractor { private static final String DEFAULT_FROZEN_GRAPH_FILE_EXTENSION = ".pb"; /** - * When an archive resource if referred, but no fragment URI is provided (to specify the target file name in - * the archive) then the extractor selects the first file in the archive with the extension that match - * the frozenGraphFileExtension (defaults to .pb). + * When an archive resource if referred, but no fragment URI is provided (to specify + * the target file name in the archive) then the extractor selects the first file in + * the archive with the extension that match the frozenGraphFileExtension (defaults to + * .pb). */ public final String frozenGraphFileExtension; @@ -89,11 +91,12 @@ public byte[] getModel(Resource modelResource) { String compressor = archiveCompressor[1]; String fragment = modelResource.getURI().getFragment(); - if (StringUtils.isNotBlank(compressor)) { - try (CompressorInputStream cis = new CompressorStreamFactory().createCompressorInputStream(compressor, bi)) { + try (CompressorInputStream cis = new CompressorStreamFactory().createCompressorInputStream(compressor, + bi)) { if (StringUtils.isNotBlank(archive)) { - try (ArchiveInputStream ais = new ArchiveStreamFactory().createArchiveInputStream(archive, cis)) { + try (ArchiveInputStream ais = new ArchiveStreamFactory().createArchiveInputStream(archive, + cis)) { // Compressor fromMemory Archive return findInArchiveStream(fragment, ais); } @@ -119,22 +122,24 @@ else if (StringUtils.isNotBlank(archive)) { // Archive only } /** - * Traverses the Archive to find either an entry that matches the modelFileNameInArchive name (if not empty) or - * and entry that ends in .pb if the modelFileNameInArchive is empty. - * - * @param modelFileNameInArchive Optional name of the archive entry that represents the frozen model file. If empty - * the archive will be searched for the first entry that ends in .pb + * Traverses the Archive to find either an entry that matches the + * modelFileNameInArchive name (if not empty) or and entry that ends in .pb if the + * modelFileNameInArchive is empty. + * @param modelFileNameInArchive Optional name of the archive entry that represents + * the frozen model file. If empty the archive will be searched for the first entry + * that ends in .pb * @param archive Archive stream to be traversed * */ private byte[] findInArchiveStream(String modelFileNameInArchive, ArchiveInputStream archive) throws IOException { ArchiveEntry entry; while ((entry = archive.getNextEntry()) != null) { - //System.out.println(entry.getName() + " : " + entry.isDirectory()); + // System.out.println(entry.getName() + " : " + entry.isDirectory()); if (archive.canReadEntryData(entry) && !entry.isDirectory()) { - if ((StringUtils.isNotBlank(modelFileNameInArchive) && entry.getName().endsWith(modelFileNameInArchive)) || - (!StringUtils.isNotBlank(modelFileNameInArchive) && entry.getName().endsWith(this.frozenGraphFileExtension))) { + if ((StringUtils.isNotBlank(modelFileNameInArchive) && entry.getName().endsWith(modelFileNameInArchive)) + || (!StringUtils.isNotBlank(modelFileNameInArchive) + && entry.getName().endsWith(this.frozenGraphFileExtension))) { return IOUtils.toByteArray(archive); } } @@ -144,22 +149,20 @@ private byte[] findInArchiveStream(String modelFileNameInArchive, ArchiveInputSt /** * Detect the Archive and the Compressor from the file extension. - * * @param fileName File name with extension. - * @return Returns a tuple of the detected (Archive, Compressor). Null stands for not available - * archive or detector. The (null, null) response stands for no Archive or Compressor discovered. + * @return Returns a tuple of the detected (Archive, Compressor). Null stands for not + * available archive or detector. The (null, null) response stands for no Archive or + * Compressor discovered. */ private String[] detectArchiveAndCompressor(String fileName) { String normalizedFileName = fileName.trim().toLowerCase(); - if (normalizedFileName.endsWith(".tar.gz") - || normalizedFileName.endsWith(".tgz") + if (normalizedFileName.endsWith(".tar.gz") || normalizedFileName.endsWith(".tgz") || normalizedFileName.endsWith(".taz")) { return new String[] { ArchiveStreamFactory.TAR, CompressorStreamFactory.GZIP }; } - else if (normalizedFileName.endsWith(".tar.bz2") - || normalizedFileName.endsWith(".tbz2") + else if (normalizedFileName.endsWith(".tar.bz2") || normalizedFileName.endsWith(".tbz2") || normalizedFileName.endsWith(".tbz")) { return new String[] { ArchiveStreamFactory.TAR, CompressorStreamFactory.BZIP2 }; } @@ -175,8 +178,7 @@ else if (hasCompressor(normalizedFileName)) { else if (normalizedFileName.endsWith(".gzip")) { return new String[] { null, CompressorStreamFactory.GZIP }; } - else if (normalizedFileName.endsWith(".bz2") - || normalizedFileName.endsWith(".bz")) { + else if (normalizedFileName.endsWith(".bz2") || normalizedFileName.endsWith(".bz")) { return new String[] { null, CompressorStreamFactory.BZIP2 }; } @@ -190,7 +192,9 @@ private boolean hasArchive(String normalizedFileName) { private Optional findArchive(String normalizedFileName) { return new ArchiveStreamFactory().getInputStreamArchiveNames() - .stream().filter(arch -> normalizedFileName.endsWith("." + arch)).findFirst(); + .stream() + .filter(arch -> normalizedFileName.endsWith("." + arch)) + .findFirst(); } private boolean hasCompressor(String normalizedFileName) { @@ -199,7 +203,9 @@ private boolean hasCompressor(String normalizedFileName) { private Optional findCompressor(String normalizedFileName) { return new CompressorStreamFactory().getInputStreamCompressorNames() - .stream().filter(compressor -> normalizedFileName.endsWith("." + compressor)).findFirst(); + .stream() + .filter(compressor -> normalizedFileName.endsWith("." + compressor)) + .findFirst(); } static { @@ -219,8 +225,7 @@ public void checkClientTrusted(X509Certificate[] certs, String authType) { public void checkServerTrusted(X509Certificate[] certs, String authType) { } - } - }; + } }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); diff --git a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/EnrichFromMemory.java b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/EnrichFromMemory.java index c6faf07d..96c1ada4 100644 --- a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/EnrichFromMemory.java +++ b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/EnrichFromMemory.java @@ -28,42 +28,40 @@ public class EnrichFromMemory implements AutoCloseable { private final GraphRunner graph1; + private final GraphRunner graph2; + private final GraphRunner graph3; public EnrichFromMemory() { - this.graph1 = new GraphRunner("x1", "y1") - .withGraphDefinition(tf -> tf.withName("y1").math.mul( - tf.withName("x1").placeholder(Integer.class), - tf.constant(10))); + this.graph1 = new GraphRunner("x1", "y1").withGraphDefinition( + tf -> tf.withName("y1").math.mul(tf.withName("x1").placeholder(Integer.class), tf.constant(10))); - this.graph2 = new GraphRunner("x2", "y2") - .withGraphDefinition(tf -> tf.withName("y2").math.mul( - tf.withName("x2").placeholder(Integer.class), - tf.constant(20))); + this.graph2 = new GraphRunner("x2", "y2").withGraphDefinition( + tf -> tf.withName("y2").math.mul(tf.withName("x2").placeholder(Integer.class), tf.constant(20))); this.graph3 = new GraphRunner(Arrays.asList("x31", "x32"), Arrays.asList("y3")) - .withGraphDefinition(tf -> tf.withName("y3").math.add( - tf.withName("x31").placeholder(Integer.class), - tf.withName("x32").placeholder(Integer.class))); + .withGraphDefinition(tf -> tf.withName("y3").math.add(tf.withName("x31").placeholder(Integer.class), + tf.withName("x32").placeholder(Integer.class))); } public int compute(Integer input) { - try ( - Tensor x = Tensor.create(input); - GraphRunnerMemory memory = new GraphRunnerMemory(); - ) { - - Map> result = - this.graph1.andThen(memory) - .andThen(graph2).andThen(memory) - .andThen(Functions.enrichFromMemory(memory, "y1")) // retrieves the graph1's y1 output and adds it as a parameter with the same name - .andThen(Functions.rename( - "y1", "x31", // renames the input y1 into x31 - "y2", "x32" // renames the input y2 into x32 - )) - .andThen(graph3).andThen(memory) - .apply(Collections.singletonMap("x", x)); + try (Tensor x = Tensor.create(input); GraphRunnerMemory memory = new GraphRunnerMemory();) { + + Map> result = this.graph1.andThen(memory) + .andThen(graph2) + .andThen(memory) + .andThen(Functions.enrichFromMemory(memory, "y1")) // retrieves the + // graph1's y1 output + // and adds it as a + // parameter with the + // same name + .andThen(Functions.rename("y1", "x31", // renames the input y1 into x31 + "y2", "x32" // renames the input y2 into x32 + )) + .andThen(graph3) + .andThen(memory) + .apply(Collections.singletonMap("x", x)); memory.getTensorMap().entrySet().forEach(e -> System.out.println(" " + e)); @@ -85,5 +83,5 @@ public static void main(String[] args) { } } } -} +} diff --git a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionComposition.java b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionComposition.java index 192751c8..c80dda11 100644 --- a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionComposition.java +++ b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionComposition.java @@ -35,17 +35,11 @@ private FunctionComposition() { // y1 = x1 * 2 , where x1 == x // y2 = x2 + 20 , where x2 == y1 and y = y2 public static void main(String[] args) { - try ( - GraphRunner graph1 = new GraphRunner("x1", "y1") - .withGraphDefinition(tf -> tf.withName("y1").math.mul( - tf.withName("x1").placeholder(Integer.class), - tf.constant(2))); - GraphRunner graph2 = new GraphRunner("x2", "y2") - .withGraphDefinition(tf -> tf.withName("y2").math.add( - tf.withName("x2").placeholder(Integer.class), - tf.constant(20))); - Tensor x = Tensor.create(10); - ) { + try (GraphRunner graph1 = new GraphRunner("x1", "y1").withGraphDefinition( + tf -> tf.withName("y1").math.mul(tf.withName("x1").placeholder(Integer.class), tf.constant(2))); + GraphRunner graph2 = new GraphRunner("x2", "y2").withGraphDefinition(tf -> tf.withName("y2").math + .add(tf.withName("x2").placeholder(Integer.class), tf.constant(20))); + Tensor x = Tensor.create(10);) { Map> result = graph1.andThen(graph2).apply(Collections.singletonMap("x", x)); @@ -54,5 +48,5 @@ public static void main(String[] args) { } } -} +} diff --git a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionCompositionMultipleInputsOutputs.java b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionCompositionMultipleInputsOutputs.java index cb233580..d8d6c38a 100644 --- a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionCompositionMultipleInputsOutputs.java +++ b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/FunctionCompositionMultipleInputsOutputs.java @@ -38,30 +38,24 @@ private FunctionCompositionMultipleInputsOutputs() { // y12 = x1 * 3 , where x1 == x // y2 = x21 + x22 , where x21 == y11, x22 == y12 and y == y2 public static void main(String[] args) { - try ( - GraphRunner graph1 = new GraphRunner(Arrays.asList("x1"), Arrays.asList("y11", "y12")) - .withGraphDefinition(tf -> { - Placeholder x1 = tf.withName("x1").placeholder(Integer.class); - tf.withName("y11").math.mul(x1, tf.constant(2)); - tf.withName("y12").math.mul(x1, tf.constant(3)); - }); + try (GraphRunner graph1 = new GraphRunner(Arrays.asList("x1"), Arrays.asList("y11", "y12")) + .withGraphDefinition(tf -> { + Placeholder x1 = tf.withName("x1").placeholder(Integer.class); + tf.withName("y11").math.mul(x1, tf.constant(2)); + tf.withName("y12").math.mul(x1, tf.constant(3)); + }); GraphRunner graph2 = new GraphRunner(Arrays.asList("x21", "x22"), Arrays.asList("y2")) - .withGraphDefinition(tf -> tf.withName("y2").math.add( - tf.withName("x21").placeholder(Integer.class), - tf.withName("x22").placeholder(Integer.class))); - Tensor x = Tensor.create(10); - ) { + .withGraphDefinition(tf -> tf.withName("y2").math.add(tf.withName("x21").placeholder(Integer.class), + tf.withName("x22").placeholder(Integer.class))); + Tensor x = Tensor.create(10);) { - Map> result = graph1 - .andThen(Functions.rename( - "y11", "x21", - "y12", "x22" - )) - .andThen(graph2) - .apply(Collections.singletonMap("x", x)); + Map> result = graph1.andThen(Functions.rename("y11", "x21", "y12", "x22")) + .andThen(graph2) + .apply(Collections.singletonMap("x", x)); - System.out.println("Result is: " + result.get("y2").intValue()); // Result is: 50 + System.out.println("Result is: " + result.get("y2").intValue()); // Result is: + // 50 } } -} +} diff --git a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/ReleaseTensorParameters.java b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/ReleaseTensorParameters.java index 77fe49cb..953b0a36 100644 --- a/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/ReleaseTensorParameters.java +++ b/common/spring-tensorflow-common/src/test/java/org/springframework/cloud/fn/common/tensorflow/ReleaseTensorParameters.java @@ -27,31 +27,25 @@ public class ReleaseTensorParameters implements AutoCloseable { private final GraphRunner graph1; + private final GraphRunner graph2; public ReleaseTensorParameters() { - this.graph1 = new GraphRunner("x1", "y1") - .withGraphDefinition(tf -> tf.withName("y1").math.mul( - tf.withName("x1").placeholder(Integer.class), - tf.constant(2))); - - this.graph2 = new GraphRunner("x2", "y2") - .withGraphDefinition(tf -> tf.withName("y2").math.add( - tf.withName("x2").placeholder(Integer.class), - tf.constant(20))); + this.graph1 = new GraphRunner("x1", "y1").withGraphDefinition( + tf -> tf.withName("y1").math.mul(tf.withName("x1").placeholder(Integer.class), tf.constant(2))); + + this.graph2 = new GraphRunner("x2", "y2").withGraphDefinition( + tf -> tf.withName("y2").math.add(tf.withName("x2").placeholder(Integer.class), tf.constant(20))); } // y = (x * 2) + 20 public int compute(Integer input) { - try ( - Tensor x = Tensor.create(input); - GraphRunnerMemory memory = new GraphRunnerMemory(); - ) { + try (Tensor x = Tensor.create(input); GraphRunnerMemory memory = new GraphRunnerMemory();) { - Map> result = - this.graph1.andThen(memory) - .andThen(graph2).andThen(memory) - .apply(Collections.singletonMap("x", x)); + Map> result = this.graph1.andThen(memory) + .andThen(graph2) + .andThen(memory) + .apply(Collections.singletonMap("x", x)); memory.getTensorMap().entrySet().forEach(e -> System.out.println(" " + e)); @@ -73,5 +67,5 @@ public static void main(String[] args) { } } } -} +} diff --git a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/Cursor.java b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/Cursor.java index ba6de357..b348c6d6 100644 --- a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/Cursor.java +++ b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/Cursor.java @@ -20,6 +20,7 @@ * @author Christian Tzolov */ public class Cursor { + private long cursor = -1; public long getCursor() { @@ -34,4 +35,5 @@ public void updateCursor(long newCursor) { public String toString() { return "Cursor{cursor=" + cursor + '}'; } + } diff --git a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionConfiguration.java b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionConfiguration.java index b5b65c78..e9c48dbb 100644 --- a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionConfiguration.java +++ b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionConfiguration.java @@ -40,7 +40,6 @@ import org.springframework.util.MimeTypeUtils; /** - * * @author Christian Tzolov */ @Configuration @@ -67,13 +66,12 @@ public TwitterStream twitterStream(twitter4j.conf.Configuration configuration) { @Bean public Function toConfigurationBuilder() { - return properties -> new ConfigurationBuilder() - .setJSONStoreEnabled(properties.isRawJson()) - .setDebugEnabled(properties.isDebugEnabled()) - .setOAuthConsumerKey(properties.getConsumerKey()) - .setOAuthConsumerSecret(properties.getConsumerSecret()) - .setOAuthAccessToken(properties.getAccessToken()) - .setOAuthAccessTokenSecret(properties.getAccessTokenSecret()); + return properties -> new ConfigurationBuilder().setJSONStoreEnabled(properties.isRawJson()) + .setDebugEnabled(properties.isDebugEnabled()) + .setOAuthConsumerKey(properties.getConsumerKey()) + .setOAuthConsumerSecret(properties.getConsumerSecret()) + .setOAuthAccessToken(properties.getAccessToken()) + .setOAuthAccessTokenSecret(properties.getAccessTokenSecret()); } @Bean @@ -82,10 +80,9 @@ public Function> json(ObjectMapper mapper) { try { String json = mapper.writeValueAsString(objects); - return MessageBuilder - .withPayload(json.getBytes()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE) - .build(); + return MessageBuilder.withPayload(json.getBytes()) + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE) + .build(); } catch (JsonProcessingException e) { logger.error("Status to JSON conversion error!", e); @@ -95,12 +92,12 @@ public Function> json(ObjectMapper mapper) { } /** - * Retrieves the raw JSON form of the provided object. - * - * Note that raw JSON forms can be retrieved only from the same thread invoked the last method - * call and will become inaccessible once another method call. + * Retrieves the raw JSON form of the provided object. * - * @return Function that can retrieve the raw JSON object from the objects returned by the Twitter4J's APIs. + * Note that raw JSON forms can be retrieved only from the same thread invoked the + * last method call and will become inaccessible once another method call. + * @return Function that can retrieve the raw JSON object from the objects returned by + * the Twitter4J's APIs. */ @Bean public Function rawJsonExtractor() { @@ -124,4 +121,5 @@ public Function> managedJson(TwitterConnectionProperties Function rawJsonExtractor, Function> json) { return list -> (properties.isRawJson()) ? rawJsonExtractor.andThen(json).apply(list) : json.apply(list); } + } diff --git a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionProperties.java b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionProperties.java index dd8e5df0..bc0fdf67 100644 --- a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionProperties.java +++ b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/TwitterConnectionProperties.java @@ -21,7 +21,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -60,8 +59,8 @@ public class TwitterConnectionProperties { /** * Enable caching the original (raw) JSON objects as returned by the Twitter APIs. - * When set to False the result will use the Twitter4J's json representations. - * When set to True the result will use the original Twitter APISs json representations. + * When set to False the result will use the Twitter4J's json representations. When + * set to True the result will use the original Twitter APISs json representations. */ private boolean rawJson = true; @@ -112,4 +111,5 @@ public boolean isRawJson() { public void setRawJson(boolean rawJson) { this.rawJson = rawJson; } + } diff --git a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/util/TwitterTestUtils.java b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/util/TwitterTestUtils.java index 25b27679..85a929cc 100644 --- a/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/util/TwitterTestUtils.java +++ b/common/spring-twitter-common/src/main/java/org/springframework/cloud/fn/common/twitter/util/TwitterTestUtils.java @@ -16,7 +16,6 @@ package org.springframework.cloud.fn.common.twitter.util; - import java.io.IOException; import java.nio.charset.Charset; import java.util.function.Function; @@ -52,8 +51,10 @@ public Function mockTwitterUrls(Stri /** * Load Spring Resource as String. - * @param resourcePath Resource path (accepts file:// , classpath:// and http:// uri schemas) - * @return Returns text (UTF8) representation of the resource pointed by the resourcePath + * @param resourcePath Resource path (accepts file:// , classpath:// and http:// uri + * schemas) + * @return Returns text (UTF8) representation of the resource pointed by the + * resourcePath */ public static String asString(String resourcePath) { try { diff --git a/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryConfiguration.java b/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryConfiguration.java index 1918f59c..51dd7b2d 100644 --- a/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryConfiguration.java +++ b/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryConfiguration.java @@ -33,7 +33,8 @@ public class XmppConnectionFactoryConfiguration { @Bean @ConditionalOnMissingBean - public XmppConnectionFactoryBean xmppConnectionFactoryBean(XmppConnectionFactoryProperties properties) throws XmppStringprepException { + public XmppConnectionFactoryBean xmppConnectionFactoryBean(XmppConnectionFactoryProperties properties) + throws XmppStringprepException { XmppConnectionFactoryBean xmppConnectionFactoryBean = new XmppConnectionFactoryBean(); xmppConnectionFactoryBean.setSubscriptionMode(properties.getSubscriptionMode()); @@ -48,11 +49,12 @@ public XmppConnectionFactoryBean xmppConnectionFactoryBean(XmppConnectionFactory if (StringUtils.hasText(properties.getServiceName())) { builder.setUsernameAndPassword(properties.getUser(), properties.getPassword()) - .setXmppDomain(properties.getServiceName()); + .setXmppDomain(properties.getServiceName()); } else { - builder.setUsernameAndPassword(XmppStringUtils.parseLocalpart(properties.getUser()), properties.getPassword()) - .setXmppDomain(properties.getUser()); + builder + .setUsernameAndPassword(XmppStringUtils.parseLocalpart(properties.getUser()), properties.getPassword()) + .setXmppDomain(properties.getUser()); } xmppConnectionFactoryBean.setConnectionConfiguration(builder.build()); diff --git a/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryProperties.java b/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryProperties.java index 99cd071e..4f337034 100644 --- a/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryProperties.java +++ b/common/spring-xmpp-common/src/main/java/org/springframework/cloud/fn/common/xmpp/XmppConnectionFactoryProperties.java @@ -24,7 +24,6 @@ import org.springframework.validation.annotation.Validated; /** - * * @author Daniel Frey * @since 4.0.0 */ @@ -33,8 +32,8 @@ public class XmppConnectionFactoryProperties { /** - * The Resource to bind to on the XMPP Host. - * - Can be empty, server will generate one if not set + * The Resource to bind to on the XMPP Host. - Can be empty, server will generate one + * if not set */ private String resource; @@ -59,8 +58,7 @@ public class XmppConnectionFactoryProperties { private String host; /** - * Port for connecting to the host. - * - Default Client Port: 5222 + * Port for connecting to the host. - Default Client Port: 5222 */ private int port = 5222; diff --git a/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerConfiguration.java b/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerConfiguration.java index 45e7aeaa..477459dc 100644 --- a/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerConfiguration.java +++ b/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerConfiguration.java @@ -62,20 +62,24 @@ public class AnalyticsConsumerConfiguration { private final Map gaugeValues = new ConcurrentHashMap<>(); @Bean(name = "analyticsConsumer") - public Consumer> analyticsConsumer(AnalyticsConsumerProperties properties, MeterRegistry[] meterRegistries, + public Consumer> analyticsConsumer(AnalyticsConsumerProperties properties, + MeterRegistry[] meterRegistries, @Lazy @Qualifier(SpelExpressionConverterConfiguration.INTEGRATION_EVALUATION_CONTEXT) EvaluationContext context) { - // If the CompositeMeterRegistry is present the it already contains all non-composite registries. - // In this case we override the input meterRegistries to use the CompositeMeterRegistry only. + // If the CompositeMeterRegistry is present the it already contains all + // non-composite registries. + // In this case we override the input meterRegistries to use the + // CompositeMeterRegistry only. final MeterRegistry[] finalMeterRegistries = Stream.of(meterRegistries) - .filter(CompositeMeterRegistry.class::isInstance) - .findFirst() - .map(meterRegistry -> new MeterRegistry[] { meterRegistry }) - .orElse(meterRegistries); + .filter(CompositeMeterRegistry.class::isInstance) + .findFirst() + .map(meterRegistry -> new MeterRegistry[] { meterRegistry }) + .orElse(meterRegistries); return message -> { - CharSequence meterNameRaw = properties.getComputedNameExpression().getValue(context, message, CharSequence.class); + CharSequence meterNameRaw = properties.getComputedNameExpression() + .getValue(context, message, CharSequence.class); String meterName = StringUtils.isEmpty(meterNameRaw) ? "empty" : meterNameRaw.toString(); // All fixed tags together are passed with every meter update. @@ -87,46 +91,52 @@ public Consumer> analyticsConsumer(AnalyticsConsumerProperties proper // Tag Expressions if (properties.getTag().getExpression() != null) { - Map> groupedTags = properties.getTag().getExpression().entrySet().stream() - // maps a pair into [, ... ] Tag array. - .map(namedExpression -> - toList(namedExpression.getValue().getValue(context, message)).stream() - .map(tagValue -> Tag.of(namedExpression.getKey(), tagValue)) - .collect(Collectors.toList())).flatMap(List::stream) - .collect(Collectors.groupingBy(Tag::getKey, Collectors.toList())); + Map> groupedTags = properties.getTag() + .getExpression() + .entrySet() + .stream() + // maps a pair into [, ... ] Tag array. + .map(namedExpression -> toList(namedExpression.getValue().getValue(context, message)).stream() + .map(tagValue -> Tag.of(namedExpression.getKey(), tagValue)) + .collect(Collectors.toList())) + .flatMap(List::stream) + .collect(Collectors.groupingBy(Tag::getKey, Collectors.toList())); allGroupedTags.putAll(groupedTags); } - this.recordMetrics(finalMeterRegistries, meterName, fixedTags, allGroupedTags, amount, properties.getMeterType()); + this.recordMetrics(finalMeterRegistries, meterName, fixedTags, allGroupedTags, amount, + properties.getMeterType()); }; } /** - * Converts a key/value Map into Tag(key,value) list. Filters out the empty key/value pairs. - * + * Converts a key/value Map into Tag(key,value) list. Filters out the empty key/value + * pairs. * @param keyValueMap key/value map to convert into tags. * @return Returns Tags list representing every non-empty key/value pair. */ protected Tags toTags(Map keyValueMap) { - return CollectionUtils.isEmpty(keyValueMap) ? Tags.empty() : - Tags.of(keyValueMap.entrySet().stream() - .filter(e -> StringUtils.hasText(e.getKey()) && StringUtils.hasText(e.getValue())) - .map(e -> Tag.of(e.getKey(), e.getValue())) - .collect(Collectors.toList())); + return CollectionUtils.isEmpty(keyValueMap) ? Tags.empty() + : Tags.of(keyValueMap.entrySet() + .stream() + .filter(e -> StringUtils.hasText(e.getKey()) && StringUtils.hasText(e.getValue())) + .map(e -> Tag.of(e.getKey(), e.getValue())) + .collect(Collectors.toList())); } /** - * Converts the input value into an list of values. If the value is not a collection/array type the result - * is a single element list. For collection/array input value the result is the list of stringified content of - * this collection. - * + * Converts the input value into an list of values. If the value is not a + * collection/array type the result is a single element list. For collection/array + * input value the result is the list of stringified content of this collection. * @param value input value can be array, collection or single value. * @return Returns value list. */ protected List toList(Object value) { if (value == null) { // Ensure that the tag is present in the meter metrics, even if empty. - // TSDB as Prometheus do not tolerate same meters to have different tags signatures. + // TSDB as Prometheus do not tolerate same meters to have different tags + // signatures. return Collections.singletonList(UNAVAILABLE_TAG); } @@ -135,10 +145,10 @@ protected List toList(Object value) { Collection valueCollection = (value instanceof Collection) ? (Collection) value : Arrays.asList(ObjectUtils.toObjectArray(value)); List list = valueCollection.stream() - .filter(Objects::nonNull) - .map(Object::toString) - .filter(StringUtils::hasText) - .collect(Collectors.toList()); + .filter(Objects::nonNull) + .map(Object::toString) + .filter(StringUtils::hasText) + .collect(Collectors.toList()); return CollectionUtils.isEmpty(list) ? Collections.singletonList(UNAVAILABLE_TAG) : list; } else { @@ -149,21 +159,18 @@ protected List toList(Object value) { private void recordMetrics(MeterRegistry[] meterRegistries, String meterName, Tags fixedTags, Map> groupedTags, double amount, AnalyticsConsumerProperties.MeterType meterType) { if (!CollectionUtils.isEmpty(groupedTags)) { - groupedTags.values().stream().map(List::size).max(Integer::compareTo).ifPresent( - max -> { - for (int i = 0; i < max; i++) { - Tags currentTags = Tags.of(fixedTags); - for (Map.Entry> e : groupedTags.entrySet()) { - currentTags = (e.getValue().size() > i) ? - currentTags.and(e.getValue().get(i)) : - currentTags.and(Tags.of(e.getKey(), "")); - } - - // Update the meterName for every configured MaterRegistry. - record(meterRegistries, meterName, currentTags, amount, meterType); - } + groupedTags.values().stream().map(List::size).max(Integer::compareTo).ifPresent(max -> { + for (int i = 0; i < max; i++) { + Tags currentTags = Tags.of(fixedTags); + for (Map.Entry> e : groupedTags.entrySet()) { + currentTags = (e.getValue().size() > i) ? currentTags.and(e.getValue().get(i)) + : currentTags.and(Tags.of(e.getKey(), "")); } - ); + + // Update the meterName for every configured MaterRegistry. + record(meterRegistries, meterName, currentTags, amount, meterType); + } + }); } else { // Update the meterName for every configured MaterRegistry. @@ -171,8 +178,8 @@ private void recordMetrics(MeterRegistry[] meterRegistries, String meterName, Ta } } - private void record(MeterRegistry[] meterRegistries, String meterName, - Iterable tags, double meterAmount, AnalyticsConsumerProperties.MeterType meterType) { + private void record(MeterRegistry[] meterRegistries, String meterName, Iterable tags, double meterAmount, + AnalyticsConsumerProperties.MeterType meterType) { for (MeterRegistry meterRegistry : meterRegistries) { if (meterType == AnalyticsConsumerProperties.MeterType.gauge) { @@ -197,8 +204,7 @@ else if (meterType == AnalyticsConsumerProperties.MeterType.counter) { } private boolean isMeterRegistryContainsGauge(MeterRegistry meterRegistry, Meter.Id gaugeId) { - return meterRegistry.find(gaugeId.getName()).gauges().stream() - .anyMatch(gauge -> gauge.getId().equals(gaugeId)); + return meterRegistry.find(gaugeId.getName()).gauges().stream().anyMatch(gauge -> gauge.getId().equals(gaugeId)); } @Bean @@ -206,4 +212,5 @@ private boolean isMeterRegistryContainsGauge(MeterRegistry meterRegistry, Meter. public SimpleMeterRegistry simpleMeterRegistry() { return new SimpleMeterRegistry(); } + } diff --git a/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerProperties.java b/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerProperties.java index 347bcf4e..f16e58dd 100644 --- a/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerProperties.java +++ b/consumer/spring-analytics-consumer/src/main/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerProperties.java @@ -34,13 +34,20 @@ public class AnalyticsConsumerProperties { enum MeterType { - /** Uses the Micrometer Counter meter type. It accumulates intermediate counts toward the point where - * the data is sent to the metrics backend.*/ + + /** + * Uses the Micrometer Counter meter type. It accumulates intermediate counts + * toward the point where the data is sent to the metrics backend. + */ counter, - /** Uses the Micrometer Gauge meter type. Gauges sample the input time series. Any intermediate values set on - * a gauge are lost by the time the gauge value is reported to a metrics backend. - * TIP: Never gauge something you can count with a Counter!*/ + /** + * Uses the Micrometer Gauge meter type. Gauges sample the input time series. Any + * intermediate values set on a gauge are lost by the time the gauge value is + * reported to a metrics backend. TIP: Never gauge something you can count with a + * Counter! + */ gauge + } /** @@ -49,27 +56,27 @@ enum MeterType { private MeterType meterType = MeterType.counter; /** - * The name of the output metrics. - * The 'name' and 'nameExpression' are mutually exclusive. Only one of them can be set. + * The name of the output metrics. The 'name' and 'nameExpression' are mutually + * exclusive. Only one of them can be set. */ private String name; /** - * A SpEL expression to compute the output metrics name from the input message. - * The 'name' and 'nameExpression' are mutually exclusive. Only one of them can be set. + * A SpEL expression to compute the output metrics name from the input message. The + * 'name' and 'nameExpression' are mutually exclusive. Only one of them can be set. */ private Expression nameExpression; /** - * If neither `name` nor `nameExpression` is set the name of the output metrics defaults to the - * Spring application name. + * If neither `name` nor `nameExpression` is set the name of the output metrics + * defaults to the Spring application name. */ @Value("${spring.application.name:analytics}") private String defaultName; /** - * A SpEL expression to compute the output metrics value (e.g. amount). - * It defaults to 1.0 + * A SpEL expression to compute the output metrics value (e.g. amount). It defaults to + * 1.0 */ private Expression amountExpression; @@ -132,20 +139,18 @@ public boolean isExclusiveOptions() { @Override public String toString() { - return "AnalyticsFunctionProperties{" + - "defaultName='" + defaultName + '\'' + - ", name=" + name + - ", tag=" + tag + - '}'; + return "AnalyticsFunctionProperties{" + "defaultName='" + defaultName + '\'' + ", name=" + name + ", tag=" + tag + + '}'; } public static class MetricsTag { /** - * DEPRECATED: Please use the analytics.tag.expression with literal SpEL expression. + * DEPRECATED: Please use the analytics.tag.expression with literal SpEL + * expression. * - * Custom, fixed Tags. Those tags have constant values, created once and then sent along with every - * published metrics. The convention to define a fixed Tags is: + * Custom, fixed Tags. Those tags have constant values, created once and then sent + * along with every published metrics. The convention to define a fixed Tags is: * * analytics.tag.fixed.[tag-name]=[tag-value] * @@ -154,10 +159,10 @@ public static class MetricsTag { private Map fixed; /** - * Computes tags from SpEL expression. - * Single SpEL expression can produce an array of values, which in turn means distinct name/value tags. - * Every name/value tag will produce a separate meter increment. - * Tag expression format is: analytics.tag.expression.[tag-name]=[SpEL expression] + * Computes tags from SpEL expression. Single SpEL expression can produce an array + * of values, which in turn means distinct name/value tags. Every name/value tag + * will produce a separate meter increment. Tag expression format is: + * analytics.tag.expression.[tag-name]=[SpEL expression] */ private Map expression; @@ -179,10 +184,9 @@ public void setExpression(Map expression) { @Override public String toString() { - return "MetricsTag{" + - "fixed=" + fixed + - ", expression=" + expression + - '}'; + return "MetricsTag{" + "fixed=" + fixed + ", expression=" + expression + '}'; } + } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerParentTest.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerParentTest.java index 9473a821..2c80c29d 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerParentTest.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/AnalyticsConsumerParentTest.java @@ -44,5 +44,7 @@ protected Message message(String payload) { @SpringBootApplication static class AnalyticsConsumerTestApplication { + } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/CountWithAmountTest.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/CountWithAmountTest.java index 099b6f88..125278e3 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/CountWithAmountTest.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/CountWithAmountTest.java @@ -26,11 +26,8 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name=counter666", - "analytics.tag.expression.foo='bar'", - "analytics.amount-expression=payload.length()" -}) +@TestPropertySource(properties = { "analytics.name=counter666", "analytics.tag.expression.foo='bar'", + "analytics.amount-expression=payload.length()" }) class CountWithAmountTest extends AnalyticsConsumerParentTest { @Test @@ -40,4 +37,5 @@ void testCounterSink() { analyticsConsumer.accept(new GenericMessage<>(message)); assertThat(meterRegistry.find("counter666").counter().count()).isEqualTo(messageSize); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/EmptyTagsTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/EmptyTagsTests.java index 23344129..6e5e9eeb 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/EmptyTagsTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/EmptyTagsTests.java @@ -28,12 +28,9 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name=counter666", - "analytics.tag.fixed.foo=", +@TestPropertySource(properties = { "analytics.name=counter666", "analytics.tag.fixed.foo=", "analytics.tag.expression.tag666=#jsonPath(payload,'$..noField')", - "analytics.tag.expression.test=#jsonPath(payload,'$..test')" -}) + "analytics.tag.expression.test=#jsonPath(payload,'$..test')" }) class EmptyTagsTests extends AnalyticsConsumerParentTest { @Test @@ -46,10 +43,12 @@ void testCounterSink() { Collection expressionTagsCounters = meterRegistry.find("counter666").tagKeys("tag666").counters(); assertThat(expressionTagsCounters.size()).isEqualTo(1); - assertThat(meterRegistry.find("counter666").meter().getId().getTag("tag666")).isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); + assertThat(meterRegistry.find("counter666").meter().getId().getTag("tag666")) + .isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); Collection testExpTagsCounters = meterRegistry.find("counter666").tagKeys("test").counters(); assertThat(testExpTagsCounters.size()).isEqualTo(1); assertThat(meterRegistry.find("counter666").meter().getId().getTag("test")).isEqualTo("Bar"); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/ExpressionCounterNameTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/ExpressionCounterNameTests.java index ebb45178..f7e1044b 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/ExpressionCounterNameTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/ExpressionCounterNameTests.java @@ -28,9 +28,7 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name-expression=payload" -}) +@TestPropertySource(properties = { "analytics.name-expression=payload" }) public class ExpressionCounterNameTests extends AnalyticsConsumerParentTest { @Test @@ -38,4 +36,5 @@ void testCounterSink() { IntStream.range(0, 13).forEach(i -> analyticsConsumer.accept(new GenericMessage<>("hello"))); assertThat(meterRegistry.find("hello").counter().count()).isEqualTo(13.0); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/FixedTagsTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/FixedTagsTests.java index 971a7412..9882b540 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/FixedTagsTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/FixedTagsTests.java @@ -30,22 +30,21 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name=counter666", - "analytics.tag.fixed.foo=bar", - "analytics.tag.fixed.gork=bork" -}) +@TestPropertySource( + properties = { "analytics.name=counter666", "analytics.tag.fixed.foo=bar", "analytics.tag.fixed.gork=bork" }) public class FixedTagsTests extends AnalyticsConsumerParentTest { @Test void testAnalyticsSink() { IntStream.range(0, 13).forEach(i -> analyticsConsumer.accept(new GenericMessage<>("hello"))); Meter counterMeter = meterRegistry.find("counter666").meter(); - assertThat(StreamSupport.stream(counterMeter.measure().spliterator(), false) - .mapToDouble(m -> m.getValue()).sum()).isEqualTo(13.0); + assertThat( + StreamSupport.stream(counterMeter.measure().spliterator(), false).mapToDouble(m -> m.getValue()).sum()) + .isEqualTo(13.0); assertThat(counterMeter.getId().getTags().size()).isEqualTo(2); assertThat(counterMeter.getId().getTag("foo")).isEqualTo("bar"); assertThat(counterMeter.getId().getTag("gork")).isEqualTo("bork"); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/GaugeWithAmountTest.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/GaugeWithAmountTest.java index 052a482b..dbf13070 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/GaugeWithAmountTest.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/GaugeWithAmountTest.java @@ -26,12 +26,8 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.meter-type=gauge", - "analytics.name=myGauge", - "analytics.tag.expression.foo='bar'", - "analytics.amount-expression=payload.length()" -}) +@TestPropertySource(properties = { "analytics.meter-type=gauge", "analytics.name=myGauge", + "analytics.tag.expression.foo='bar'", "analytics.amount-expression=payload.length()" }) class GaugeWithAmountTest extends AnalyticsConsumerParentTest { @Test diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/LiteralTagExpressionsTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/LiteralTagExpressionsTests.java index 55a1e898..22278ede 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/LiteralTagExpressionsTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/LiteralTagExpressionsTests.java @@ -29,11 +29,8 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name=counter666", - "analytics.tag.expression.foo='bar'", - "analytics.tag.expression.gork='bork'" -}) +@TestPropertySource(properties = { "analytics.name=counter666", "analytics.tag.expression.foo='bar'", + "analytics.tag.expression.gork='bork'" }) public class LiteralTagExpressionsTests extends AnalyticsConsumerParentTest { @Test diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/NullTagsTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/NullTagsTests.java index 40f40a0a..5ba14e22 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/NullTagsTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/NullTagsTests.java @@ -28,12 +28,9 @@ /** * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.name=counter666", - "analytics.tag.fixed.foo=", +@TestPropertySource(properties = { "analytics.name=counter666", "analytics.tag.fixed.foo=", "analytics.tag.expression.tag666=#jsonPath(payload,'$..noField')", - "analytics.tag.expression.test=#jsonPath(payload,'$..test')" -}) + "analytics.tag.expression.test=#jsonPath(payload,'$..test')" }) public class NullTagsTests extends AnalyticsConsumerParentTest { @Test @@ -46,10 +43,13 @@ public class NullTagsTests extends AnalyticsConsumerParentTest { Collection expressionTagsCounters = meterRegistry.find("counter666").tagKeys("tag666").counters(); assertThat(expressionTagsCounters.size()).isEqualTo(1); - assertThat(meterRegistry.find("counter666").meter().getId().getTag("tag666")).isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); + assertThat(meterRegistry.find("counter666").meter().getId().getTag("tag666")) + .isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); Collection testExpTagsCounters = meterRegistry.find("counter666").tagKeys("test").counters(); assertThat(testExpTagsCounters.size()).isEqualTo(1); - assertThat(meterRegistry.find("counter666").meter().getId().getTag("test")).isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); + assertThat(meterRegistry.find("counter666").meter().getId().getTag("test")) + .isEqualTo(AnalyticsConsumerConfiguration.UNAVAILABLE_TAG); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/StockExchangeAnalyticsTests.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/StockExchangeAnalyticsTests.java index c8a463c0..07c17310 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/StockExchangeAnalyticsTests.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/analytics/StockExchangeAnalyticsTests.java @@ -33,12 +33,9 @@ * @author Christian Tzolov */ -@TestPropertySource(properties = { - "analytics.meter-type=counter", - "analytics.name=stocks", +@TestPropertySource(properties = { "analytics.meter-type=counter", "analytics.name=stocks", "analytics.tag.expression.symbol=#jsonPath(payload,'$.data.symbol')", - "analytics.tag.expression.exchange=#jsonPath(payload,'$.data.exchange')" -}) + "analytics.tag.expression.exchange=#jsonPath(payload,'$.data.exchange')" }) public class StockExchangeAnalyticsTests extends AnalyticsConsumerParentTest { @Test @@ -60,15 +57,18 @@ public void testCounter() throws IOException { assertThat(counters).hasSize(2); - //Iterator itr = counters.iterator(); + // Iterator itr = counters.iterator(); // - //Counter applCounter = itr.next(); - //assertThat(applCounter.count()).isEqualTo(3); - //assertThat(applCounter.getId().getTags()).contains(Tag.of("symbol", "AAPL"), Tag.of("exchange", "XNAS")); + // Counter applCounter = itr.next(); + // assertThat(applCounter.count()).isEqualTo(3); + // assertThat(applCounter.getId().getTags()).contains(Tag.of("symbol", "AAPL"), + // Tag.of("exchange", "XNAS")); // - //Counter vmwCounter = itr.next(); - //assertThat(vmwCounter.count()).isEqualTo(2); - //assertThat(vmwCounter.getId().getTags()).contains(Tag.of("symbol", "VMW"), Tag.of("exchange", "NYSE")); + // Counter vmwCounter = itr.next(); + // assertThat(vmwCounter.count()).isEqualTo(2); + // assertThat(vmwCounter.getId().getTags()).contains(Tag.of("symbol", "VMW"), + // Tag.of("exchange", "NYSE")); } + } diff --git a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/demo/StockExchangeAnalyticsExample.java b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/demo/StockExchangeAnalyticsExample.java index 2f74f52d..ea3618a8 100644 --- a/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/demo/StockExchangeAnalyticsExample.java +++ b/consumer/spring-analytics-consumer/src/test/java/org/springframework/cloud/fn/consumer/demo/StockExchangeAnalyticsExample.java @@ -35,19 +35,17 @@ import org.springframework.messaging.support.MessageBuilder; /** - * Sample Spring Boot Application that uses the analyticsConsumer to compute running stats from - * stock exchange messages. + * Sample Spring Boot Application that uses the analyticsConsumer to compute running stats + * from stock exchange messages. * - * Counter configuration: - * + * Counter configuration: * --analytics.meter-type=counter * --analytics.name=stocks * --analytics.tag.expression.symbol=#jsonPath(payload,'$.data.symbol') * --analytics.tag.expression.exchange=#jsonPath(payload,'$.data.exchange') * * - * Gauge configuration: - * + * Gauge configuration: * --analytics.meter-type=gauge * --analytics.name=stocks * --analytics.tag.expression.symbol=#jsonPath(payload,'$.data.symbol') @@ -55,8 +53,7 @@ * --analytics.amount-expression=#jsonPath(payload,'$.data.volume') * * - * Sample Wavefront configuration: - * + * Sample Wavefront configuration: * --management.metrics.export.wavefront.enabled=true * --management.metrics.export.wavefront.uri=YOUR_WAVEFRONT_SERVER_URI * --management.metrics.export.wavefront.api-token=YOUR_API_TOKEN @@ -74,23 +71,25 @@ public static void main(String[] args) { } @Bean - public CommandLineRunner commandLineRunner(Consumer> analyticsConsumer, - MeterRegistry meterRegistry, Supplier stockMessageGenerator) { + public CommandLineRunner commandLineRunner(Consumer> analyticsConsumer, MeterRegistry meterRegistry, + Supplier stockMessageGenerator) { // Run every second. return args -> Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { String message = stockMessageGenerator.get(); - // Submit new message using the stockMessageGenerator to generate random stock messages. + // Submit new message using the stockMessageGenerator to generate random stock + // messages. analyticsConsumer.accept(MessageBuilder.withPayload(message).build()); // Print current stock meters - System.out.println(meterRegistry.getMeters().stream() - .filter(meter -> meter.getId().getName().contains("stocks")) - .map(meter -> meter.getId().getType() + " | " + meter.getId() + " | " + meter.measure()) - .collect(Collectors.joining("\n")) + - "\n========================================================================="); + System.out.println(meterRegistry.getMeters() + .stream() + .filter(meter -> meter.getId().getName().contains("stocks")) + .map(meter -> meter.getId().getType() + " | " + meter.getId() + " | " + meter.measure()) + .collect(Collectors.joining("\n")) + + "\n========================================================================="); }, 0, 1000, TimeUnit.MILLISECONDS); } @@ -103,16 +102,11 @@ public Supplier stockMessageGenerator() { return () -> { int stockIndex = random.nextInt(STOCKS.length); - return "{\n" + - " \"data\": {\n" + - " \"symbol\": \"" + STOCKS[stockIndex][1] + "\",\n" + - " \"exchange\": \"" + STOCKS[stockIndex][0] + "\",\n" + - " \"open\": " + (1 + 10 * random.nextDouble()) + ",\n" + - " \"close\": " + (1 + 10 * random.nextDouble()) + ",\n" + - " \"volume\": " + (1000 + 100000 * random.nextDouble()) + "\n" + - " }\n" + - "}"; + return "{\n" + " \"data\": {\n" + " \"symbol\": \"" + STOCKS[stockIndex][1] + "\",\n" + + " \"exchange\": \"" + STOCKS[stockIndex][0] + "\",\n" + " \"open\": " + + (1 + 10 * random.nextDouble()) + ",\n" + " \"close\": " + (1 + 10 * random.nextDouble()) + + ",\n" + " \"volume\": " + (1000 + 100000 * random.nextDouble()) + "\n" + " }\n" + "}"; }; } -} +} diff --git a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerConfiguration.java b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerConfiguration.java index 2750c32a..40c9c1ed 100644 --- a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerConfiguration.java +++ b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerConfiguration.java @@ -75,22 +75,17 @@ public IntegrationFlow cassandraConsumerFlow(MessageHandler cassandraSinkMessage IntegrationFlowBuilder integrationFlowBuilder = IntegrationFlow.from(CassandraConsumerFunction.class); String ingestQuery = this.cassandraSinkProperties.getIngestQuery(); if (StringUtils.hasText(ingestQuery)) { - integrationFlowBuilder.transform( - new PayloadToMatrixTransformer(objectMapper, ingestQuery, - CassandraMessageHandler.Type.UPDATE == this.cassandraSinkProperties.getQueryType() - ? new UpdateQueryColumnNameExtractor() - : new InsertQueryColumnNameExtractor())); + integrationFlowBuilder.transform(new PayloadToMatrixTransformer(objectMapper, ingestQuery, + CassandraMessageHandler.Type.UPDATE == this.cassandraSinkProperties.getQueryType() + ? new UpdateQueryColumnNameExtractor() : new InsertQueryColumnNameExtractor())); } - return integrationFlowBuilder - .handle(cassandraSinkMessageHandler) - .get(); + return integrationFlowBuilder.handle(cassandraSinkMessageHandler).get(); } @Bean public MessageHandler cassandraSinkMessageHandler(ReactiveCassandraOperations cassandraOperations) { - CassandraMessageHandler.Type queryType = - Optional.ofNullable(this.cassandraSinkProperties.getQueryType()) - .orElse(CassandraMessageHandler.Type.INSERT); + CassandraMessageHandler.Type queryType = Optional.ofNullable(this.cassandraSinkProperties.getQueryType()) + .orElse(CassandraMessageHandler.Type.INSERT); CassandraMessageHandler cassandraMessageHandler = new CassandraMessageHandler(cassandraOperations, queryType); cassandraMessageHandler.setProducesReply(true); @@ -98,24 +93,22 @@ public MessageHandler cassandraSinkMessageHandler(ReactiveCassandraOperations ca ConsistencyLevel consistencyLevel = this.cassandraSinkProperties.getConsistencyLevel(); if (consistencyLevel != null || ttl > 0) { - WriteOptions.WriteOptionsBuilder writeOptionsBuilder = - switch (queryType) { - case INSERT -> InsertOptions.builder(); - case UPDATE -> UpdateOptions.builder(); - default -> WriteOptions.builder(); - }; + WriteOptions.WriteOptionsBuilder writeOptionsBuilder = switch (queryType) { + case INSERT -> InsertOptions.builder(); + case UPDATE -> UpdateOptions.builder(); + default -> WriteOptions.builder(); + }; - JavaUtils.INSTANCE - .acceptIfNotNull(consistencyLevel, writeOptionsBuilder::consistencyLevel) - .acceptIfCondition(ttl > 0, ttl, writeOptionsBuilder::ttl); + JavaUtils.INSTANCE.acceptIfNotNull(consistencyLevel, writeOptionsBuilder::consistencyLevel) + .acceptIfCondition(ttl > 0, ttl, writeOptionsBuilder::ttl); cassandraMessageHandler.setWriteOptions(writeOptionsBuilder.build()); } JavaUtils.INSTANCE - .acceptIfHasText(this.cassandraSinkProperties.getIngestQuery(), cassandraMessageHandler::setIngestQuery) - .acceptIfNotNull(this.cassandraSinkProperties.getStatementExpression(), - cassandraMessageHandler::setStatementExpression); + .acceptIfHasText(this.cassandraSinkProperties.getIngestQuery(), cassandraMessageHandler::setIngestQuery) + .acceptIfNotNull(this.cassandraSinkProperties.getStatementExpression(), + cassandraMessageHandler::setStatementExpression); return cassandraMessageHandler; } @@ -124,15 +117,13 @@ private static boolean isUuid(String uuid) { if (uuid.length() == 36) { String[] parts = uuid.split("-"); if (parts.length == 5) { - return (parts[0].length() == 8) && (parts[1].length() == 4) && - (parts[2].length() == 4) && (parts[3].length() == 4) && - (parts[4].length() == 12); + return (parts[0].length() == 8) && (parts[1].length() == 4) && (parts[2].length() == 4) + && (parts[3].length() == 4) && (parts[4].length() == 12); } } return false; } - private static class PayloadToMatrixTransformer extends AbstractPayloadTransformer>> { private final Jackson2JsonObjectMapper jsonObjectMapper; @@ -145,7 +136,7 @@ private static class PayloadToMatrixTransformer extends AbstractPayloadTransform this.jsonObjectMapper = new Jackson2JsonObjectMapper(objectMapper); this.columns.addAll(columnNameExtractor.extract(query)); this.jsonObjectMapper.getObjectMapper() - .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); } @Override diff --git a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraAppClusterConfiguration.java b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraAppClusterConfiguration.java index 89b5501a..277f43bb 100644 --- a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraAppClusterConfiguration.java +++ b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraAppClusterConfiguration.java @@ -63,36 +63,31 @@ public class CassandraAppClusterConfiguration { @Bean - public CqlSessionBuilderCustomizer clusterBuilderCustomizer( - CassandraClusterProperties cassandraClusterProperties) { + public CqlSessionBuilderCustomizer clusterBuilderCustomizer(CassandraClusterProperties cassandraClusterProperties) { PropertyMapper map = PropertyMapper.get(); - return builder -> - map.from(cassandraClusterProperties::isSkipSslValidation) - .whenTrue() - .toCall(() -> { - try { - builder.withSslContext(TrustAllSSLContextFactory.getSslContext()); - } - catch (NoSuchAlgorithmException | KeyManagementException ex) { - throw new BeanInitializationException( - "Unable to configure a Cassandra cluster using SSL.", ex); - } - - }); + return builder -> map.from(cassandraClusterProperties::isSkipSslValidation).whenTrue().toCall(() -> { + try { + builder.withSslContext(TrustAllSSLContextFactory.getSslContext()); + } + catch (NoSuchAlgorithmException | KeyManagementException ex) { + throw new BeanInitializationException("Unable to configure a Cassandra cluster using SSL.", ex); + } + + }); } @Bean @ConditionalOnProperty("cassandra.cluster.create-keyspace") public Object keyspaceCreator(CassandraProperties cassandraProperties, CqlSessionBuilder cqlSessionBuilder) { - CreateKeyspaceSpecification createKeyspaceSpecification = - CreateKeyspaceSpecification - .createKeyspace(cassandraProperties.getKeyspaceName()) - .withSimpleReplication() - .ifNotExists(); + CreateKeyspaceSpecification createKeyspaceSpecification = CreateKeyspaceSpecification + .createKeyspace(cassandraProperties.getKeyspaceName()) + .withSimpleReplication() + .ifNotExists(); String createKeySpaceQuery = new CreateKeyspaceCqlGenerator(createKeyspaceSpecification).toCql(); - try (var systemSession = cqlSessionBuilder.withKeyspace(CqlSessionFactoryBean.CASSANDRA_SYSTEM_SESSION).build()) { + try (var systemSession = cqlSessionBuilder.withKeyspace(CqlSessionFactoryBean.CASSANDRA_SYSTEM_SESSION) + .build()) { systemSession.execute(createKeySpaceQuery); } @@ -106,25 +101,22 @@ public CqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder) { return cqlSessionBuilder.build(); } - @Bean @ConditionalOnProperty("cassandra.cluster.init-script") public Object keyspaceInitializer(CassandraClusterProperties cassandraClusterProperties, ReactiveCassandraTemplate reactiveCassandraTemplate) throws IOException { - String scripts = - new Scanner(cassandraClusterProperties.getInitScript().getInputStream(), - StandardCharsets.UTF_8) - .useDelimiter("\\A") - .next(); + String scripts = new Scanner(cassandraClusterProperties.getInitScript().getInputStream(), + StandardCharsets.UTF_8) + .useDelimiter("\\A") + .next(); - ReactiveCqlOperations reactiveCqlOperations = - reactiveCassandraTemplate.getReactiveCqlOperations(); + ReactiveCqlOperations reactiveCqlOperations = reactiveCassandraTemplate.getReactiveCqlOperations(); Flux.fromArray(StringUtils.delimitedListToStringArray(scripts, ";", "\r\n\f")) - .filter(StringUtils::hasText) // an empty String after the last ';' - .concatMap(script -> reactiveCqlOperations.execute(script + ";")) - .blockLast(); + .filter(StringUtils::hasText) // an empty String after the last ';' + .concatMap(script -> reactiveCqlOperations.execute(script + ";")) + .blockLast(); return null; @@ -144,9 +136,9 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Binder.get(this.environment) - .bind("cassandra.cluster.entity-base-packages", String[].class) - .map(Arrays::asList) - .ifBound(packagesToScan -> EntityScanPackages.register(registry, packagesToScan)); + .bind("cassandra.cluster.entity-base-packages", String[].class) + .map(Arrays::asList) + .ifBound(packagesToScan -> EntityScanPackages.register(registry, packagesToScan)); } } diff --git a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraClusterProperties.java b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraClusterProperties.java index 0d2f46aa..c96e8ba8 100644 --- a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraClusterProperties.java +++ b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/CassandraClusterProperties.java @@ -47,8 +47,7 @@ public class CassandraClusterProperties { /** * Base packages to scan for entities annotated with Table annotations. */ - private String[] entityBasePackages = { }; - + private String[] entityBasePackages = {}; public void setCreateKeyspace(boolean createKeyspace) { this.createKeyspace = createKeyspace; diff --git a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/TrustAllSSLContextFactory.java b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/TrustAllSSLContextFactory.java index 5987b88b..25425ffd 100644 --- a/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/TrustAllSSLContextFactory.java +++ b/consumer/spring-cassandra-consumer/src/main/java/org/springframework/cloud/fn/consumer/cassandra/cluster/TrustAllSSLContextFactory.java @@ -25,10 +25,9 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; - /** - * Helper to provide an SSL Context that does not validate - * certificates presented in the SSL handshake. + * Helper to provide an SSL Context that does not validate certificates presented in the + * SSL handshake. * * The usual caveats apply. * @@ -43,24 +42,22 @@ private TrustAllSSLContextFactory() { static SSLContext getSslContext() throws NoSuchAlgorithmException, KeyManagementException { - TrustManager[] trustAllCerts = new TrustManager[] { - new X509TrustManager() { + TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } - @Override - public void checkClientTrusted(X509Certificate[] certs, String authType) { - } + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } - @Override - public void checkServerTrusted(X509Certificate[] certs, String authType) { - } + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } - } - }; + } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerApplicationTests.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerApplicationTests.java index 9ef3b810..ed428bdf 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerApplicationTests.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraConsumerApplicationTests.java @@ -42,8 +42,7 @@ * @author Artem Bilan */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "spring.cassandra.keyspace-name=" + CassandraConsumerApplicationTests.CASSANDRA_KEYSPACE, + properties = { "spring.cassandra.keyspace-name=" + CassandraConsumerApplicationTests.CASSANDRA_KEYSPACE, "cassandra.cluster.createKeyspace=true" }) @DirtiesContext abstract class CassandraConsumerApplicationTests implements CassandraContainerTest { @@ -56,12 +55,11 @@ abstract class CassandraConsumerApplicationTests implements CassandraContainerTe @Autowired protected Function> cassandraConsumer; - @DynamicPropertySource static void registerConfigurationProperties(DynamicPropertyRegistry registry) { registry.add("spring.cassandra.localDatacenter", () -> CASSANDRA_CONTAINER.getLocalDatacenter()); - registry.add("spring.cassandra.contactPoints", () -> - Optional.of(CASSANDRA_CONTAINER.getContactPoint()) + registry.add("spring.cassandra.contactPoints", + () -> Optional.of(CASSANDRA_CONTAINER.getContactPoint()) .map(contactPoint -> contactPoint.getAddress().getHostAddress() + ':' + contactPoint.getPort()) .get()); } @@ -75,14 +73,8 @@ protected static List getBookList(int numBooks) { List books = new ArrayList<>(); for (int i = 0; i < numBooks; i++) { - books.add( - new Book( - UUID.randomUUID(), - "Spring Cloud Data Flow Guide", - "SCDF Guru", - i * 10 + 5, - LocalDate.now(), - true)); + books.add(new Book(UUID.randomUUID(), "Spring Cloud Data Flow Guide", "SCDF Guru", i * 10 + 5, + LocalDate.now(), true)); } return books; diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraContainerTest.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraContainerTest.java index 2a99ea7e..0c151827 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraContainerTest.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraContainerTest.java @@ -21,14 +21,13 @@ import org.testcontainers.junit.jupiter.Testcontainers; /** - * The base contract for JUnit tests based on the container for Apache Cassandra. - * The Testcontainers 'reuse' option must be disabled,so, Ryuk container is started - * and will clean all the containers up from this test suite after JVM exit. - * Since the MqSQL container instance is shared via static property, it is going to be - * started only once per JVM, therefore the target Docker container is reused automatically. + * The base contract for JUnit tests based on the container for Apache Cassandra. The + * Testcontainers 'reuse' option must be disabled,so, Ryuk container is started and will + * clean all the containers up from this test suite after JVM exit. Since the MqSQL + * container instance is shared via static property, it is going to be started only once + * per JVM, therefore the target Docker container is reused automatically. * * @author Artem Bilan - * * @since 6.0 */ @Testcontainers(disabledWithoutDocker = true) diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraEntityInsertTests.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraEntityInsertTests.java index f2b329c7..19befa55 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraEntityInsertTests.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraEntityInsertTests.java @@ -32,31 +32,21 @@ /** * @author Artem Bilan */ -@TestPropertySource(properties = { - "spring.cassandra.schema-action=RECREATE", +@TestPropertySource(properties = { "spring.cassandra.schema-action=RECREATE", "cassandra.cluster.entity-base-packages=org.springframework.cloud.fn.consumer.cassandra.domain" }) class CassandraEntityInsertTests extends CassandraConsumerApplicationTests { @Test void testInsert() { - Book book = - new Book( - UUID.randomUUID(), - "Spring Integration Cassandra", - "Cassandra Guru", - 521, - LocalDate.now(), - true); + Book book = new Book(UUID.randomUUID(), "Spring Integration Cassandra", "Cassandra Guru", 521, LocalDate.now(), + true); Mono result = this.cassandraConsumer.apply(book); StepVerifier.create(result) - .expectNextCount(1) - .then(() -> - assertThat(this.cassandraTemplate.query(Book.class) - .count()) - .isEqualTo(1)) - .verifyComplete(); + .expectNextCount(1) + .then(() -> assertThat(this.cassandraTemplate.query(Book.class).count()).isEqualTo(1)) + .verifyComplete(); } } diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestInsertTests.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestInsertTests.java index 57643b9e..aa1f5c6c 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestInsertTests.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestInsertTests.java @@ -34,10 +34,8 @@ /** * @author Artem Bilan */ -@TestPropertySource(properties = { - "cassandra.cluster.init-script=init-db.cql", - "cassandra.ingest-query=" + - "insert into book (isbn, title, author, pages, saleDate, inStock) values (?, ?, ?, ?, ?, ?)" }) +@TestPropertySource(properties = { "cassandra.cluster.init-script=init-db.cql", "cassandra.ingest-query=" + + "insert into book (isbn, title, author, pages, saleDate, inStock) values (?, ?, ?, ?, ?, ?)" }) class CassandraIngestInsertTests extends CassandraConsumerApplicationTests { @Test @@ -46,16 +44,12 @@ void testIngestQuery(@Autowired ObjectMapper objectMapper) throws Exception { Jackson2JsonObjectMapper mapper = new Jackson2JsonObjectMapper(objectMapper); - Mono result = - this.cassandraConsumer.apply(mapper.toJson(books)); + Mono result = this.cassandraConsumer.apply(mapper.toJson(books)); StepVerifier.create(result) - .expectNextCount(1) - .then(() -> - assertThat(this.cassandraTemplate.query(Book.class) - .count()) - .isEqualTo(5)) - .verifyComplete(); + .expectNextCount(1) + .then(() -> assertThat(this.cassandraTemplate.query(Book.class).count()).isEqualTo(5)) + .verifyComplete(); } } diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestNamedParamsTests.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestNamedParamsTests.java index 63b9bd57..797f8fd4 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestNamedParamsTests.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestNamedParamsTests.java @@ -35,11 +35,9 @@ /** * @author Artem Bilan */ -@TestPropertySource(properties = { - "cassandra.cluster.init-script=init-db.cql", - "cassandra.ingest-query=" + - "insert into book (isbn, title, author, pages, saleDate, inStock) " + - "values (:myIsbn, :myTitle, :myAuthor, ?, ?, ?)" }) +@TestPropertySource(properties = { "cassandra.cluster.init-script=init-db.cql", + "cassandra.ingest-query=" + "insert into book (isbn, title, author, pages, saleDate, inStock) " + + "values (:myIsbn, :myTitle, :myAuthor, ?, ?, ?)" }) class CassandraIngestNamedParamsTests extends CassandraConsumerApplicationTests { @Test @@ -53,16 +51,12 @@ void testIngestQuery(@Autowired ObjectMapper objectMapper) throws Exception { booksJsonWithNamedParams = StringUtils.replace(booksJsonWithNamedParams, "title", "myTitle"); booksJsonWithNamedParams = StringUtils.replace(booksJsonWithNamedParams, "author", "myAuthor"); - Mono result = - this.cassandraConsumer.apply(booksJsonWithNamedParams); + Mono result = this.cassandraConsumer.apply(booksJsonWithNamedParams); StepVerifier.create(result) - .expectNextCount(1) - .then(() -> - assertThat(this.cassandraTemplate.query(Book.class) - .count()) - .isEqualTo(5)) - .verifyComplete(); + .expectNextCount(1) + .then(() -> assertThat(this.cassandraTemplate.query(Book.class).count()).isEqualTo(5)) + .verifyComplete(); } } diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestUpdateTests.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestUpdateTests.java index 8d5156ff..e0126b77 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestUpdateTests.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/CassandraIngestUpdateTests.java @@ -34,11 +34,9 @@ /** * @author Artem Bilan */ -@TestPropertySource(properties = { - "cassandra.cluster.init-script=init-db.cql", - "cassandra.ingest-query=" + - "update book set inStock = :inStock, author = :author, pages = :pages, " + - "saleDate = :saleDate, title = :title where isbn = :isbn", +@TestPropertySource(properties = { "cassandra.cluster.init-script=init-db.cql", + "cassandra.ingest-query=" + "update book set inStock = :inStock, author = :author, pages = :pages, " + + "saleDate = :saleDate, title = :title where isbn = :isbn", "cassandra.queryType=UPDATE" }) class CassandraIngestUpdateTests extends CassandraConsumerApplicationTests { @@ -48,16 +46,12 @@ void testIngestQuery(@Autowired ObjectMapper objectMapper) throws Exception { Jackson2JsonObjectMapper mapper = new Jackson2JsonObjectMapper(objectMapper); - Mono result = - this.cassandraConsumer.apply(mapper.toJson(books)); + Mono result = this.cassandraConsumer.apply(mapper.toJson(books)); StepVerifier.create(result) - .expectNextCount(1) - .then(() -> - assertThat(this.cassandraTemplate.query(Book.class) - .count()) - .isEqualTo(5)) - .verifyComplete(); + .expectNextCount(1) + .then(() -> assertThat(this.cassandraTemplate.query(Book.class).count()).isEqualTo(5)) + .verifyComplete(); } } diff --git a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/domain/Book.java b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/domain/Book.java index 7ac253fe..55266b2f 100644 --- a/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/domain/Book.java +++ b/consumer/spring-cassandra-consumer/src/test/java/org/springframework/cloud/fn/consumer/cassandra/domain/Book.java @@ -30,12 +30,7 @@ * @author Artem Bilan */ @Table("book") -public record Book( - @PrimaryKey UUID isbn, - String title, - @Indexed String author, - Integer pages, - LocalDate saleDate, +public record Book(@PrimaryKey UUID isbn, String title, @Indexed String author, Integer pages, LocalDate saleDate, Boolean isInStock) { } diff --git a/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerConfiguration.java b/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerConfiguration.java index 636a22a6..8e428afe 100644 --- a/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerConfiguration.java +++ b/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerConfiguration.java @@ -78,19 +78,24 @@ public class ElasticsearchConsumerConfiguration { private static final Log logger = LogFactory.getLog(ElasticsearchConsumerConfiguration.class); @Bean - FactoryBean aggregator(MessageGroupStore messageGroupStore, ElasticsearchConsumerProperties consumerProperties) { + FactoryBean aggregator(MessageGroupStore messageGroupStore, + ElasticsearchConsumerProperties consumerProperties) { AggregatorFactoryBean aggregatorFactoryBean = new AggregatorFactoryBean(); aggregatorFactoryBean.setCorrelationStrategy(message -> ""); aggregatorFactoryBean.setReleaseStrategy(new MessageCountReleaseStrategy(consumerProperties.getBatchSize())); if (consumerProperties.getGroupTimeout() >= 0) { - aggregatorFactoryBean.setGroupTimeoutExpression(new ValueExpression<>(consumerProperties.getGroupTimeout())); + aggregatorFactoryBean + .setGroupTimeoutExpression(new ValueExpression<>(consumerProperties.getGroupTimeout())); } aggregatorFactoryBean.setMessageStore(messageGroupStore); - // Currently, there is no way to customize the splitting behavior of an aggregator receiving + // Currently, there is no way to customize the splitting behavior of an aggregator + // receiving // a Collection> from the configured MessageGroupProcessor. - // Thus, fooling the aggregator with a wrapper of Message is just a straightforward way to preserve the - // individual message headers and release an entire batch to downstream indexing handler. + // Thus, fooling the aggregator with a wrapper of Message is just a + // straightforward way to preserve the + // individual message headers and release an entire batch to downstream indexing + // handler. aggregatorFactoryBean.setProcessorBean(new AbstractAggregatingMessageGroupProcessor() { @Override protected Object aggregatePayloads(MessageGroup group, Map defaultHeaders) { @@ -118,14 +123,11 @@ MessageGroupStore messageGroupStore() { } @Bean - IntegrationFlow elasticsearchConsumerFlow( - @Qualifier("aggregator") MessageHandler aggregator, - ElasticsearchConsumerProperties properties, - @Qualifier("indexingHandler") MessageHandler indexingHandler - ) { - - final IntegrationFlowBuilder builder = - IntegrationFlow.from(MessageConsumer.class, gateway -> gateway.beanName("elasticsearchConsumer")); + IntegrationFlow elasticsearchConsumerFlow(@Qualifier("aggregator") MessageHandler aggregator, + ElasticsearchConsumerProperties properties, @Qualifier("indexingHandler") MessageHandler indexingHandler) { + + final IntegrationFlowBuilder builder = IntegrationFlow.from(MessageConsumer.class, + gateway -> gateway.beanName("elasticsearchConsumer")); if (properties.getBatchSize() > 1) { builder.handle(aggregator); } @@ -133,10 +135,8 @@ IntegrationFlow elasticsearchConsumerFlow( } @Bean - public MessageHandler indexingHandler( - ElasticsearchClient elasticsearchClient, - ElasticsearchConsumerProperties consumerProperties - ) { + public MessageHandler indexingHandler(ElasticsearchClient elasticsearchClient, + ElasticsearchConsumerProperties consumerProperties) { return message -> { if (message.getPayload() instanceof Iterable) { BulkRequest.Builder builder = new BulkRequest.Builder(); @@ -144,9 +144,10 @@ public MessageHandler indexingHandler( .filter(MessageWrapper.class::isInstance) .map(itemPayload -> ((MessageWrapper) itemPayload).getMessage()) .map(m -> buildIndexRequest(m, consumerProperties)) - .forEach(indexRequest -> - builder.operations(builder1 -> builder1.index(idx -> idx.index(indexRequest.index()).id(indexRequest.id()).document(indexRequest.document()))) - ); + .forEach(indexRequest -> builder + .operations(builder1 -> builder1.index(idx -> idx.index(indexRequest.index()) + .id(indexRequest.id()) + .document(indexRequest.document())))); index(elasticsearchClient, builder.build(), consumerProperties.isAsync()); } @@ -194,11 +195,13 @@ else if (message.getPayload() instanceof Map) { private void index(ElasticsearchClient elasticsearchClient, BulkRequest request, boolean isAsync) { if (isAsync) { - ElasticsearchAsyncClient elasticsearchAsyncClient = new ElasticsearchAsyncClient(elasticsearchClient._transport()); + ElasticsearchAsyncClient elasticsearchAsyncClient = new ElasticsearchAsyncClient( + elasticsearchClient._transport()); CompletableFuture responseCompletableFuture = elasticsearchAsyncClient.bulk(request); responseCompletableFuture.whenComplete((bulkResponse, x) -> { if (x != null) { - throw new IllegalStateException("Error occurred while performing bulk index operation: " + x.getMessage(), x); + throw new IllegalStateException( + "Error occurred while performing bulk index operation: " + x.getMessage(), x); } else { handleBulkResponse(bulkResponse); @@ -212,14 +215,16 @@ private void index(ElasticsearchClient elasticsearchClient, BulkRequest request, handleBulkResponse(bulkResponse); } catch (IOException e) { - throw new IllegalStateException("Error occurred while performing bulk index operation: " + e.getMessage(), e); + throw new IllegalStateException( + "Error occurred while performing bulk index operation: " + e.getMessage(), e); } } } private void index(ElasticsearchClient elasticsearchClient, IndexRequest request, boolean isAsync) { if (isAsync) { - ElasticsearchAsyncClient elasticsearchAsyncClient = new ElasticsearchAsyncClient(elasticsearchClient._transport()); + ElasticsearchAsyncClient elasticsearchAsyncClient = new ElasticsearchAsyncClient( + elasticsearchClient._transport()); CompletableFuture responseCompletableFuture = elasticsearchAsyncClient.index(request); responseCompletableFuture.whenComplete((indexResponse, x) -> { if (x != null) { @@ -248,9 +253,8 @@ private void handleBulkResponse(BulkResponse response) { if (logger.isDebugEnabled()) { logger.debug("itemResponse.error=" + itemResponse.error()); } - logger.error(String.format("Index operation [id=%s, index=%s] failed: %s", - itemResponse.id(), itemResponse.index(), itemResponse.error().toString()) - ); + logger.error(String.format("Index operation [id=%s, index=%s] failed: %s", itemResponse.id(), + itemResponse.index(), itemResponse.error().toString())); } else { var r = itemResponse.get(); @@ -258,12 +262,14 @@ private void handleBulkResponse(BulkResponse response) { if (logger.isDebugEnabled()) { logger.debug("itemResponse:" + r); } - logger.debug(String.format("Index operation [id=%s, index=%s] succeeded: document [id=%s, version=%s] was written on shard %s.", - itemResponse.id(), itemResponse.index(), r.source().get("id"), r.source().get("version"), r.source().get("shardId")) - ); + logger.debug(String.format( + "Index operation [id=%s, index=%s] succeeded: document [id=%s, version=%s] was written on shard %s.", + itemResponse.id(), itemResponse.index(), r.source().get("id"), + r.source().get("version"), r.source().get("shardId"))); } else { - logger.debug(String.format("Index operation [id=%s, index=%s] succeeded", itemResponse.id(), itemResponse.index())); + logger.debug(String.format("Index operation [id=%s, index=%s] succeeded", itemResponse.id(), + itemResponse.index())); } } } @@ -272,20 +278,22 @@ private void handleBulkResponse(BulkResponse response) { if (response.errors()) { String error = response.items() .stream() - .map(bulkResponseItem -> bulkResponseItem.error() != null ? bulkResponseItem.error().toString() : "") - .reduce((errorCause, errorCause2) -> errorCause != null ? errorCause + " : " + errorCause2 : errorCause2) + .map(bulkResponseItem -> bulkResponseItem.error() != null ? bulkResponseItem.error().toString() : "") + .reduce((errorCause, errorCause2) -> errorCause != null ? errorCause + " : " + errorCause2 + : errorCause2) .orElseGet(response::toString); throw new IllegalStateException("Bulk indexing operation completed with failures: " + error); } } private void handleResponse(IndexResponse response) { - logger.debug(String.format("Index operation [index=%s] succeeded: document [id=%s, version=%d] was written on shard %s.", - response.index(), response.id(), response.version(), response.shards().toString()) - ); + logger.debug(String.format( + "Index operation [index=%s] succeeded: document [id=%s, version=%d] was written on shard %s.", + response.index(), response.id(), response.version(), response.shards().toString())); } static class MessageWrapper { + private final Message message; MessageWrapper(Message message) { @@ -295,6 +303,7 @@ static class MessageWrapper { public Message getMessage() { return message; } + } private interface MessageConsumer extends Consumer> { diff --git a/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerProperties.java b/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerProperties.java index a6d7badc..1131256e 100644 --- a/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerProperties.java +++ b/consumer/spring-elasticsearch-consumer/src/main/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerProperties.java @@ -27,44 +27,45 @@ public class ElasticsearchConsumerProperties { /** - * The id of the document to index. - * If set, the INDEX_ID header value overrides this property on a per message basis. + * The id of the document to index. If set, the INDEX_ID header value overrides this + * property on a per message basis. */ Expression id; /** - * Name of the index. - * If set, the INDEX_NAME header value overrides this property on a per message basis. + * Name of the index. If set, the INDEX_NAME header value overrides this property on a + * per message basis. */ String index; /** - * Indicates the shard to route to. - * If not provided, Elasticsearch will default to a hash of the document id. + * Indicates the shard to route to. If not provided, Elasticsearch will default to a + * hash of the document id. */ String routing; /** - * Timeout for the shard to be available. - * If not set, it defaults to 1 minute set by the Elasticsearch client. + * Timeout for the shard to be available. If not set, it defaults to 1 minute set by + * the Elasticsearch client. */ long timeoutSeconds; /** - * Indicates whether the indexing operation is async or not. - * By default indexing is done synchronously. + * Indicates whether the indexing operation is async or not. By default indexing is + * done synchronously. */ boolean async; /** - * Number of items to index for each request. It defaults to 1. - * For values greater than 1 bulk indexing API will be used. + * Number of items to index for each request. It defaults to 1. For values greater + * than 1 bulk indexing API will be used. */ int batchSize = 1; /** - * Timeout in milliseconds after which message group is flushed when bulk indexing is active. - * It defaults to -1, meaning no automatic flush of idle message groups occurs. + * Timeout in milliseconds after which message group is flushed when bulk indexing is + * active. It defaults to -1, meaning no automatic flush of idle message groups + * occurs. */ long groupTimeout = -1L; @@ -123,4 +124,5 @@ public long getGroupTimeout() { public void setGroupTimeout(long groupTimeout) { this.groupTimeout = groupTimeout; } + } diff --git a/consumer/spring-elasticsearch-consumer/src/test/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerApplicationTests.java b/consumer/spring-elasticsearch-consumer/src/test/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerApplicationTests.java index 371ec084..2e7f53a3 100644 --- a/consumer/spring-elasticsearch-consumer/src/test/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerApplicationTests.java +++ b/consumer/spring-elasticsearch-consumer/src/test/java/org/springframework/cloud/fn/consumer/elasticsearch/ElasticsearchConsumerApplicationTests.java @@ -65,9 +65,8 @@ public class ElasticsearchConsumerApplicationTests { @Container static final ElasticsearchContainer elasticsearch = new ElasticsearchContainer( - DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch") - .withTag("7.17.7") - ).withStartupTimeout(Duration.ofSeconds(120)) + DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch").withTag("7.17.7")) + .withStartupTimeout(Duration.ofSeconds(120)) .withStartupAttempts(3); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() @@ -78,12 +77,12 @@ public class ElasticsearchConsumerApplicationTests { public void testBasicJsonString() { this.contextRunner .withPropertyValues("elasticsearch.consumer.index=foo", "elasticsearch.consumer.id=1", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); - final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}"; + final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," + "\"fullName\":\"John Doe\"}"; final Message message = MessageBuilder.withPayload(jsonObject).build(); elasticsearchConsumer.accept(message); @@ -102,14 +101,15 @@ public void testBasicJsonString() { public void testIdPassedAsMessageHeader() { this.contextRunner .withPropertyValues("elasticsearch.consumer.index=foo", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); - final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}"; + final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," + "\"fullName\":\"John Doe\"}"; final Message message = MessageBuilder.withPayload(jsonObject) - .setHeader(ElasticsearchConsumerConfiguration.INDEX_ID_HEADER, "2").build(); + .setHeader(ElasticsearchConsumerConfiguration.INDEX_ID_HEADER, "2") + .build(); log.info("elasticsearchConsumer.accept:{}", message); elasticsearchConsumer.accept(message); @@ -124,13 +124,14 @@ public void testIdPassedAsMessageHeader() { } @Test - @SuppressWarnings({ "unchecked", "rawtypes"}) + @SuppressWarnings({ "unchecked", "rawtypes" }) public void testJsonAsMap() { this.contextRunner .withPropertyValues("elasticsearch.consumer.index=foo", "elasticsearch.consumer.id=3", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); final Map jsonMap = new HashMap<>(); jsonMap.put("age", 10); @@ -160,13 +161,13 @@ public void testJsonAsMap() { public void testAsyncIndexing() { this.contextRunner .withPropertyValues("elasticsearch.consumer.index=foo", "elasticsearch.consumer.async=true", - "elasticsearch.consumer.id=5", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + "elasticsearch.consumer.id=5", + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); - final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}"; + final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," + "\"fullName\":\"John Doe\"}"; final Message message = MessageBuilder.withPayload(jsonObject).build(); log.info("elasticsearchConsumer.accept:{}", message); elasticsearchConsumer.accept(message); @@ -185,16 +186,20 @@ public void testAsyncIndexing() { @SuppressWarnings("unchecked") public void testBulkIndexingWithIdFromHeader() { this.contextRunner - .withPropertyValues("elasticsearch.consumer.index=foo_" + UUID.randomUUID(), "elasticsearch.consumer.batch-size=10", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + .withPropertyValues("elasticsearch.consumer.index=foo_" + UUID.randomUUID(), + "elasticsearch.consumer.batch-size=10", + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); - final ElasticsearchConsumerProperties properties = context.getBean(ElasticsearchConsumerProperties.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); + final ElasticsearchConsumerProperties properties = context + .getBean(ElasticsearchConsumerProperties.class); final ElasticsearchClient elasticsearchClient = context.getBean(ElasticsearchClient.class); - for (int i = 0; i < properties.getBatchSize(); i++) { - final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()).id(Integer.toString(i)).build(); + final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()) + .id(Integer.toString(i)) + .build(); assertThatExceptionOfType(ElasticsearchException.class) .isThrownBy(() -> elasticsearchClient.get(getRequest, JsonData.class)) .withFailMessage("Expected index not found exception for message %d") @@ -202,7 +207,7 @@ public void testBulkIndexingWithIdFromHeader() { final Message message = MessageBuilder .withPayload("{\"seq\":" + i + ",\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}") + + "\"fullName\":\"John Doe\"}") .setHeader(ElasticsearchConsumerConfiguration.INDEX_ID_HEADER, Integer.toString(i)) .build(); log.info("elasticsearchConsumer.accept:{}", message); @@ -210,13 +215,14 @@ public void testBulkIndexingWithIdFromHeader() { } for (int i = 0; i < properties.getBatchSize(); i++) { - final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()).id(Integer.toString(i)).build(); + final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()) + .id(Integer.toString(i)) + .build(); final GetResponse response = elasticsearchClient.get(getRequest, JsonData.class); - assertThat(response.found()) - .withFailMessage("Document with id=%d cannot be found.", i) - .isTrue(); - assertThat(response.source().toJson().asJsonObject().get("seq").toString()).isEqualTo(Integer.toString(i)); + assertThat(response.found()).withFailMessage("Document with id=%d cannot be found.", i).isTrue(); + assertThat(response.source().toJson().asJsonObject().get("seq").toString()) + .isEqualTo(Integer.toString(i)); } }); } @@ -225,16 +231,20 @@ public void testBulkIndexingWithIdFromHeader() { @SuppressWarnings("unchecked") public void testBulkIndexingItemFailure() { this.contextRunner - .withPropertyValues("elasticsearch.consumer.index=foo_" + UUID.randomUUID(), "elasticsearch.consumer.batch-size=10", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + .withPropertyValues("elasticsearch.consumer.index=foo_" + UUID.randomUUID(), + "elasticsearch.consumer.batch-size=10", + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); - final ElasticsearchConsumerProperties properties = context.getBean(ElasticsearchConsumerProperties.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); + final ElasticsearchConsumerProperties properties = context + .getBean(ElasticsearchConsumerProperties.class); final ElasticsearchClient elasticsearchClient = context.getBean(ElasticsearchClient.class); - for (int i = 0; i < properties.getBatchSize(); i++) { - final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()).id(Integer.toString(i)).build(); + final GetRequest getRequest = new GetRequest.Builder().index(properties.getIndex()) + .id(Integer.toString(i)) + .build(); assertThatExceptionOfType(ElasticsearchException.class) .isThrownBy(() -> elasticsearchClient.get(getRequest, JsonData.class)) .withFailMessage("Expected index not found exception for message %d") @@ -242,12 +252,13 @@ public void testBulkIndexingItemFailure() { MessageBuilder builder = MessageBuilder .withPayload("{\"seq\":" + i + ",\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}") + + "\"fullName\":\"John Doe\"}") .setHeader(ElasticsearchConsumerConfiguration.INDEX_ID_HEADER, Integer.toString(i)); if (i == 0) { // set an invalid index name to make the first request fail - builder.setHeader(ElasticsearchConsumerConfiguration.INDEX_NAME_HEADER, "_" + properties.getIndex()); + builder.setHeader(ElasticsearchConsumerConfiguration.INDEX_NAME_HEADER, + "_" + properties.getIndex()); } final Message message = builder.build(); @@ -258,8 +269,7 @@ public void testBulkIndexingItemFailure() { } else { // last invocation - assertThatIllegalStateException() - .isThrownBy(() -> elasticsearchConsumer.accept(message)) + assertThatIllegalStateException().isThrownBy(() -> elasticsearchConsumer.accept(message)) .withMessageContaining("Bulk indexing operation completed with failures"); } } @@ -271,15 +281,16 @@ public void testBulkIndexingItemFailure() { public void testIndexFromMessageHeader() { this.contextRunner .withPropertyValues("elasticsearch.consumer.index=foo", - "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) + "spring.elasticsearch.rest.uris=http://" + elasticsearch.getHttpHostAddress()) .run(context -> { - final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", Consumer.class); - final ElasticsearchConsumerProperties properties = context.getBean(ElasticsearchConsumerProperties.class); + final Consumer> elasticsearchConsumer = context.getBean("elasticsearchConsumer", + Consumer.class); + final ElasticsearchConsumerProperties properties = context + .getBean(ElasticsearchConsumerProperties.class); final String dynamicIndex = properties.getIndex() + "-2"; - final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," - + "\"fullName\":\"John Doe\"}"; + final String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," + "\"fullName\":\"John Doe\"}"; final Message message = MessageBuilder.withPayload(jsonObject) .setHeader(ElasticsearchConsumerConfiguration.INDEX_ID_HEADER, "2") .setHeader(ElasticsearchConsumerConfiguration.INDEX_NAME_HEADER, dynamicIndex) @@ -299,16 +310,18 @@ public void testIndexFromMessageHeader() { @SpringBootApplication static class ElasticsearchConsumerTestApplication { + } @Configuration static class Config extends ElasticsearchConfiguration { + @NonNull @Override public ClientConfiguration clientConfiguration() { - return ClientConfiguration.builder() - .connectedTo(elasticsearch.getHttpHostAddress()) - .build(); + return ClientConfiguration.builder().connectedTo(elasticsearch.getHttpHostAddress()).build(); } + } + } diff --git a/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerConfiguration.java b/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerConfiguration.java index 784418f3..2802d1b7 100644 --- a/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerConfiguration.java +++ b/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerConfiguration.java @@ -56,8 +56,7 @@ public Consumer> fileConsumer(FileWritingMessageHandler fileWritingMe public FileWritingMessageHandler fileWritingMessageHandler(FileNameGenerator fileNameGenerator, @Nullable ComponentCustomizer fileWritingMessageHandlerCustomizer) { - FileWritingMessageHandler handler = - this.properties.getDirectoryExpression() != null + FileWritingMessageHandler handler = this.properties.getDirectoryExpression() != null ? new FileWritingMessageHandler( EXPRESSION_PARSER.parseExpression(this.properties.getDirectoryExpression())) : new FileWritingMessageHandler(this.properties.getDirectory()); diff --git a/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerProperties.java b/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerProperties.java index 30ce5886..f8170616 100644 --- a/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerProperties.java +++ b/consumer/spring-file-consumer/src/main/java/org/springframework/cloud/fn/consumer/file/FileConsumerProperties.java @@ -128,9 +128,7 @@ public void setName(String name) { } public String getNameExpression() { - return (nameExpression != null) - ? nameExpression + " + '" + getSuffix() + "'" - : "'" + name + getSuffix() + "'"; + return (nameExpression != null) ? nameExpression + " + '" + getSuffix() + "'" : "'" + name + getSuffix() + "'"; } public void setNameExpression(String nameExpression) { diff --git a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/AbstractFileConsumerTests.java b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/AbstractFileConsumerTests.java index 0a26929d..5cc1b73b 100644 --- a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/AbstractFileConsumerTests.java +++ b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/AbstractFileConsumerTests.java @@ -54,5 +54,7 @@ public static void afterAll() { @SpringBootApplication static class FileConsumerTestApplication { + } + } diff --git a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/ExpressionTests.java b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/ExpressionTests.java index 91138ff5..2612253e 100644 --- a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/ExpressionTests.java +++ b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/ExpressionTests.java @@ -38,12 +38,11 @@ * @author Artem Bilan * @author Soby Chacko *

- * We don't need a separate SpringBootApplication for this test as there is already one available in this package. - * {@link AbstractFileConsumerTests}. + * We don't need a separate SpringBootApplication for this test as there is already one + * available in this package. {@link AbstractFileConsumerTests}. */ -@SpringBootTest(properties = {"file.consumer.nameExpression = payload.substring(0, 4)", - "file.consumer.directoryExpression = '${java.io.tmpdir}'+'/'+headers.dir", - "file.consumer.suffix=out"}) +@SpringBootTest(properties = { "file.consumer.nameExpression = payload.substring(0, 4)", + "file.consumer.directoryExpression = '${java.io.tmpdir}'+'/'+headers.dir", "file.consumer.suffix=out" }) @DirtiesContext public class ExpressionTests { @@ -60,6 +59,7 @@ public void test() throws Exception { file.deleteOnExit(); assertThat(file.exists()).isTrue(); assertThat("this is something" + System.lineSeparator()) - .isEqualTo(FileCopyUtils.copyToString(new FileReader(file))); + .isEqualTo(FileCopyUtils.copyToString(new FileReader(file))); } + } diff --git a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/TextFileTests.java b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/TextFileTests.java index 60a9b218..2e8390ee 100644 --- a/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/TextFileTests.java +++ b/consumer/spring-file-consumer/src/test/java/org/springframework/cloud/fn/consumer/file/TextFileTests.java @@ -32,7 +32,7 @@ * @author Artem Bilan * @author Soby Chacko */ -@TestPropertySource(properties = {"file.consumer.name = test", "file.consumer.suffix=txt"}) +@TestPropertySource(properties = { "file.consumer.name = test", "file.consumer.suffix=txt" }) public class TextFileTests extends AbstractFileConsumerTests { @Test @@ -41,7 +41,7 @@ public void test() throws Exception { File file = new File(tempDir.toFile(), "test.txt"); assertThat(file.exists()).isTrue(); assertThat("hello file-consumer" + System.lineSeparator()) - .isEqualTo(FileCopyUtils.copyToString(new FileReader(file))); + .isEqualTo(FileCopyUtils.copyToString(new FileReader(file))); } } diff --git a/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerConfiguration.java b/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerConfiguration.java index 2aba1b60..5c1e3795 100644 --- a/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerConfiguration.java +++ b/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerConfiguration.java @@ -52,15 +52,15 @@ public class FtpConsumerConfiguration { public IntegrationFlow ftpInboundFlow(FtpConsumerProperties properties, SessionFactory ftpSessionFactory, @Nullable ComponentCustomizer ftpMessageHandlerSpecCustomizer) { - IntegrationFlowBuilder integrationFlowBuilder = - IntegrationFlow.from(MessageConsumer.class, (gateway) -> gateway.beanName("ftpConsumer")); + IntegrationFlowBuilder integrationFlowBuilder = IntegrationFlow.from(MessageConsumer.class, + (gateway) -> gateway.beanName("ftpConsumer")); - FtpMessageHandlerSpec handlerSpec = - Ftp.outboundAdapter(new FtpRemoteFileTemplate(ftpSessionFactory), properties.getMode()) - .remoteDirectory(properties.getRemoteDir()) - .remoteFileSeparator(properties.getRemoteFileSeparator()) - .autoCreateDirectory(properties.isAutoCreateDir()) - .temporaryFileSuffix(properties.getTmpFileSuffix()); + FtpMessageHandlerSpec handlerSpec = Ftp + .outboundAdapter(new FtpRemoteFileTemplate(ftpSessionFactory), properties.getMode()) + .remoteDirectory(properties.getRemoteDir()) + .remoteFileSeparator(properties.getRemoteFileSeparator()) + .autoCreateDirectory(properties.isAutoCreateDir()) + .temporaryFileSuffix(properties.getTmpFileSuffix()); if (properties.getFilenameExpression() != null) { handlerSpec.fileNameExpression( EXPRESSION_PARSER.parseExpression(properties.getFilenameExpression()).getExpressionString()); @@ -70,9 +70,7 @@ public IntegrationFlow ftpInboundFlow(FtpConsumerProperties properties, SessionF ftpMessageHandlerSpecCustomizer.customize(handlerSpec); } - return integrationFlowBuilder - .handle(handlerSpec) - .get(); + return integrationFlowBuilder.handle(handlerSpec).get(); } private interface MessageConsumer extends Consumer> { diff --git a/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerProperties.java b/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerProperties.java index b99ff3eb..5ae6197f 100644 --- a/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerProperties.java +++ b/consumer/spring-ftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerProperties.java @@ -136,4 +136,5 @@ public String getRemoteFileSeparator() { public void setRemoteFileSeparator(String remoteFileSeparator) { this.remoteFileSeparator = remoteFileSeparator; } + } diff --git a/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerPropertiesTests.java b/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerPropertiesTests.java index 4d449a9c..c2908a57 100644 --- a/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerPropertiesTests.java +++ b/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerPropertiesTests.java @@ -36,8 +36,7 @@ public class FtpConsumerPropertiesTests { @Test public void remoteDirCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.remoteDir:/remote") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.remoteDir:/remote").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -48,8 +47,7 @@ public void remoteDirCanBeCustomized() { @Test public void autoCreateDirCanBeDisabled() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.autoCreateDir:false") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.autoCreateDir:false").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -60,8 +58,7 @@ public void autoCreateDirCanBeDisabled() { @Test public void tmpFileSuffixCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.tmpFileSuffix:.foo") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.tmpFileSuffix:.foo").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -72,8 +69,7 @@ public void tmpFileSuffixCanBeCustomized() { @Test public void tmpFileRemoteDirCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.temporaryRemoteDir:/foo") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.temporaryRemoteDir:/foo").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -84,8 +80,7 @@ public void tmpFileRemoteDirCanBeCustomized() { @Test public void remoteFileSeparatorCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.remoteFileSeparator:\\") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.remoteFileSeparator:\\").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -96,8 +91,7 @@ public void remoteFileSeparatorCanBeCustomized() { @Test public void useTemporaryFileNameCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.useTemporaryFilename:false") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.useTemporaryFilename:false").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -108,8 +102,7 @@ public void useTemporaryFileNameCanBeCustomized() { @Test public void fileExistsModeCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.consumer.mode:FAIL") - .applyTo(context); + TestPropertyValues.of("ftp.consumer.mode:FAIL").applyTo(context); context.register(Conf.class); context.refresh(); FtpConsumerProperties properties = context.getBean(FtpConsumerProperties.class); @@ -122,4 +115,5 @@ public void fileExistsModeCanBeCustomized() { static class Conf { } + } diff --git a/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerTests.java b/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerTests.java index e7815d31..08712329 100644 --- a/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerTests.java +++ b/consumer/spring-ftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/ftp/FtpConsumerTests.java @@ -33,13 +33,8 @@ @DirtiesContext @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "ftp.consumer.remoteDir = ftpTarget", - "ftp.factory.username = foo", - "ftp.factory.password = foo", - "ftp.consumer.mode = FAIL", - "ftp.consumer.filenameExpression = payload.name.toUpperCase()" - }) + properties = { "ftp.consumer.remoteDir = ftpTarget", "ftp.factory.username = foo", "ftp.factory.password = foo", + "ftp.consumer.mode = FAIL", "ftp.consumer.filenameExpression = payload.name.toUpperCase()" }) public class FtpConsumerTests extends FtpTestSupport { @Autowired @@ -72,5 +67,7 @@ public void serverRefreshed() { // noop test to test the dirs are refreshed prop @SpringBootApplication static class FtpConsumerTestApplication { + } + } diff --git a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/DefaultInitializationScriptResource.java b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/DefaultInitializationScriptResource.java index df838db3..a3a641e1 100644 --- a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/DefaultInitializationScriptResource.java +++ b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/DefaultInitializationScriptResource.java @@ -25,8 +25,8 @@ import org.springframework.core.io.ByteArrayResource; /** - * An in-memory script crafted for dropping-creating the table we're working with. - * All columns are created as VARCHAR(2000). + * An in-memory script crafted for dropping-creating the table we're working with. All + * columns are created as VARCHAR(2000). * * @author Eric Bottard * @author Thomas Risberg diff --git a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerConfiguration.java b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerConfiguration.java index 80ed1046..3befc0ca 100644 --- a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerConfiguration.java +++ b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerConfiguration.java @@ -126,10 +126,10 @@ private static String generateSql(String tableName, Set columns) { @Bean IntegrationFlow jdbcConsumerFlow(@Qualifier("aggregator") MessageHandler aggregator, - JdbcMessageHandler jdbcMessageHandler) { + JdbcMessageHandler jdbcMessageHandler) { - final IntegrationFlowBuilder builder = - IntegrationFlow.from(Consumer.class, gateway -> gateway.beanName("jdbcConsumer")); + final IntegrationFlowBuilder builder = IntegrationFlow.from(Consumer.class, + gateway -> gateway.beanName("jdbcConsumer")); if (properties.getBatchSize() > 1 || properties.getIdleTimeout() > 0) { builder.handle(aggregator); } @@ -172,8 +172,8 @@ public JdbcMessageHandler jdbcMessageHandler(DataSource dataSource) { this.spelExpressionParser.parseExpression(qualified)); } catch (SpelParseException e) { - logger.info("failed to parse qualified fallback expression " + qualified + - "; be sure your expression uses the 'payload.' prefix where necessary"); + logger.info("failed to parse qualified fallback expression " + qualified + + "; be sure your expression uses the 'payload.' prefix where necessary"); } } } @@ -189,17 +189,17 @@ protected void handleMessageInternal(final Message message) { ? message.getHeaders().get(MessageHeaders.CONTENT_TYPE).toString() : MimeTypeUtils.APPLICATION_JSON_VALUE; if (message.getPayload() instanceof Iterable) { - Stream messageStream = - StreamSupport.stream(((Iterable) message.getPayload()).spliterator(), false) - .map(payload -> { - if (payload instanceof byte[]) { - return convertibleContentType(contentType) ? - new String(((byte[]) payload)) : payload; - } - else { - return payload; - } - }); + Stream messageStream = StreamSupport + .stream(((Iterable) message.getPayload()).spliterator(), false) + .map(payload -> { + if (payload instanceof byte[]) { + return convertibleContentType(contentType) ? new String(((byte[]) payload)) + : payload; + } + else { + return payload; + } + }); convertedMessage = new MutableMessage<>(messageStream.collect(Collectors.toList()), message.getHeaders()); } @@ -213,8 +213,8 @@ protected void handleMessageInternal(final Message message) { super.handleMessageInternal(convertedMessage); } }; - SqlParameterSourceFactory parameterSourceFactory = - new ParameterFactory(columnExpressionVariations, this.evaluationContext); + SqlParameterSourceFactory parameterSourceFactory = new ParameterFactory(columnExpressionVariations, + this.evaluationContext); jdbcMessageHandler.setSqlParameterSourceFactory(parameterSourceFactory); return jdbcMessageHandler; } @@ -228,9 +228,8 @@ public DataSourceInitializer nonBootDataSourceInitializer(DataSource dataSource, databasePopulator.setIgnoreFailedDrops(true); dataSourceInitializer.setDatabasePopulator(databasePopulator); if ("true".equals(properties.getInitialize())) { - databasePopulator.addScript( - new DefaultInitializationScriptResource(this.properties.getTableName(), - this.properties.getColumnsMap().keySet())); + databasePopulator.addScript(new DefaultInitializationScriptResource(this.properties.getTableName(), + this.properties.getColumnsMap().keySet())); } else { databasePopulator.addScript(resourceLoader.getResource(this.properties.getInitialize())); diff --git a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerProperties.java b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerProperties.java index a3c5d3f1..23c4b747 100644 --- a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerProperties.java +++ b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerProperties.java @@ -38,8 +38,8 @@ public class JdbcConsumerProperties { private String tableName = "messages"; /** - * The comma separated colon-based pairs of column names and SpEL expressions for values to insert/update. - * Names are used at initialization time to issue the DDL. + * The comma separated colon-based pairs of column names and SpEL expressions for + * values to insert/update. Names are used at initialization time to issue the DDL. */ private String columns = "payload:payload.toString()"; @@ -106,4 +106,5 @@ Map getColumnsMap() { } return this.columnsMap; } + } diff --git a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/ShorthandMapConverter.java b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/ShorthandMapConverter.java index 78534e99..7bb966c0 100644 --- a/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/ShorthandMapConverter.java +++ b/consumer/spring-jdbc-consumer/src/main/java/org/springframework/cloud/fn/consumer/jdbc/ShorthandMapConverter.java @@ -23,12 +23,14 @@ import org.springframework.util.Assert; /** - * A Converter from String to Map that accepts csv {@literal key:value} pairs - * (similar to what comes out of the box in Spring Core) but also simple - * {@literal key} items, in which case the value is assumed to be equal to the key. + * A Converter from String to Map that accepts csv {@literal key:value} pairs (similar to + * what comes out of the box in Spring Core) but also simple {@literal key} items, in + * which case the value is assumed to be equal to the key. *

- *

Additionally, commas and colons can be escaped by using a backslash, which is - * useful if said mappings are to be used for SpEL for example.

+ *

+ * Additionally, commas and colons can be escaped by using a backslash, which is useful if + * said mappings are to be used for SpEL for example. + *

* * @author Eric Bottard * @author Artem Bilan @@ -49,8 +51,8 @@ public Map convert(String source) { } // Split on colon, if not preceded by backslash String[] keyValuePair = unescaped.split("(? message = MessageBuilder.withPayload(sent).build(); jdbcConsumer.accept(message); } - Awaitility.await().until(() -> jdbcOperations - .queryForObject("select count(*) from messages", Integer.class), value -> value == numberOfInserts); + Awaitility.await() + .until(() -> jdbcOperations.queryForObject("select count(*) from messages", Integer.class), + value -> value == numberOfInserts); } } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/DataReceivedAsByteArrayTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/DataReceivedAsByteArrayTests.java index e4e9b9df..468bd68f 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/DataReceivedAsByteArrayTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/DataReceivedAsByteArrayTests.java @@ -41,8 +41,8 @@ public void testInsertionWhenDataReceivedAsByteArray() { String hello = "{\"a\": \"hello\"}"; final Message message = MessageBuilder.withPayload(hello.getBytes()).build(); jdbcConsumer.accept(message); - final Integer count = - jdbcOperations.queryForObject("select count(*) from messages where a = ?", Integer.class, "hello"); + final Integer count = jdbcOperations.queryForObject("select count(*) from messages where a = ?", Integer.class, + "hello"); assertThat(count).isEqualTo(1); } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ExplicitTableCreationTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ExplicitTableCreationTests.java index 6c2c065c..ec6d5eb0 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ExplicitTableCreationTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ExplicitTableCreationTests.java @@ -34,9 +34,8 @@ * @author Soby Chacko * @author Szabolcs Stremler */ -@TestPropertySource(properties = {"jdbc.consumer.tableName=foobar", - "jdbc.consumer.initialize=classpath:explicit-script.sql", - "jdbc.consumer.columns=a,b"}) +@TestPropertySource(properties = { "jdbc.consumer.tableName=foobar", + "jdbc.consumer.initialize=classpath:explicit-script.sql", "jdbc.consumer.columns=a,b" }) public class ExplicitTableCreationTests extends JdbcConsumerApplicationTests { @Test @@ -44,9 +43,8 @@ public void testInsertion() { Payload sent = new Payload("hello", 42); final Message message = MessageBuilder.withPayload(sent).build(); jdbcConsumer.accept(message); - Payload result = - jdbcOperations.query("select a, b from foobar", new BeanPropertyRowMapper<>(Payload.class)) - .get(0); + Payload result = jdbcOperations.query("select a, b from foobar", new BeanPropertyRowMapper<>(Payload.class)) + .get(0); assertThat(result).usingRecursiveComparison().isEqualTo(sent); } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/HeaderInsertTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/HeaderInsertTests.java index b8c1ceaf..ec47d365 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/HeaderInsertTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/HeaderInsertTests.java @@ -39,10 +39,10 @@ public class HeaderInsertTests extends JdbcConsumerApplicationTests { @Test public void testHeaderInsertion() { Payload sent = new Payload("hello", 42); - final Message message = MessageBuilder.withPayload(sent) - .setHeader("foo", "bar").build(); + final Message message = MessageBuilder.withPayload(sent).setHeader("foo", "bar").build(); jdbcConsumer.accept(message); - assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ?", - Integer.class, "bar")).isEqualTo(1); + assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ?", Integer.class, "bar")) + .isEqualTo(1); } + } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ImplicitTableCreationTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ImplicitTableCreationTests.java index fb0eaaaa..ef7ef826 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ImplicitTableCreationTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/ImplicitTableCreationTests.java @@ -34,10 +34,8 @@ * @author Soby Chacko * @author Szabolcs Stremler */ -@TestPropertySource(properties = { - "jdbc.consumer.tableName=no_script", - "jdbc.consumer.initialize=true", - "jdbc.consumer.columns=a,b"}) +@TestPropertySource(properties = { "jdbc.consumer.tableName=no_script", "jdbc.consumer.initialize=true", + "jdbc.consumer.columns=a,b" }) public class ImplicitTableCreationTests extends JdbcConsumerApplicationTests { @Test @@ -45,8 +43,8 @@ public void testInsertion() { Payload sent = new Payload("hello", 42); final Message message = MessageBuilder.withPayload(sent).build(); jdbcConsumer.accept(message); - Payload result = jdbcOperations - .query("select a, b from no_script", new BeanPropertyRowMapper<>(Payload.class)).get(0); + Payload result = jdbcOperations.query("select a, b from no_script", new BeanPropertyRowMapper<>(Payload.class)) + .get(0); assertThat(result).usingRecursiveComparison().isEqualTo(sent); } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerApplicationTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerApplicationTests.java index c069ca3b..259be577 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerApplicationTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JdbcConsumerApplicationTests.java @@ -88,6 +88,7 @@ public String toString() { @SpringBootApplication static class JdbcConsumerTestApplication { + } } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JsonStringPayloadInsertTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JsonStringPayloadInsertTests.java index c167e70e..571ad8e3 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JsonStringPayloadInsertTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/JsonStringPayloadInsertTests.java @@ -47,15 +47,15 @@ public void testInsertion() { jdbcConsumer.accept(message2); final Message message3 = MessageBuilder.withPayload(stringC).build(); jdbcConsumer.accept(message3); - assertThat(jdbcOperations.queryForObject( - "select count(*) from messages where a = ? and b = ?", - Integer.class, "hello1", 42)).isEqualTo(1); - assertThat(jdbcOperations.queryForObject( - "select count(*) from messages where a = ? and b IS NULL", - Integer.class, "hello2")).isEqualTo(1); - assertThat(jdbcOperations.queryForObject( - "select count(*) from messages where a = ? and b IS NULL", - Integer.class, "hello3")).isEqualTo(1); + assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ? and b = ?", Integer.class, + "hello1", 42)) + .isEqualTo(1); + assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ? and b IS NULL", + Integer.class, "hello2")) + .isEqualTo(1); + assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ? and b IS NULL", + Integer.class, "hello3")) + .isEqualTo(1); } } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/MapPayloadInsertTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/MapPayloadInsertTests.java index 9ecce9cf..40db3f59 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/MapPayloadInsertTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/MapPayloadInsertTests.java @@ -58,12 +58,15 @@ public void testInsertion() { jdbcConsumer.accept(message2); final Message> message3 = MessageBuilder.withPayload(mapC).build(); jdbcConsumer.accept(message3); - assertThat(namedParameterJdbcOperations.queryForObject( - "select count(*) from messages where a = :a and b = :b", mapA, Integer.class)).isEqualTo(1); - assertThat(namedParameterJdbcOperations.queryForObject( - "select count(*) from messages where a = :a and b IS NULL", mapB, Integer.class)).isEqualTo(1); - assertThat(namedParameterJdbcOperations.queryForObject( - "select count(*) from messages where a = :a and b IS NULL", mapC, Integer.class)).isEqualTo(1); + assertThat(namedParameterJdbcOperations.queryForObject("select count(*) from messages where a = :a and b = :b", + mapA, Integer.class)) + .isEqualTo(1); + assertThat(namedParameterJdbcOperations + .queryForObject("select count(*) from messages where a = :a and b IS NULL", mapB, Integer.class)) + .isEqualTo(1); + assertThat(namedParameterJdbcOperations + .queryForObject("select count(*) from messages where a = :a and b IS NULL", mapC, Integer.class)) + .isEqualTo(1); } } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SimpleMappingTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SimpleMappingTests.java index b69e4755..02cba89d 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SimpleMappingTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SimpleMappingTests.java @@ -42,8 +42,8 @@ public void testInsertion() { Payload sent = new Payload("hello", 42); final Message message = MessageBuilder.withPayload(sent).build(); jdbcConsumer.accept(message); - Payload result = jdbcOperations - .query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)).get(0); + Payload result = jdbcOperations.query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)) + .get(0); assertThat(result).usingRecursiveComparison().isEqualTo(sent); } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SpELTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SpELTests.java index c7906006..670fbdaa 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SpELTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/SpELTests.java @@ -44,8 +44,8 @@ public void testInsertion() { final Message message = MessageBuilder.withPayload(sent).build(); jdbcConsumer.accept(message); Payload expected = new Payload("hell", 666); - Payload result = jdbcOperations - .query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)).get(0); + Payload result = jdbcOperations.query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)) + .get(0); assertThat(result).usingRecursiveComparison().isEqualTo(expected); } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/UnqualifiableColumnExpressionTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/UnqualifiableColumnExpressionTests.java index 3f5f829a..1e78bcec 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/UnqualifiableColumnExpressionTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/UnqualifiableColumnExpressionTests.java @@ -37,10 +37,12 @@ public class UnqualifiableColumnExpressionTests extends JdbcConsumerApplicationT @Test public void doesNotFailParsingUnqualifiableExpression() { - // if the app initializes, the test condition passes, but go ahead and apply the column expression anyway + // if the app initializes, the test condition passes, but go ahead and apply the + // column expression anyway jdbcConsumer.accept(MessageBuilder.withPayload(new Payload("desrever", 123)).build()); - assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ? and b = ?", - Integer.class, "reversed", 123)).isEqualTo(1); + assertThat(jdbcOperations.queryForObject("select count(*) from messages where a = ? and b = ?", Integer.class, + "reversed", 123)) + .isEqualTo(1); } } diff --git a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/VaryingInsertTests.java b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/VaryingInsertTests.java index 8fafda2b..f91065a7 100644 --- a/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/VaryingInsertTests.java +++ b/consumer/spring-jdbc-consumer/src/test/java/org/springframework/cloud/fn/consumer/jdbc/VaryingInsertTests.java @@ -52,8 +52,8 @@ public void testInsertion() { jdbcConsumer.accept(message3); final Message message4 = MessageBuilder.withPayload(d).build(); jdbcConsumer.accept(message4); - List result = jdbcOperations - .query("select a, b from messages", new BeanPropertyRowMapper<>(Payload.class)); + List result = jdbcOperations.query("select a, b from messages", + new BeanPropertyRowMapper<>(Payload.class)); Assertions.assertThat(result).extracting("a").containsExactly("hello", "world", "bonjour", null); Assertions.assertThat(result).extracting("b").contains(42, 12, 22, null); } diff --git a/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfiguration.java b/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfiguration.java index b3be0ea2..650c1a21 100644 --- a/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfiguration.java +++ b/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfiguration.java @@ -37,11 +37,10 @@ import org.springframework.messaging.MessageChannel; /** - * A configuration for Apache Kafka Publisher (Consumer function). - * Uses a {@link KafkaProducerMessageHandlerSpec} to publish a message to Kafka topic. + * A configuration for Apache Kafka Publisher (Consumer function). Uses a + * {@link KafkaProducerMessageHandlerSpec} to publish a message to Kafka topic. * * @author Artem Bilan - * * @since 4.0 */ @AutoConfiguration(after = KafkaAutoConfiguration.class) @@ -60,10 +59,8 @@ public Consumer> kafkaPublisher(KafkaProducerMessageHandler kaf @Bean public KafkaProducerMessageHandlerSpec kafkaProducerMessageHandlerSpec(KafkaTemplate kafkaTemplate, - KafkaPublisherProperties kafkaPublisherProperties, - PublishSubscribeChannel kafkaPublisherSuccessChannel, - PublishSubscribeChannel kafkaPublisherFailureChannel, - PublishSubscribeChannel kafkaPublisherFuturesChannel, + KafkaPublisherProperties kafkaPublisherProperties, PublishSubscribeChannel kafkaPublisherSuccessChannel, + PublishSubscribeChannel kafkaPublisherFailureChannel, PublishSubscribeChannel kafkaPublisherFuturesChannel, @Nullable ComponentCustomizer> kafkaProducerSpecComponentCustomizer) { var kafkaProducerMessageHandlerSpec = Kafka.outboundChannelAdapter(kafkaTemplate); @@ -73,15 +70,24 @@ public Consumer> kafkaPublisher(KafkaProducerMessageHandler kaf mapper.from(kafkaPublisherProperties.getTopic()).to(kafkaProducerMessageHandlerSpec::topic); mapper.from(kafkaPublisherProperties.getTopicExpression()).to(kafkaProducerMessageHandlerSpec::topicExpression); mapper.from(kafkaPublisherProperties.getKey()).to(kafkaProducerMessageHandlerSpec::messageKey); - mapper.from(kafkaPublisherProperties.getKeyExpression()).to(kafkaProducerMessageHandlerSpec::messageKeyExpression); + mapper.from(kafkaPublisherProperties.getKeyExpression()) + .to(kafkaProducerMessageHandlerSpec::messageKeyExpression); mapper.from(kafkaPublisherProperties.getPartition()).to(kafkaProducerMessageHandlerSpec::partitionId); - mapper.from(kafkaPublisherProperties.getPartitionExpression()).to(kafkaProducerMessageHandlerSpec::partitionIdExpression); - mapper.from(kafkaPublisherProperties.getTimestamp()).as(ValueExpression::new).to(kafkaProducerMessageHandlerSpec::timestampExpression); - mapper.from(kafkaPublisherProperties.getTimestampExpression()).to(kafkaProducerMessageHandlerSpec::timestampExpression); - mapper.from(kafkaPublisherProperties.getSendTimeout()).as(Duration::toMillis).to(kafkaProducerMessageHandlerSpec::sendTimeout); - mapper.from(kafkaPublisherProperties.isUseTemplateConverter()).to(kafkaProducerMessageHandlerSpec::useTemplateConverter); - - kafkaProducerMessageHandlerSpec.headerMapper(new DefaultKafkaHeaderMapper(kafkaPublisherProperties.getMappedHeaders())); + mapper.from(kafkaPublisherProperties.getPartitionExpression()) + .to(kafkaProducerMessageHandlerSpec::partitionIdExpression); + mapper.from(kafkaPublisherProperties.getTimestamp()) + .as(ValueExpression::new) + .to(kafkaProducerMessageHandlerSpec::timestampExpression); + mapper.from(kafkaPublisherProperties.getTimestampExpression()) + .to(kafkaProducerMessageHandlerSpec::timestampExpression); + mapper.from(kafkaPublisherProperties.getSendTimeout()) + .as(Duration::toMillis) + .to(kafkaProducerMessageHandlerSpec::sendTimeout); + mapper.from(kafkaPublisherProperties.isUseTemplateConverter()) + .to(kafkaProducerMessageHandlerSpec::useTemplateConverter); + + kafkaProducerMessageHandlerSpec + .headerMapper(new DefaultKafkaHeaderMapper(kafkaPublisherProperties.getMappedHeaders())); kafkaProducerMessageHandlerSpec.sendSuccessChannel(kafkaPublisherSuccessChannel); kafkaProducerMessageHandlerSpec.sendFailureChannel(kafkaPublisherFailureChannel); diff --git a/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherProperties.java b/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherProperties.java index 4994cab6..a5022786 100644 --- a/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherProperties.java +++ b/consumer/spring-kafka-publisher/src/main/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherProperties.java @@ -25,14 +25,14 @@ * Properties for the Kafka Publisher (Consumer function). * * @author Artem Bilan - * * @since 4.0 */ @ConfigurationProperties("kafka.publisher") public class KafkaPublisherProperties { /** - * Kafka topic - overridden by topicExpression, if supplied. Defaults to KafkaTemplate.getDefaultTopic() + * Kafka topic - overridden by topicExpression, if supplied. Defaults to + * KafkaTemplate.getDefaultTopic() */ private String topic; @@ -77,7 +77,8 @@ public class KafkaPublisherProperties { private boolean sync; /** - * How long Kafka producer handler should wait for send operation results. Defaults to 10 seconds. + * How long Kafka producer handler should wait for send operation results. Defaults to + * 10 seconds. */ private Duration sendTimeout = Duration.ofSeconds(10); diff --git a/consumer/spring-kafka-publisher/src/test/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfigurationTests.java b/consumer/spring-kafka-publisher/src/test/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfigurationTests.java index 23c387a5..4977ee43 100644 --- a/consumer/spring-kafka-publisher/src/test/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfigurationTests.java +++ b/consumer/spring-kafka-publisher/src/test/java/org/springframework/cloud/fn/consumer/kafka/KafkaPublisherConfigurationTests.java @@ -52,98 +52,87 @@ /** * @author Artem Bilan - * * @since 4.0 */ @EmbeddedKafka(partitions = 1, controlledShutdown = true) public class KafkaPublisherConfigurationTests { final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - IntegrationAutoConfiguration.class, - KafkaAutoConfiguration.class, - KafkaPublisherConfiguration.class, - SpelExpressionConverterConfiguration.class)); + .withConfiguration(AutoConfigurations.of(IntegrationAutoConfiguration.class, KafkaAutoConfiguration.class, + KafkaPublisherConfiguration.class, SpelExpressionConverterConfiguration.class)); @Test void defaultTopicReceivesTheRecord() { String defaultTopic = "DEFAULT_TOPIC"; - this.contextRunner.withPropertyValues("spring.kafka.template.defaultTopic=" + defaultTopic) - .run((context) -> { - KafkaTemplate kafkaTemplate = obtainKafkaTemplate(context); - Consumer> kafkaPublisher = getKafkaPublisher(context); - String testData = "test data"; - kafkaPublisher.accept(new GenericMessage<>(testData)); - ConsumerRecord receive = kafkaTemplate.receive(defaultTopic, 0, 0, Duration.ofSeconds(10)); - assertThat(receive).extracting(ConsumerRecord::value).isEqualTo(testData); - }); + this.contextRunner.withPropertyValues("spring.kafka.template.defaultTopic=" + defaultTopic).run((context) -> { + KafkaTemplate kafkaTemplate = obtainKafkaTemplate(context); + Consumer> kafkaPublisher = getKafkaPublisher(context); + String testData = "test data"; + kafkaPublisher.accept(new GenericMessage<>(testData)); + ConsumerRecord receive = kafkaTemplate.receive(defaultTopic, 0, 0, Duration.ofSeconds(10)); + assertThat(receive).extracting(ConsumerRecord::value).isEqualTo(testData); + }); } @Test void wrongPartitionViaProperties() { - this.contextRunner.withPropertyValues( - "spring.kafka.producer.properties[max.block.ms]=1000", - "kafka.publisher.topic=topic1", - "kafka.publisher.partition=1", // Our broker allows only one partition for auto-created topic - "kafka.publisher.sync=true") - .run((context) -> { - Consumer> kafkaConsumer = getKafkaPublisher(context); - assertThatExceptionOfType(MessageHandlingException.class) - .isThrownBy(() -> kafkaConsumer.accept(new GenericMessage<>("test data"))) - .withCauseInstanceOf(KafkaException.class) - .withStackTraceContaining("not present in metadata after 1000 ms."); - }); + this.contextRunner + .withPropertyValues("spring.kafka.producer.properties[max.block.ms]=1000", "kafka.publisher.topic=topic1", + "kafka.publisher.partition=1", // Our broker allows only one partition + // for auto-created topic + "kafka.publisher.sync=true") + .run((context) -> { + Consumer> kafkaConsumer = getKafkaPublisher(context); + assertThatExceptionOfType(MessageHandlingException.class) + .isThrownBy(() -> kafkaConsumer.accept(new GenericMessage<>("test data"))) + .withCauseInstanceOf(KafkaException.class) + .withStackTraceContaining("not present in metadata after 1000 ms."); + }); } @Test void successChannelInteractionAndMappedHeaders() { - this.contextRunner.withPropertyValues("kafka.publisher.topicExpression=headers.topic", - "kafka.publisher.mappedHeaders=mapped") - .run((context) -> { - KafkaTemplate kafkaTemplate = obtainKafkaTemplate(context); - Consumer> kafkaConsumer = getKafkaPublisher(context); - - PublishSubscribeChannel kafkaConsumerSuccessChannel = - context.getBean("kafkaPublisherSuccessChannel", PublishSubscribeChannel.class); - - Sinks.One> successSend = Sinks.one(); - - kafkaConsumerSuccessChannel.subscribe(successSend::tryEmitValue); - - String testTopic = "topic2"; - String testData = "some other data"; - Message testMessage = - MessageBuilder.withPayload(testData) - .setHeader("topic", testTopic) - .setHeader("mapped", "mapped value") - .setHeader("not mapped", "not mapped") - .build(); - - kafkaConsumer.accept(testMessage); - - ConsumerRecord receive = kafkaTemplate.receive(testTopic, 0, 0, Duration.ofSeconds(10)); - assertThat(receive).extracting(ConsumerRecord::value).isEqualTo(testData); - Map headers = - Arrays.stream(receive.headers().toArray()) - .collect(Collectors.toMap(Header::key, (header) -> new String(header.value()))); - assertThat(headers) - .containsEntry("mapped", "mapped value") - .doesNotContainKeys("topic", "not mapped"); - - Message successMessage = successSend.asMono().block(Duration.ofSeconds(10)); - - assertThat(successMessage) - .satisfies(message -> { - assertThat(message.getPayload()).isEqualTo(testData); - MessageHeaders messageHeaders = message.getHeaders(); - assertThat(messageHeaders) - .containsKeys("topic", "mapped", "not mapped", KafkaHeaders.RECORD_METADATA); - assertThat(messageHeaders.get(KafkaHeaders.RECORD_METADATA)) - .isInstanceOf(RecordMetadata.class) - .extracting("topicPartition") - .isEqualTo(new TopicPartition(testTopic, 0)); - }); + this.contextRunner + .withPropertyValues("kafka.publisher.topicExpression=headers.topic", "kafka.publisher.mappedHeaders=mapped") + .run((context) -> { + KafkaTemplate kafkaTemplate = obtainKafkaTemplate(context); + Consumer> kafkaConsumer = getKafkaPublisher(context); + + PublishSubscribeChannel kafkaConsumerSuccessChannel = context.getBean("kafkaPublisherSuccessChannel", + PublishSubscribeChannel.class); + + Sinks.One> successSend = Sinks.one(); + + kafkaConsumerSuccessChannel.subscribe(successSend::tryEmitValue); + + String testTopic = "topic2"; + String testData = "some other data"; + Message testMessage = MessageBuilder.withPayload(testData) + .setHeader("topic", testTopic) + .setHeader("mapped", "mapped value") + .setHeader("not mapped", "not mapped") + .build(); + + kafkaConsumer.accept(testMessage); + + ConsumerRecord receive = kafkaTemplate.receive(testTopic, 0, 0, Duration.ofSeconds(10)); + assertThat(receive).extracting(ConsumerRecord::value).isEqualTo(testData); + Map headers = Arrays.stream(receive.headers().toArray()) + .collect(Collectors.toMap(Header::key, (header) -> new String(header.value()))); + assertThat(headers).containsEntry("mapped", "mapped value").doesNotContainKeys("topic", "not mapped"); + + Message successMessage = successSend.asMono().block(Duration.ofSeconds(10)); + + assertThat(successMessage).satisfies(message -> { + assertThat(message.getPayload()).isEqualTo(testData); + MessageHeaders messageHeaders = message.getHeaders(); + assertThat(messageHeaders).containsKeys("topic", "mapped", "not mapped", + KafkaHeaders.RECORD_METADATA); + assertThat(messageHeaders.get(KafkaHeaders.RECORD_METADATA)).isInstanceOf(RecordMetadata.class) + .extracting("topicPartition") + .isEqualTo(new TopicPartition(testTopic, 0)); }); + }); } @SuppressWarnings("unchecked") diff --git a/consumer/spring-log-consumer/src/main/java/org/springframework/cloud/fn/consumer/log/LogConsumerConfiguration.java b/consumer/spring-log-consumer/src/main/java/org/springframework/cloud/fn/consumer/log/LogConsumerConfiguration.java index ede6abaf..bce52c5e 100644 --- a/consumer/spring-log-consumer/src/main/java/org/springframework/cloud/fn/consumer/log/LogConsumerConfiguration.java +++ b/consumer/spring-log-consumer/src/main/java/org/springframework/cloud/fn/consumer/log/LogConsumerConfiguration.java @@ -25,11 +25,11 @@ import org.springframework.messaging.Message; /** - * The Configuration class for {@link Consumer} which logs incoming data. - * For the logging logic a Spring Integration {@link org.springframework.integration.handler.LoggingHandler} - * is used. - * If incoming payload is a {@code byte[]} and incoming message {@code contentType} header is text-compatible - * (e.g. {@code application/json}), it is converted into a {@link String}. + * The Configuration class for {@link Consumer} which logs incoming data. For the logging + * logic a Spring Integration + * {@link org.springframework.integration.handler.LoggingHandler} is used. If incoming + * payload is a {@code byte[]} and incoming message {@code contentType} header is + * text-compatible (e.g. {@code application/json}), it is converted into a {@link String}. * Otherwise the payload is passed to logger as is. * * @author Artem Bilan @@ -41,8 +41,8 @@ public class LogConsumerConfiguration { @Bean IntegrationFlow logConsumerFlow(LogConsumerProperties logSinkProperties) { return IntegrationFlow.from(MessageConsumer.class, (gateway) -> gateway.beanName("logConsumer")) - .log(logSinkProperties.getLevel(), logSinkProperties.getName(), logSinkProperties.getExpression()) - .nullChannel(); + .log(logSinkProperties.getLevel(), logSinkProperties.getName(), logSinkProperties.getExpression()) + .nullChannel(); } private interface MessageConsumer extends Consumer> { diff --git a/consumer/spring-log-consumer/src/test/java/org/springframework/cloud/fn/consumer/log/LogConsumerApplicationTests.java b/consumer/spring-log-consumer/src/test/java/org/springframework/cloud/fn/consumer/log/LogConsumerApplicationTests.java index 392de1b4..c7b208b0 100644 --- a/consumer/spring-log-consumer/src/test/java/org/springframework/cloud/fn/consumer/log/LogConsumerApplicationTests.java +++ b/consumer/spring-log-consumer/src/test/java/org/springframework/cloud/fn/consumer/log/LogConsumerApplicationTests.java @@ -57,8 +57,8 @@ class LogConsumerApplicationTests { @Test public void testJsonContentType() { Message message = MessageBuilder.withPayload("{\"foo\":\"bar\"}") - .setHeader("contentType", new MimeType("json")) - .build(); + .setHeader("contentType", new MimeType("json")) + .build(); testMessage(message, "{\"foo\":\"bar\"}"); } @@ -77,17 +77,20 @@ private void testMessage(Message message, String expectedPayload) { this.logConsumer.accept(message); verify(logger, times(2)).warn(captor.capture()); -// Message captorMessage = (Message) captor.getAllValues().get(2); -// assertThat(captorMessage.getPayload()).isEqualTo(expectedPayload); -// -// MessageHeaders messageHeaders = captorMessage.getHeaders(); -// assertThat(messageHeaders).hasSize(4); -// -// assertThat(messageHeaders) -// .containsEntry(MessageHeaders.CONTENT_TYPE, message.getHeaders().get(MessageHeaders.CONTENT_TYPE)); + // Message captorMessage = (Message) captor.getAllValues().get(2); + // assertThat(captorMessage.getPayload()).isEqualTo(expectedPayload); + // + // MessageHeaders messageHeaders = captorMessage.getHeaders(); + // assertThat(messageHeaders).hasSize(4); + // + // assertThat(messageHeaders) + // .containsEntry(MessageHeaders.CONTENT_TYPE, + // message.getHeaders().get(MessageHeaders.CONTENT_TYPE)); } @SpringBootApplication static class LogConsumerTestApplication { + } + } diff --git a/consumer/spring-mongodb-consumer/src/main/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerProperties.java b/consumer/spring-mongodb-consumer/src/main/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerProperties.java index 8986ce92..26a99243 100644 --- a/consumer/spring-mongodb-consumer/src/main/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerProperties.java +++ b/consumer/spring-mongodb-consumer/src/main/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerProperties.java @@ -22,6 +22,7 @@ import org.springframework.expression.Expression; import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; + /** * @author Artem Bilan * @author David Turanski @@ -61,4 +62,5 @@ public Expression getCollectionExpression() { private boolean isValid() { return StringUtils.hasText(this.collection) || this.collectionExpression != null; } + } diff --git a/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerApplicationTests.java b/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerApplicationTests.java index 680635be..b5c8b581 100644 --- a/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerApplicationTests.java +++ b/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbConsumerApplicationTests.java @@ -43,9 +43,7 @@ * @author David Turanski * @author Chris Bono */ -@SpringBootTest(properties = { - "mongodb.consumer.collection=testing" -}) +@SpringBootTest(properties = { "mongodb.consumer.collection=testing" }) class MongoDbConsumerApplicationTests implements MongoDbTestContainerSupport { @DynamicPropertySource @@ -72,9 +70,7 @@ void testMongodbConsumer() { data2.put("firstName", "Foo"); data2.put("lastName", "Bar"); - Flux> messages = Flux.just( - new GenericMessage<>(data1), - new GenericMessage<>(data2), + Flux> messages = Flux.just(new GenericMessage<>(data1), new GenericMessage<>(data2), new GenericMessage<>("{\"my_data\": \"THE DATA\"}")); messages.map(message -> { @@ -84,24 +80,27 @@ void testMongodbConsumer() { }).subscribe(); await().timeout(Duration.ofSeconds(10)) - .until(() -> mongoTemplate.findAll(Document.class, properties.getCollection()).count().block() == 3L); + .until(() -> mongoTemplate.findAll(Document.class, properties.getCollection()).count().block() == 3L); - StepVerifier.create(this.mongoTemplate.findAll(Document.class, properties.getCollection()) + StepVerifier + .create(this.mongoTemplate.findAll(Document.class, properties.getCollection()) .sort(Comparator.comparing(d -> d.get("_id").toString()))) - .assertNext(document -> { - assertThat(document.get("foo")).isEqualTo("bar"); - }) - .assertNext(document -> { - assertThat(document.get("firstName")).isEqualTo("Foo"); - assertThat(document.get("lastName")).isEqualTo("Bar"); - }) - .assertNext(document -> { - assertThat(document.get("my_data")).isEqualTo("THE DATA"); - }) - .verifyComplete(); + .assertNext(document -> { + assertThat(document.get("foo")).isEqualTo("bar"); + }) + .assertNext(document -> { + assertThat(document.get("firstName")).isEqualTo("Foo"); + assertThat(document.get("lastName")).isEqualTo("Bar"); + }) + .assertNext(document -> { + assertThat(document.get("my_data")).isEqualTo("THE DATA"); + }) + .verifyComplete(); } @SpringBootApplication static class MongoDbConsumerTestApplication { + } + } diff --git a/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbTestContainerSupport.java b/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbTestContainerSupport.java index bdb32724..47396062 100644 --- a/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbTestContainerSupport.java +++ b/consumer/spring-mongodb-consumer/src/test/java/org/springframework/cloud/fn/consumer/mongo/MongoDbTestContainerSupport.java @@ -30,9 +30,9 @@ @Testcontainers(disabledWithoutDocker = true) public interface MongoDbTestContainerSupport { - MongoDBContainer MONGO_CONTAINER = new MongoDBContainer("mongo:6.0.6") - .withStartupTimeout(Duration.ofSeconds(120)) + MongoDBContainer MONGO_CONTAINER = new MongoDBContainer("mongo:6.0.6").withStartupTimeout(Duration.ofSeconds(120)) .withStartupAttempts(3); + @BeforeAll static void startContainer() { MONGO_CONTAINER.start(); diff --git a/consumer/spring-mqtt-consumer/src/main/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerProperties.java b/consumer/spring-mqtt-consumer/src/main/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerProperties.java index 439bd89e..c7a3f5a0 100644 --- a/consumer/spring-mqtt-consumer/src/main/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerProperties.java +++ b/consumer/spring-mqtt-consumer/src/main/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerProperties.java @@ -114,4 +114,5 @@ public boolean isAsync() { public void setAsync(boolean async) { this.async = async; } + } diff --git a/consumer/spring-mqtt-consumer/src/test/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerTests.java b/consumer/spring-mqtt-consumer/src/test/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerTests.java index c572a045..74bf584d 100644 --- a/consumer/spring-mqtt-consumer/src/test/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerTests.java +++ b/consumer/spring-mqtt-consumer/src/test/java/org/springframework/cloud/fn/consumer/mqtt/MqttConsumerTests.java @@ -42,22 +42,19 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(properties = { - "mqtt.consumer.topic=test", - "mqtt.ssl-properties.com.ibm.ssl.protocol=TLS", +@SpringBootTest(properties = { "mqtt.consumer.topic=test", "mqtt.ssl-properties.com.ibm.ssl.protocol=TLS", "mqtt.ssl-properties.com.ibm.ssl.keyStoreType=TEST" }) @DirtiesContext @Tag("integration") public class MqttConsumerTests { static { - GenericContainer mosquitto = - new GenericContainer<>("eclipse-mosquitto:2.0.13") - .withCommand("mosquitto -c /mosquitto-no-auth.conf") - .withReuse(true) - .withExposedPorts(1883) - .withStartupTimeout(Duration.ofSeconds(120)) - .withStartupAttempts(3); + GenericContainer mosquitto = new GenericContainer<>("eclipse-mosquitto:2.0.13") + .withCommand("mosquitto -c /mosquitto-no-auth.conf") + .withReuse(true) + .withExposedPorts(1883) + .withStartupTimeout(Duration.ofSeconds(120)) + .withStartupAttempts(3); mosquitto.start(); final Integer mappedPort = mosquitto.getMappedPort(1883); System.setProperty("mqtt.url", "tcp://localhost:" + mappedPort); @@ -82,8 +79,8 @@ public void testMqttConsumer() { MqttConnectOptions connectionInfo = this.mqttPahoMessageDrivenChannelAdapter.getConnectionInfo(); Properties sslProperties = connectionInfo.getSSLProperties(); assertThat(sslProperties) - .containsEntry(SSLSocketFactoryFactory.SSLPROTOCOL, SSLSocketFactoryFactory.DEFAULT_PROTOCOL) - .containsEntry(SSLSocketFactoryFactory.KEYSTORETYPE, "TEST"); + .containsEntry(SSLSocketFactoryFactory.SSLPROTOCOL, SSLSocketFactoryFactory.DEFAULT_PROTOCOL) + .containsEntry(SSLSocketFactoryFactory.KEYSTORETYPE, "TEST"); this.mqttConsumer.accept(MessageBuilder.withPayload("hello").build()); Message in = this.queue.receive(10000); diff --git a/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerConfiguration.java b/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerConfiguration.java index ad92019c..9b010f71 100644 --- a/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerConfiguration.java +++ b/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerConfiguration.java @@ -99,13 +99,12 @@ public AmqpOutboundChannelAdapterSpec amqpChannelAdapter(ConnectionFactory rabbi throws Exception { AmqpOutboundChannelAdapterSpec handler = Amqp - .outboundAdapter(rabbitTemplate(this.properties.isOwnConnection() - ? buildLocalConnectionFactory() : rabbitConnectionFactory)) - .mappedRequestHeaders(properties.getMappedRequestHeaders()) - .defaultDeliveryMode(properties.getPersistentDeliveryMode() - ? MessageDeliveryMode.PERSISTENT - : MessageDeliveryMode.NON_PERSISTENT) - .headersMappedLast(this.properties.isHeadersMappedLast()); + .outboundAdapter(rabbitTemplate( + this.properties.isOwnConnection() ? buildLocalConnectionFactory() : rabbitConnectionFactory)) + .mappedRequestHeaders(properties.getMappedRequestHeaders()) + .defaultDeliveryMode(properties.getPersistentDeliveryMode() ? MessageDeliveryMode.PERSISTENT + : MessageDeliveryMode.NON_PERSISTENT) + .headersMappedLast(this.properties.isHeadersMappedLast()); Expression exchangeExpression = this.properties.getExchangeExpression(); if (exchangeExpression != null) { @@ -139,10 +138,8 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory rabbitConnectionFactory) return rabbitTemplate; } - @Bean - @ConditionalOnProperty(name = "rabbit.converterBeanName", - havingValue = RabbitConsumerProperties.JSON_CONVERTER) + @ConditionalOnProperty(name = "rabbit.converterBeanName", havingValue = RabbitConsumerProperties.JSON_CONVERTER) public Jackson2JsonMessageConverter jsonConverter() { return new Jackson2JsonMessageConverter(); } @@ -165,25 +162,28 @@ private CachingConnectionFactory rabbitConnectionFactory(RabbitProperties proper ObjectProvider credentialsRefreshService, ObjectProvider connectionFactoryCustomizers) throws Exception { - /* NOTE: This is based on RabbitAutoConfiguration.RabbitConnectionFactoryCreator - * https://github.com/spring-projects/spring-boot/blob/c820ad01a108d419d8548265b8a34ed7c5591f7c/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java#L95 - * [UPGRADE_CONSIDERATION] this should stay somewhat in sync w/ the functionality provided by its original source. + /* + * NOTE: This is based on RabbitAutoConfiguration.RabbitConnectionFactoryCreator + * https://github.com/spring-projects/spring-boot/blob/ + * c820ad01a108d419d8548265b8a34ed7c5591f7c/spring-boot-project/spring-boot- + * autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/ + * RabbitAutoConfiguration.java#L95 [UPGRADE_CONSIDERATION] this should stay + * somewhat in sync w/ the functionality provided by its original source. */ RabbitConnectionFactoryBean connectionFactoryBean = new RabbitConnectionFactoryBean(); - RabbitConnectionFactoryBeanConfigurer connectionFactoryBeanConfigurer = - new RabbitConnectionFactoryBeanConfigurer(resourceLoader, properties); + RabbitConnectionFactoryBeanConfigurer connectionFactoryBeanConfigurer = new RabbitConnectionFactoryBeanConfigurer( + resourceLoader, properties); connectionFactoryBeanConfigurer.setCredentialsProvider(credentialsProvider.getIfUnique()); connectionFactoryBeanConfigurer.setCredentialsRefreshService(credentialsRefreshService.getIfUnique()); connectionFactoryBeanConfigurer.configure(connectionFactoryBean); connectionFactoryBean.afterPropertiesSet(); com.rabbitmq.client.ConnectionFactory connectionFactory = connectionFactoryBean.getObject(); - connectionFactoryCustomizers.orderedStream() - .forEach((customizer) -> customizer.customize(connectionFactory)); + connectionFactoryCustomizers.orderedStream().forEach((customizer) -> customizer.customize(connectionFactory)); CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(connectionFactory); - CachingConnectionFactoryConfigurer cachingConnectionFactoryConfigurer = - new CachingConnectionFactoryConfigurer(properties); + CachingConnectionFactoryConfigurer cachingConnectionFactoryConfigurer = new CachingConnectionFactoryConfigurer( + properties); cachingConnectionFactoryConfigurer.setConnectionNameStrategy(cf -> "rabbit.sink.own.connection"); cachingConnectionFactoryConfigurer.configure(cachingConnectionFactory); cachingConnectionFactory.afterPropertiesSet(); diff --git a/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerProperties.java b/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerProperties.java index 914fdc83..c5c05bfe 100644 --- a/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerProperties.java +++ b/consumer/spring-rabbit-consumer/src/main/java/org/springframework/cloud/fn/consumer/rabbit/RabbitConsumerProperties.java @@ -52,8 +52,8 @@ public class RabbitConsumerProperties { private Expression routingKeyExpression; /** - * Default delivery mode when 'amqp_deliveryMode' header is not present, - * true for PERSISTENT. + * Default delivery mode when 'amqp_deliveryMode' header is not present, true for + * PERSISTENT. */ private boolean persistentDeliveryMode; @@ -63,8 +63,9 @@ public class RabbitConsumerProperties { private String[] mappedRequestHeaders = { "*" }; /** - * The bean name for a custom message converter; if omitted, a SimpleMessageConverter is used. - * If 'jsonConverter', a Jackson2JsonMessageConverter bean will be created for you. + * The bean name for a custom message converter; if omitted, a SimpleMessageConverter + * is used. If 'jsonConverter', a Jackson2JsonMessageConverter bean will be created + * for you. */ private String converterBeanName; @@ -155,4 +156,5 @@ public boolean isHeadersMappedLast() { public void setHeadersMappedLast(boolean headersMappedLast) { this.headersMappedLast = headersMappedLast; } + } diff --git a/consumer/spring-redis-consumer/src/main/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerProperties.java b/consumer/spring-redis-consumer/src/main/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerProperties.java index 7a91e0aa..6c777f78 100644 --- a/consumer/spring-redis-consumer/src/main/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerProperties.java +++ b/consumer/spring-redis-consumer/src/main/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerProperties.java @@ -30,7 +30,8 @@ import org.springframework.validation.annotation.Validated; /** - * Used to configure those Redis Sink module options that are not related to connecting to Redis. + * Used to configure those Redis Sink module options that are not related to connecting to + * Redis. * * @author Eric Bottard * @author Mark Pollack @@ -145,7 +146,8 @@ public void setTopic(String topic) { this.topic = topic; } - // The javabean property name is what will be reported in case of violation. Make it meaningful + // The javabean property name is what will be reported in case of violation. Make it + // meaningful @AssertTrue(message = "Exactly one of 'queue', 'queueExpression', 'key', 'keyExpression', " + "'topic' and 'topicExpression' must be set") public boolean isMutuallyExclusive() { diff --git a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/AbstractRedisConsumerTests.java b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/AbstractRedisConsumerTests.java index 58370fee..5738b2b0 100644 --- a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/AbstractRedisConsumerTests.java +++ b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/AbstractRedisConsumerTests.java @@ -54,4 +54,5 @@ static void redisProperties(DynamicPropertyRegistry registry) { static class RedisConsumerTestApplication { } + } diff --git a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerKeyTests.java b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerKeyTests.java index b6fc741d..37cb77a6 100644 --- a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerKeyTests.java +++ b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerKeyTests.java @@ -39,7 +39,7 @@ public class RedisConsumerKeyTests extends AbstractRedisConsumerTests { @Test public void testWithKey() { - //Setup + // Setup String key = "foo"; redisTemplate.delete(key); @@ -49,18 +49,19 @@ public void testWithKey() { list.add("Moe"); list.add("Jack"); - //Execute + // Execute Message> message = new GenericMessage<>(list); redisConsumer.accept(message); - //Assert + // Assert assertThat(redisList.size()).isEqualTo(3); assertThat(redisList.get(0)).isEqualTo("Manny"); assertThat(redisList.get(1)).isEqualTo("Moe"); assertThat(redisList.get(2)).isEqualTo("Jack"); - //Cleanup + // Cleanup redisTemplate.delete(key); } + } diff --git a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerQueueTests.java b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerQueueTests.java index eecf8ca2..b392ce2e 100644 --- a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerQueueTests.java +++ b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerQueueTests.java @@ -41,4 +41,5 @@ public void testWithQueue() { Object result = redisTemplate.boundListOps("test-queue").rightPop(5000, TimeUnit.MILLISECONDS); assertThat(result).isEqualTo("hello"); } + } diff --git a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerTopicTests.java b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerTopicTests.java index d2af40dc..b69409c6 100644 --- a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerTopicTests.java +++ b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisConsumerTopicTests.java @@ -82,5 +82,7 @@ private static class Listener { public void handleMessage(String s) { this.latch.countDown(); } + } + } diff --git a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisTestContainerSupport.java b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisTestContainerSupport.java index 8f12bba9..ad5030e6 100644 --- a/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisTestContainerSupport.java +++ b/consumer/spring-redis-consumer/src/test/java/org/springframework/cloud/fn/consumer/redis/RedisTestContainerSupport.java @@ -29,8 +29,8 @@ */ @Testcontainers(disabledWithoutDocker = true) public interface RedisTestContainerSupport { - GenericContainer REDIS_CONTAINER = new GenericContainer<>("redis:7") - .withExposedPorts(6379) + + GenericContainer REDIS_CONTAINER = new GenericContainer<>("redis:7").withExposedPorts(6379) .withStartupTimeout(Duration.ofSeconds(120)) .withStartupAttempts(3); @@ -42,4 +42,5 @@ static void startContainer() { static String getUri() { return "redis://localhost:" + REDIS_CONTAINER.getFirstMappedPort(); } + } diff --git a/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerConfiguration.java b/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerConfiguration.java index 029c21ef..26d86c46 100644 --- a/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerConfiguration.java +++ b/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerConfiguration.java @@ -33,20 +33,15 @@ public class RsocketConsumerConfiguration { @Bean public Function>, Mono> rsocketConsumer(RSocketRequester.Builder builder, - RsocketConsumerProperties rsocketConsumerProperties) { - RSocketRequester rSocketRequester = - rsocketConsumerProperties.getUri() != null - ? builder.websocket(rsocketConsumerProperties.getUri()) - : builder.tcp(rsocketConsumerProperties.getHost(), rsocketConsumerProperties.getPort()); + RsocketConsumerProperties rsocketConsumerProperties) { + RSocketRequester rSocketRequester = rsocketConsumerProperties.getUri() != null + ? builder.websocket(rsocketConsumerProperties.getUri()) + : builder.tcp(rsocketConsumerProperties.getHost(), rsocketConsumerProperties.getPort()); String route = rsocketConsumerProperties.getRoute(); - return input -> - input.flatMap(message -> - rSocketRequester.route(route) - .data(message.getPayload()) - .send()) - .ignoreElements(); + return input -> input.flatMap(message -> rSocketRequester.route(route).data(message.getPayload()).send()) + .ignoreElements(); } } diff --git a/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerProperties.java b/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerProperties.java index f2f36fc7..43769e51 100644 --- a/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerProperties.java +++ b/consumer/spring-rsocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerProperties.java @@ -74,4 +74,5 @@ public URI getUri() { public void setUri(URI uri) { this.uri = uri; } + } diff --git a/consumer/spring-rsocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerTests.java b/consumer/spring-rsocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerTests.java index 4c57c437..fd296239 100644 --- a/consumer/spring-rsocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerTests.java +++ b/consumer/spring-rsocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/rsocket/RsocketConsumerTests.java @@ -41,13 +41,13 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.util.ReflectionTestUtils; -@SpringBootTest(properties = {"spring.rsocket.server.port=0"}) +@SpringBootTest(properties = { "spring.rsocket.server.port=0" }) @DirtiesContext public class RsocketConsumerTests { private static ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() - .withUserConfiguration(RsocketConsumerConfiguration.class, RSocketRequesterAutoConfiguration.class, - RSocketStrategiesAutoConfiguration.class); + .withUserConfiguration(RsocketConsumerConfiguration.class, RSocketRequesterAutoConfiguration.class, + RSocketStrategiesAutoConfiguration.class); @Autowired ApplicationContext applicationContext; @@ -59,19 +59,18 @@ void testRsocketConsumer() { RSocketServer server = (RSocketServer) ReflectionTestUtils.getField(serverBootstrap, "server"); final int port = server.address().getPort(); - applicationContextRunner.withPropertyValues( - "rsocket.consumer.port=" + port, - "rsocket.consumer.route=test-route") - .run(context -> { - Function>, Mono> rsocketConsumer = context.getBean("rsocketConsumer", Function.class); - rsocketConsumer.apply(Flux.just(new GenericMessage<>("Hello RSocket"))) - .subscribe(); + applicationContextRunner + .withPropertyValues("rsocket.consumer.port=" + port, "rsocket.consumer.route=test-route") + .run(context -> { + Function>, Mono> rsocketConsumer = context.getBean("rsocketConsumer", + Function.class); + rsocketConsumer.apply(Flux.just(new GenericMessage<>("Hello RSocket"))).subscribe(); - StepVerifier.create(RSocketserverApplication.fireForgetPayloads) - .expectNext("Hello RSocket") - .thenCancel() - .verify(); - }); + StepVerifier.create(RSocketserverApplication.fireForgetPayloads) + .expectNext("Hello RSocket") + .thenCancel() + .verify(); + }); } @@ -86,7 +85,7 @@ static class RSocketserverApplication { void someMethod(String payload) { fireForgetPayloads.onNext(payload); } - } -} + } +} diff --git a/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerConfiguration.java b/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerConfiguration.java index 8eceaab8..d0b90da8 100644 --- a/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerConfiguration.java +++ b/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerConfiguration.java @@ -52,15 +52,13 @@ public Consumer> s3Consumer(IntegrationFlow s3ConsumerFlow) { public IntegrationFlow s3ConsumerFlow(@Nullable TransferListener transferListener, MessageHandler amazonS3MessageHandler) { - return flow -> flow - .enrichHeaders(headers -> headers.header(AwsHeaders.TRANSFER_LISTENER, transferListener)) - .handle(amazonS3MessageHandler); + return flow -> flow.enrichHeaders(headers -> headers.header(AwsHeaders.TRANSFER_LISTENER, transferListener)) + .handle(amazonS3MessageHandler); } @Bean public MessageHandler amazonS3MessageHandler(S3TransferManager s3TransferManager, - AwsS3ConsumerProperties s3ConsumerProperties, - BeanFactory beanFactory, + AwsS3ConsumerProperties s3ConsumerProperties, BeanFactory beanFactory, @Nullable BiConsumer> uploadMetadataProvider) { Expression bucketExpression = s3ConsumerProperties.getBucketExpression(); @@ -85,19 +83,17 @@ public MessageHandler amazonS3MessageHandler(S3TransferManager s3TransferManager if (aclExpression != null) { EvaluationContext evaluationContext = IntegrationContextUtils.getEvaluationContext(beanFactory); - metadataProviderToUse = - (builder, message) -> { - Object aclValue = aclExpression.getValue(evaluationContext, message); - Assert.notNull(aclValue, - () -> String.format("The expression '%s' for message '%s' returned null", - aclExpression, message)); + metadataProviderToUse = (builder, message) -> { + Object aclValue = aclExpression.getValue(evaluationContext, message); + Assert.notNull(aclValue, () -> String.format("The expression '%s' for message '%s' returned null", + aclExpression, message)); - builder.acl(aclValue.toString()); + builder.acl(aclValue.toString()); - if (uploadMetadataProvider != null) { - uploadMetadataProvider.accept(builder, message); - } - }; + if (uploadMetadataProvider != null) { + uploadMetadataProvider.accept(builder, message); + } + }; } if (metadataProviderToUse != null) { diff --git a/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerProperties.java b/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerProperties.java index 04dd3388..bed66422 100644 --- a/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerProperties.java +++ b/consumer/spring-s3-consumer/src/main/java/org/springframework/cloud/fn/consumer/s3/AwsS3ConsumerProperties.java @@ -99,12 +99,13 @@ public void setAclExpression(Expression aclExpression) { @AssertTrue(message = "Exactly one of 'bucket' or 'bucketExpression' must be set") public boolean isMutuallyExclusiveBucketAndBucketExpression() { - return (this.bucket != null && this.bucketExpression == null) || - (this.bucket == null && this.bucketExpression != null); + return (this.bucket != null && this.bucketExpression == null) + || (this.bucket == null && this.bucketExpression != null); } @AssertTrue(message = "Only one of 'acl' or 'aclExpression' must be set") public boolean isMutuallyExclusiveAclAndAclExpression() { return this.acl == null || this.aclExpression == null; } + } diff --git a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AbstractAwsS3ConsumerMockTests.java b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AbstractAwsS3ConsumerMockTests.java index 14ccc5ba..504c1f3f 100644 --- a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AbstractAwsS3ConsumerMockTests.java +++ b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AbstractAwsS3ConsumerMockTests.java @@ -47,12 +47,11 @@ @DirtiesContext @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "spring.cloud.aws.credentials.accessKey=" + AbstractAwsS3ConsumerMockTests.AWS_ACCESS_KEY, + properties = { "spring.cloud.aws.credentials.accessKey=" + AbstractAwsS3ConsumerMockTests.AWS_ACCESS_KEY, "spring.cloud.aws.credentials.secretKey=" + AbstractAwsS3ConsumerMockTests.AWS_SECRET_KEY, "spring.cloud.aws.region.static=" + AbstractAwsS3ConsumerMockTests.AWS_REGION, "spring.cloud.aws.s3.endpoint=s3://foo", - "s3.consumer.bucket=" + AbstractAwsS3ConsumerMockTests.S3_BUCKET}) + "s3.consumer.bucket=" + AbstractAwsS3ConsumerMockTests.S3_BUCKET }) public abstract class AbstractAwsS3ConsumerMockTests { protected static final String AWS_ACCESS_KEY = "test.accessKey"; @@ -80,9 +79,8 @@ public abstract class AbstractAwsS3ConsumerMockTests { @BeforeEach public void setupTest() { - willReturn(CompletableFuture.completedFuture(PutObjectResponse.builder().build())) - .given(amazonS3) - .putObject(any(PutObjectRequest.class), any(AsyncRequestBody.class)); + willReturn(CompletableFuture.completedFuture(PutObjectResponse.builder().build())).given(amazonS3) + .putObject(any(PutObjectRequest.class), any(AsyncRequestBody.class)); new DirectFieldAccessor(this.s3TransferManager).setPropertyValue("s3AsyncClient", amazonS3); } @@ -99,7 +97,6 @@ public CountDownLatch transferCompletedLatch() { public TransferListener transferListener() { return new TransferListener() { - @Override public void transferComplete(Context.TransferComplete context) { transferCompletedLatch().countDown(); @@ -113,8 +110,8 @@ public BiConsumer> uploadMetadataProvider() return (builder, message) -> { if (message.getPayload() instanceof InputStream) { builder.contentLength(1L) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .contentDisposition("test.json"); + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contentDisposition("test.json"); } }; } diff --git a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadFileTests.java b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadFileTests.java index 2ec4d009..a8530427 100644 --- a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadFileTests.java +++ b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadFileTests.java @@ -42,22 +42,21 @@ public class AmazonS3UploadFileTests extends AbstractAwsS3ConsumerMockTests { @Test public void test() throws Exception { - S3AsyncClient amazonS3Client = - TestUtils.getPropertyValue(this.s3TransferManager, "s3AsyncClient", S3AsyncClient.class); + S3AsyncClient amazonS3Client = TestUtils.getPropertyValue(this.s3TransferManager, "s3AsyncClient", + S3AsyncClient.class); File file = new File(temporaryRemoteFolder.toFile(), "foo.mp3"); file.createNewFile(); - Message message = MessageBuilder.withPayload(file) - .build(); + Message message = MessageBuilder.withPayload(file).build(); this.s3Consumer.accept(message); - ArgumentCaptor putObjectRequestArgumentCaptor = - ArgumentCaptor.forClass(PutObjectRequest.class); - ArgumentCaptor asyncRequestBodyArgumentCaptor = - ArgumentCaptor.forClass(AsyncRequestBody.class); - verify(amazonS3Client, atLeastOnce()) - .putObject(putObjectRequestArgumentCaptor.capture(), asyncRequestBodyArgumentCaptor.capture()); + ArgumentCaptor putObjectRequestArgumentCaptor = ArgumentCaptor + .forClass(PutObjectRequest.class); + ArgumentCaptor asyncRequestBodyArgumentCaptor = ArgumentCaptor + .forClass(AsyncRequestBody.class); + verify(amazonS3Client, atLeastOnce()).putObject(putObjectRequestArgumentCaptor.capture(), + asyncRequestBodyArgumentCaptor.capture()); PutObjectRequest putObjectRequest = putObjectRequestArgumentCaptor.getValue(); assertThat(putObjectRequest.bucket()).isEqualTo(S3_BUCKET); @@ -69,9 +68,9 @@ public void test() throws Exception { AsyncRequestBody asyncRequestBody = asyncRequestBodyArgumentCaptor.getValue(); StepVerifier.create(asyncRequestBody) - .assertNext(buffer -> assertThat(TestUtils.getPropertyValue(buffer, "hb", byte[].class)).isEmpty()) - .expectComplete() - .verify(); + .assertNext(buffer -> assertThat(TestUtils.getPropertyValue(buffer, "hb", byte[].class)).isEmpty()) + .expectComplete() + .verify(); assertThat(this.transferCompletedLatch.await(10, TimeUnit.SECONDS)).isTrue(); } diff --git a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadInputStreamTests.java b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadInputStreamTests.java index 315aab39..d50cb4b2 100644 --- a/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadInputStreamTests.java +++ b/consumer/spring-s3-consumer/src/test/java/org/springframework/cloud/fn/consumer/s3/AmazonS3UploadInputStreamTests.java @@ -43,22 +43,20 @@ public class AmazonS3UploadInputStreamTests extends AbstractAwsS3ConsumerMockTes @Test public void test() throws Exception { - S3AsyncClient amazonS3Client = - TestUtils.getPropertyValue(this.s3TransferManager, "s3AsyncClient", S3AsyncClient.class); + S3AsyncClient amazonS3Client = TestUtils.getPropertyValue(this.s3TransferManager, "s3AsyncClient", + S3AsyncClient.class); InputStream payload = new StringInputStream("a"); - Message message = MessageBuilder.withPayload(payload) - .setHeader("key", "myInputStream") - .build(); + Message message = MessageBuilder.withPayload(payload).setHeader("key", "myInputStream").build(); this.s3Consumer.accept(message); - ArgumentCaptor putObjectRequestArgumentCaptor = - ArgumentCaptor.forClass(PutObjectRequest.class); - ArgumentCaptor asyncRequestBodyArgumentCaptor = - ArgumentCaptor.forClass(AsyncRequestBody.class); - verify(amazonS3Client, atLeastOnce()) - .putObject(putObjectRequestArgumentCaptor.capture(), asyncRequestBodyArgumentCaptor.capture()); + ArgumentCaptor putObjectRequestArgumentCaptor = ArgumentCaptor + .forClass(PutObjectRequest.class); + ArgumentCaptor asyncRequestBodyArgumentCaptor = ArgumentCaptor + .forClass(AsyncRequestBody.class); + verify(amazonS3Client, atLeastOnce()).putObject(putObjectRequestArgumentCaptor.capture(), + asyncRequestBodyArgumentCaptor.capture()); PutObjectRequest putObjectRequest = putObjectRequestArgumentCaptor.getValue(); assertThat(putObjectRequest.bucket()).isEqualTo(S3_BUCKET); @@ -68,12 +66,11 @@ public void test() throws Exception { assertThat(putObjectRequest.contentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE); assertThat(putObjectRequest.contentDisposition()).isEqualTo("test.json"); - AsyncRequestBody asyncRequestBody = asyncRequestBodyArgumentCaptor.getValue(); StepVerifier.create(asyncRequestBody.map(buffer -> StandardCharsets.UTF_8.decode(buffer).toString())) - .expectNext("a") - .expectComplete() - .verify(); + .expectNext("a") + .expectComplete() + .verify(); } } diff --git a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerConfiguration.java b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerConfiguration.java index 58a4018f..c1c006da 100644 --- a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerConfiguration.java +++ b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerConfiguration.java @@ -36,6 +36,7 @@ /** * Configuration for SFTP Consumer. + * * @author Soby Chacko * @author Corneil du Plessis */ @@ -49,17 +50,17 @@ public IntegrationFlow ftpOutboundFlow(SftpConsumerProperties properties, SessionFactory ftpSessionFactory, @Nullable ComponentCustomizer sftpMessageHandlerSpecCustomizer) { - IntegrationFlowBuilder integrationFlowBuilder = - IntegrationFlow.from(MessageConsumer.class, (gateway) -> gateway.beanName("sftpConsumer")); + IntegrationFlowBuilder integrationFlowBuilder = IntegrationFlow.from(MessageConsumer.class, + (gateway) -> gateway.beanName("sftpConsumer")); - SftpMessageHandlerSpec handlerSpec = - Sftp.outboundAdapter(new SftpRemoteFileTemplate(ftpSessionFactory), properties.getMode()) - .remoteDirectory(properties.getRemoteDir()) - .temporaryRemoteDirectory(properties.getTemporaryRemoteDir()) - .remoteFileSeparator(properties.getRemoteFileSeparator()) - .autoCreateDirectory(properties.isAutoCreateDir()) - .useTemporaryFileName(properties.isUseTemporaryFilename()) - .temporaryFileSuffix(properties.getTmpFileSuffix()); + SftpMessageHandlerSpec handlerSpec = Sftp + .outboundAdapter(new SftpRemoteFileTemplate(ftpSessionFactory), properties.getMode()) + .remoteDirectory(properties.getRemoteDir()) + .temporaryRemoteDirectory(properties.getTemporaryRemoteDir()) + .remoteFileSeparator(properties.getRemoteFileSeparator()) + .autoCreateDirectory(properties.isAutoCreateDir()) + .useTemporaryFileName(properties.isUseTemporaryFilename()) + .temporaryFileSuffix(properties.getTmpFileSuffix()); if (properties.getFilenameExpression() != null) { handlerSpec.fileNameExpression(properties.getFilenameExpression()); } @@ -68,9 +69,7 @@ public IntegrationFlow ftpOutboundFlow(SftpConsumerProperties properties, sftpMessageHandlerSpecCustomizer.customize(handlerSpec); } - return integrationFlowBuilder - .handle(handlerSpec) - .get(); + return integrationFlowBuilder.handle(handlerSpec).get(); } private interface MessageConsumer extends Consumer> { diff --git a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerProperties.java b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerProperties.java index 57ecdcd2..84fd95af 100644 --- a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerProperties.java +++ b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerProperties.java @@ -38,7 +38,8 @@ public class SftpConsumerProperties { private final Factory factory = new Factory(); /** - * A temporary directory where the file will be written if 'isUseTemporaryFilename()' is true. + * A temporary directory where the file will be written if 'isUseTemporaryFilename()' + * is true. */ private String temporaryRemoteDir = "/"; @@ -198,7 +199,6 @@ public static class Factory { */ private Expression knownHostsExpression = null; - @NotBlank public String getHost() { return this.host; @@ -275,4 +275,5 @@ public void setKnownHostsExpression(Expression knownHosts) { } } + } diff --git a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerSessionFactoryConfiguration.java b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerSessionFactoryConfiguration.java index 90b4995d..61742d82 100644 --- a/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerSessionFactoryConfiguration.java +++ b/consumer/spring-sftp-consumer/src/main/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerSessionFactoryConfiguration.java @@ -39,8 +39,7 @@ public class SftpConsumerSessionFactoryConfiguration { @Bean @ConditionalOnMissingBean - public SessionFactory sftpSessionFactory( - SftpConsumerProperties properties, + public SessionFactory sftpSessionFactory(SftpConsumerProperties properties, ApplicationContext applicationContext) { DefaultSftpSessionFactory sftpSessionFactory = new DefaultSftpSessionFactory(); @@ -54,7 +53,7 @@ public SessionFactory sftpSessionFactory( sftpSessionFactory.setAllowUnknownKeys(factory.isAllowUnknownKeys()); if (factory.getKnownHostsExpression() != null) { String knownHostsLocation = factory.getKnownHostsExpression() - .getValue(IntegrationContextUtils.getEvaluationContext(applicationContext), String.class); + .getValue(IntegrationContextUtils.getEvaluationContext(applicationContext), String.class); Resource knownHostsResource = applicationContext.getResource(knownHostsLocation); sftpSessionFactory.setKnownHostsResource(knownHostsResource); } @@ -65,4 +64,5 @@ public SessionFactory sftpSessionFactory( return sftpSessionFactory; } } + } diff --git a/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerPropertiesTests.java b/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerPropertiesTests.java index c70912ac..ab0a703a 100644 --- a/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerPropertiesTests.java +++ b/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerPropertiesTests.java @@ -141,8 +141,9 @@ public void knownHostsExpression() { context.refresh(); SessionFactory sessionFactory = context.getBean(SessionFactory.class); assertThat(TestUtils.getPropertyValue(sessionFactory, "sessionFactory.knownHosts") - .toString().replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/") - .endsWith("/.ssh/known_hosts]")).isTrue(); + .toString() + .replaceAll(java.util.regex.Matcher.quoteReplacement(File.separator), "/") + .endsWith("/.ssh/known_hosts]")).isTrue(); context.close(); } @@ -170,7 +171,8 @@ public Converter spelConverter() { } /** - * TODO: This needs to be refactored into a generic place for any functions to use. + * TODO: This needs to be refactored into a generic place for any functions to + * use. * * A simple converter from String to Expression. * @@ -190,14 +192,13 @@ public Expression convert(String source) { try { Expression expression = this.parser.parseExpression(source); if (expression instanceof SpelExpression) { - ((SpelExpression) expression) - .setEvaluationContext(this.evaluationContext); + ((SpelExpression) expression).setEvaluationContext(this.evaluationContext); } return expression; } catch (ParseException e) { - throw new IllegalArgumentException(String.format( - "Could not convert '%s' into a SpEL expression", source), e); + throw new IllegalArgumentException( + String.format("Could not convert '%s' into a SpEL expression", source), e); } } diff --git a/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerTests.java b/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerTests.java index 07225706..e093fea8 100644 --- a/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerTests.java +++ b/consumer/spring-sftp-consumer/src/test/java/org/springframework/cloud/fn/consumer/sftp/SftpConsumerTests.java @@ -33,15 +33,11 @@ @DirtiesContext @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "sftp.consumer.remoteDir = sftpTarget", - "sftp.consumer.factory.username = foo", - "sftp.consumer.factory.password = foo", - "sftp.consumer.mode = FAIL", + properties = { "sftp.consumer.remoteDir = sftpTarget", "sftp.consumer.factory.username = foo", + "sftp.consumer.factory.password = foo", "sftp.consumer.mode = FAIL", "sftp.consumer.factory.port = ${sftp.factory.port}", "sftp.consumer.filenameExpression = payload.name.toUpperCase()", - "sftp.consumer.factory.allowUnknownKeys = true" - }) + "sftp.consumer.factory.allowUnknownKeys = true" }) public class SftpConsumerTests extends SftpTestSupport { @Autowired @@ -74,6 +70,7 @@ public void serverRefreshed() { // noop test to test the dirs are refreshed prop @SpringBootApplication static class SftpConsumerTestApplication { + } -} +} diff --git a/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerConfiguration.java b/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerConfiguration.java index 25caf7a8..88b72117 100644 --- a/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerConfiguration.java +++ b/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerConfiguration.java @@ -40,14 +40,15 @@ * @author Chris Bono */ @Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties({TcpConsumerProperties.class, TcpConnectionFactoryProperties.class}) +@EnableConfigurationProperties({ TcpConsumerProperties.class, TcpConnectionFactoryProperties.class }) public class TcpConsumerConfiguration { private TcpConsumerProperties properties; + private TcpConnectionFactoryProperties tcpConnectionProperties; public TcpConsumerConfiguration(TcpConsumerProperties properties, - TcpConnectionFactoryProperties tcpConnectionProperties) { + TcpConnectionFactoryProperties tcpConnectionProperties) { this.properties = properties; this.tcpConnectionProperties = tcpConnectionProperties; } @@ -58,7 +59,8 @@ public Consumer> tcpConsumer(TcpSendingMessageHandlerSmartLifeCycle h } @Bean - public TcpSendingMessageHandlerSmartLifeCycle handler(@Qualifier("tcpSinkConnectionFactory") AbstractConnectionFactory connectionFactory) { + public TcpSendingMessageHandlerSmartLifeCycle handler( + @Qualifier("tcpSinkConnectionFactory") AbstractConnectionFactory connectionFactory) { TcpSendingMessageHandlerSmartLifeCycle tcpMessageHandler = new TcpSendingMessageHandlerSmartLifeCycle(); tcpMessageHandler.setConnectionFactory(connectionFactory); return tcpMessageHandler; @@ -105,5 +107,7 @@ public boolean isAutoStartup() { public int getPhase() { return Integer.MIN_VALUE; } + } + } diff --git a/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerProperties.java b/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerProperties.java index 4ba112c2..c17bdb8f 100644 --- a/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerProperties.java +++ b/consumer/spring-tcp-consumer/src/main/java/org/springframework/cloud/fn/consumer/tcp/TcpConsumerProperties.java @@ -87,4 +87,5 @@ public boolean isClose() { public void setClose(boolean close) { this.close = close; } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/AbstractTcpConsumerTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/AbstractTcpConsumerTests.java index f1d92a92..07b8392e 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/AbstractTcpConsumerTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/AbstractTcpConsumerTests.java @@ -75,10 +75,9 @@ public static void shutDown() { server.shutDown(); } - /* - * Sends two messages and asserts they arrive as expected on the other side using - * the supplied decoder. + * Sends two messages and asserts they arrive as expected on the other side using the + * supplied decoder. */ protected void doTest(AbstractByteArraySerializer decoder) throws Exception { server.setDecoder(decoder); @@ -93,8 +92,8 @@ protected void doTest(AbstractByteArraySerializer decoder) throws Exception { } /** - * TCP server that uses the supplied {@link AbstractByteArraySerializer} - * to decode the input stream and put the resulting message in a queue. + * TCP server that uses the supplied {@link AbstractByteArraySerializer} to decode the + * input stream and put the resulting message in a queue. * */ private static class TestTCPServer implements Runnable { @@ -173,10 +172,12 @@ private void shutDown() { catch (IOException e) { } } + } @SpringBootApplication public static class TcpConsumerTestApplication { } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/CRLFTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/CRLFTests.java index 43dd6d42..102abc91 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/CRLFTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/CRLFTests.java @@ -20,7 +20,6 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer; - /** * @author Gary Russell */ @@ -30,4 +29,5 @@ public class CRLFTests extends AbstractTcpConsumerTests { public void test() throws Exception { doTest(new ByteArrayCrLfSerializer()); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L1Tests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L1Tests.java index b55b9581..bb8d94ac 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L1Tests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L1Tests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = L1"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = L1" }) public class L1Tests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArrayLengthHeaderSerializer(1)); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L2Tests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L2Tests.java index b1454e78..985acc35 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L2Tests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L2Tests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = L2"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = L2" }) public class L2Tests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArrayLengthHeaderSerializer(2)); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L4Tests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L4Tests.java index a909d5b1..aa8c7b82 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L4Tests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/L4Tests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = L4"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = L4" }) public class L4Tests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArrayLengthHeaderSerializer(4)); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/LFTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/LFTests.java index f633f18e..1998f66d 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/LFTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/LFTests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = LF"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = LF" }) public class LFTests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArrayLfSerializer()); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NULLTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NULLTests.java index f22126bb..5e1b90cd 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NULLTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NULLTests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = NULL"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = NULL" }) public class NULLTests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArraySingleTerminatorSerializer((byte) 0)); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NotNioTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NotNioTests.java index aee67b2c..36a6e945 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NotNioTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/NotNioTests.java @@ -27,7 +27,7 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.host = foo"}) +@TestPropertySource(properties = { "tcp.consumer.host = foo" }) public class NotNioTests extends AbstractTcpConsumerTests { @Test @@ -37,4 +37,5 @@ public void test() throws Exception { assertThat(TestUtils.getPropertyValue(this.connectionFactory, "lookupHost", Boolean.class)).isFalse(); assertThat(TestUtils.getPropertyValue(this.connectionFactory, "soTimeout")).isEqualTo(120000); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/PropertiesPopulatedTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/PropertiesPopulatedTests.java index 19a92efe..b41ced47 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/PropertiesPopulatedTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/PropertiesPopulatedTests.java @@ -27,8 +27,9 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.host = foo", "tcp.nio = true", "tcp.reverseLookup = true", - "tcp.useDirectBuffers = true", "tcp.socketTimeout = 123", "tcp.consumer.close = true", "tcp.consumer.charset = bar"}) +@TestPropertySource(properties = { "tcp.consumer.host = foo", "tcp.nio = true", "tcp.reverseLookup = true", + "tcp.useDirectBuffers = true", "tcp.socketTimeout = 123", "tcp.consumer.close = true", + "tcp.consumer.charset = bar" }) public class PropertiesPopulatedTests extends AbstractTcpConsumerTests { @Test @@ -41,4 +42,5 @@ public void test() throws Exception { assertThat(this.connectionFactory.isSingleUse()).isTrue(); assertThat(TestUtils.getPropertyValue(this.connectionFactory, "mapper.charset")).isEqualTo("bar"); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/RAWTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/RAWTests.java index c1a6efa5..76354f1b 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/RAWTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/RAWTests.java @@ -24,11 +24,12 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.consumer.encoder = RAW", "tcp.consumer.close = true"}) +@TestPropertySource(properties = { "tcp.consumer.encoder = RAW", "tcp.consumer.close = true" }) public class RAWTests extends AbstractTcpConsumerTests { @Test public void test() throws Exception { doTest(new ByteArrayRawSerializer()); } + } diff --git a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/STXETXTests.java b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/STXETXTests.java index 25cdddc1..26199190 100644 --- a/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/STXETXTests.java +++ b/consumer/spring-tcp-consumer/src/test/java/org/springframework/cloud/fn/consumer/tcp/STXETXTests.java @@ -31,4 +31,5 @@ public class STXETXTests extends AbstractTcpConsumerTests { public void test() throws Exception { doTest(new ByteArrayStxEtxSerializer()); } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerConfiguration.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerConfiguration.java index ae55a818..1e6189a8 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerConfiguration.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerConfiguration.java @@ -29,7 +29,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -43,45 +42,50 @@ public Consumer> friendshipConsumer(TwitterFriendshipsConsumerPropert return message -> { try { - TwitterFriendshipsConsumerProperties.OperationType type = - properties.getType().getValue(message, TwitterFriendshipsConsumerProperties.OperationType.class); - //TwitterFriendshipsSinkProperties.OperationType type = TwitterFriendshipsSinkProperties.OperationType.create; + TwitterFriendshipsConsumerProperties.OperationType type = properties.getType() + .getValue(message, TwitterFriendshipsConsumerProperties.OperationType.class); + // TwitterFriendshipsSinkProperties.OperationType type = + // TwitterFriendshipsSinkProperties.OperationType.create; if (properties.getUserId() != null) { Long userId = properties.getUserId().getValue(message, long.class); switch (type) { - case create: - boolean follow = properties.getCreate().getFollow().getValue(message, boolean.class); - twitter.createFriendship(userId, follow); - return; + case create: + boolean follow = properties.getCreate().getFollow().getValue(message, boolean.class); + twitter.createFriendship(userId, follow); + return; - case update: - boolean enableDeviceNotification = properties.getUpdate().getDevice().getValue(message, boolean.class); - boolean retweets = properties.getUpdate().getRetweets().getValue(message, boolean.class); - twitter.updateFriendship(userId, enableDeviceNotification, retweets); - return; + case update: + boolean enableDeviceNotification = properties.getUpdate() + .getDevice() + .getValue(message, boolean.class); + boolean retweets = properties.getUpdate().getRetweets().getValue(message, boolean.class); + twitter.updateFriendship(userId, enableDeviceNotification, retweets); + return; - case destroy: - twitter.destroyFriendship(userId); - return; + case destroy: + twitter.destroyFriendship(userId); + return; } } else if (properties.getScreenName() != null) { String screenName = properties.getScreenName().getValue(message, String.class); switch (type) { - case create: - boolean follow = properties.getCreate().getFollow().getValue(message, boolean.class); - twitter.createFriendship(screenName, follow); - return; + case create: + boolean follow = properties.getCreate().getFollow().getValue(message, boolean.class); + twitter.createFriendship(screenName, follow); + return; - case update: - boolean enableDeviceNotification = properties.getUpdate().getDevice().getValue(message, boolean.class); - boolean retweets = properties.getUpdate().getRetweets().getValue(message, boolean.class); - twitter.updateFriendship(screenName, enableDeviceNotification, retweets); - return; + case update: + boolean enableDeviceNotification = properties.getUpdate() + .getDevice() + .getValue(message, boolean.class); + boolean retweets = properties.getUpdate().getRetweets().getValue(message, boolean.class); + twitter.updateFriendship(screenName, enableDeviceNotification, retweets); + return; - case destroy: - twitter.destroyFriendship(screenName); - return; + case destroy: + twitter.destroyFriendship(screenName); + return; } } else { @@ -93,4 +97,5 @@ else if (properties.getScreenName() != null) { } }; } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerProperties.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerProperties.java index 7cc4b89d..23925580 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerProperties.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/friendship/TwitterFriendshipsConsumerProperties.java @@ -25,7 +25,6 @@ import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -35,8 +34,10 @@ public class TwitterFriendshipsConsumerProperties { public enum OperationType { + /** Friendship operation types. */ create, update, destroy + } /** @@ -102,6 +103,7 @@ public boolean isUserProvided() { } public static class Create { + /** * The ID of the user to follow (boolean). */ @@ -115,9 +117,11 @@ public Expression getFollow() { public void setFollow(Expression follow) { this.follow = follow; } + } public static class Update { + /** * Enable/disable device notifications from the target user. */ @@ -145,5 +149,7 @@ public Expression getRetweets() { public void setRetweets(Expression retweets) { this.retweets = retweets; } + } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerConfiguration.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerConfiguration.java index 377d8319..20c67c22 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerConfiguration.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerConfiguration.java @@ -31,7 +31,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -42,7 +41,8 @@ public class TwitterMessageConsumerConfiguration { private static final Log logger = LogFactory.getLog(TwitterMessageConsumerConfiguration.class); @Bean - public Consumer> sendDirectMessageConsumer(TwitterMessageConsumerProperties messageProperties, Twitter twitter) { + public Consumer> sendDirectMessageConsumer(TwitterMessageConsumerProperties messageProperties, + Twitter twitter) { return message -> { try { String messageText = messageProperties.getText().getValue(message, String.class); @@ -68,4 +68,5 @@ else if (messageProperties.getScreenName() != null) { } }; } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerProperties.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerProperties.java index e37be02b..407bf3cf 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerProperties.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/message/TwitterMessageConsumerProperties.java @@ -21,7 +21,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -47,7 +46,8 @@ public class TwitterMessageConsumerProperties { private Expression userId; /** - * A media id to associate with the message. A Direct Message may only reference a single media id. + * A media id to associate with the message. A Direct Message may only reference a + * single media id. */ private Expression mediaId; @@ -82,4 +82,5 @@ public Expression getMediaId() { public void setMediaId(Expression mediaId) { this.mediaId = mediaId; } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerConfiguration.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerConfiguration.java index af49801d..37b0b9cc 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerConfiguration.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerConfiguration.java @@ -35,7 +35,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -85,8 +84,8 @@ public Function, StatusUpdate> messageToStatusUpdateFunction( } if (updateProperties.getDisplayCoordinates() != null) { - statusUpdate.setDisplayCoordinates( - updateProperties.getDisplayCoordinates().getValue(message, boolean.class)); + statusUpdate + .setDisplayCoordinates(updateProperties.getDisplayCoordinates().getValue(message, boolean.class)); } if (updateProperties.getMediaIds() != null) { @@ -109,4 +108,5 @@ public Consumer> twitterStatusUpdateConsumer(Function, Sta Consumer updateStatus) { return message -> updateStatus.accept(statusUpdateQuery.apply(message)); } + } diff --git a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerProperties.java b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerProperties.java index acb2dde6..47a9b75a 100644 --- a/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerProperties.java +++ b/consumer/spring-twitter-consumer/src/main/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateConsumerProperties.java @@ -24,7 +24,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -35,17 +34,19 @@ public class TwitterUpdateConsumerProperties { private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload"); /** - * (SpEL expression) The text of the text update. URL encode as necessary. t.co link wrapping will - * affect character counts. Defaults to message's payload + * (SpEL expression) The text of the text update. URL encode as necessary. t.co link + * wrapping will affect character counts. Defaults to message's payload */ @NotNull private Expression text = DEFAULT_EXPRESSION; /** - * (SpEL expression) In order for a URL to not be counted in the text body of an extended Tweet, provide a URL as a Tweet attachment. - * This URL must be a Tweet permalink, or Direct Message deep link. Arbitrary, non-Twitter URLs must remain in - * the text text. URLs passed to the attachment_url parameter not matching either a Tweet permalink or Direct - * Message deep link will fail at Tweet creation and cause an exception. + * (SpEL expression) In order for a URL to not be counted in the text body of an + * extended Tweet, provide a URL as a Tweet attachment. This URL must be a Tweet + * permalink, or Direct Message deep link. Arbitrary, non-Twitter URLs must remain in + * the text text. URLs passed to the attachment_url parameter not matching either a + * Tweet permalink or Direct Message deep link will fail at Tweet creation and cause + * an exception. */ private Expression attachmentUrl; @@ -55,31 +56,37 @@ public class TwitterUpdateConsumerProperties { private Expression placeId; /** - * (SpEL expression) The ID of an existing text that the update is in reply to. Note: This parameter will be ignored unless the - * author of the Tweet this parameter references is mentioned within the text text. Therefore, you must - * include @username, where username is the author of the referenced Tweet, within the update. + * (SpEL expression) The ID of an existing text that the update is in reply to. Note: + * This parameter will be ignored unless the author of the Tweet this parameter + * references is mentioned within the text text. Therefore, you must + * include @username, where username is the author of the referenced Tweet, within the + * update. * - * When inReplyToStatusId is set the auto_populate_reply_metadata is automatically set as well. Later ensures - * that leading @mentions will be looked up from the original Tweet, and added to the new Tweet from there. - * This wil append @mentions into the metadata of an extended Tweet as a reply chain grows, until the limit - * on @mentions is reached. In cases where the original Tweet has been deleted, - * the reply will fail. + * When inReplyToStatusId is set the auto_populate_reply_metadata is automatically set + * as well. Later ensures that leading @mentions will be looked up from the original + * Tweet, and added to the new Tweet from there. This wil append @mentions into the + * metadata of an extended Tweet as a reply chain grows, until the limit on @mentions + * is reached. In cases where the original Tweet has been deleted, the reply will + * fail. */ private Expression inReplyToStatusId; /** - * (SpEL expression) Whether or not to put a pin on the exact coordinates a Tweet has been sent from. + * (SpEL expression) Whether or not to put a pin on the exact coordinates a Tweet has + * been sent from. */ private Expression displayCoordinates; /** - * (SpEL expression) A comma-delimited list of media_ids to associate with the Tweet. You may include up to 4 photos or 1 animated - * GIF or 1 video in a Tweet. See Uploading Media for further details on uploading media. + * (SpEL expression) A comma-delimited list of media_ids to associate with the Tweet. + * You may include up to 4 photos or 1 animated GIF or 1 video in a Tweet. See + * Uploading Media for further details on uploading media. */ private Expression mediaIds; /** - * (SpEL expression) The location this Tweet refers to. Ignored if geo_enabled for the user is false! + * (SpEL expression) The location this Tweet refers to. Ignored if geo_enabled for the + * user is false! */ private final Location location = new Location(); @@ -142,16 +149,19 @@ public boolean validateLatLon() { } public static class Location { + /** - * The latitude of the location this Tweet refers to. This parameter will be ignored unless it is inside the range - * -90.0 to +90.0 (North is positive) inclusive. It will also be ignored if there is no corresponding long parameter. + * The latitude of the location this Tweet refers to. This parameter will be + * ignored unless it is inside the range -90.0 to +90.0 (North is positive) + * inclusive. It will also be ignored if there is no corresponding long parameter. */ private Expression lat; /** - * The longitude of the location this Tweet refers to. The valid ranges for longitude are -180.0 to +180.0 (East - * is positive) inclusive. This parameter will be ignored if outside that range, if it is not a number, - * if geo_enabled is disabled, or if there no corresponding lat parameter. + * The longitude of the location this Tweet refers to. The valid ranges for + * longitude are -180.0 to +180.0 (East is positive) inclusive. This parameter + * will be ignored if outside that range, if it is not a number, if geo_enabled is + * disabled, or if there no corresponding lat parameter. */ private Expression lon; @@ -170,5 +180,7 @@ public Expression getLon() { public void setLon(Expression lon) { this.lon = lon; } + } + } diff --git a/consumer/spring-twitter-consumer/src/test/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateSinkFunctionConfigurationTests.java b/consumer/spring-twitter-consumer/src/test/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateSinkFunctionConfigurationTests.java index 25d4e17a..d24c70b4 100644 --- a/consumer/spring-twitter-consumer/src/test/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateSinkFunctionConfigurationTests.java +++ b/consumer/spring-twitter-consumer/src/test/java/org/springframework/cloud/fn/consumer/twitter/status/update/TwitterUpdateSinkFunctionConfigurationTests.java @@ -44,8 +44,7 @@ public class TwitterUpdateSinkFunctionConfigurationTests { public void testStatusUpdateConsumer() throws TwitterException { Twitter twitter = mock(Twitter.class); - Consumer statusUpdateConsumer = - new TwitterUpdateConsumerConfiguration().updateStatus(twitter); + Consumer statusUpdateConsumer = new TwitterUpdateConsumerConfiguration().updateStatus(twitter); StatusUpdate statusUpdateQuery = new StatusUpdate("Hello World"); statusUpdateConsumer.accept(statusUpdateQuery); @@ -64,8 +63,8 @@ public void testMessageToStatusUpdateFunction() { properties.getLocation().setLat(expression("'37.78217'")); properties.getLocation().setLon(expression("'-122.40062'")); - Function, StatusUpdate> messageToStatusUpdateFunction = - new TwitterUpdateConsumerConfiguration().messageToStatusUpdateFunction(properties); + Function, StatusUpdate> messageToStatusUpdateFunction = new TwitterUpdateConsumerConfiguration() + .messageToStatusUpdateFunction(properties); StatusUpdate result = messageToStatusUpdateFunction.apply(new GenericMessage<>("Hello World")); @@ -83,4 +82,5 @@ private Expression expression(String expressionString) { ExpressionParser parser = new SpelExpressionParser(); return parser.parseExpression(expressionString); } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfiguration.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfiguration.java index bcd35214..e004b529 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfiguration.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfiguration.java @@ -69,4 +69,5 @@ public WavefrontService wavefrontService(final WavefrontConsumerProperties prope properties.getApiToken()); } } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerProperties.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerProperties.java index f5b28ce9..97289d08 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerProperties.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerProperties.java @@ -59,13 +59,13 @@ public class WavefrontConsumerProperties { private Expression timestampExpression; /** - * Collection of custom metadata associated with the metric.Point tags cannot be empty. - * Valid characters for keys: alphanumeric, hyphen ('-'), underscore ('_'), dot ('.'). - * For values any character is allowed, including spaces. To include a double quote, escape it with a backslash, - * A backslash cannot be the last character in the tag value. - * Maximum allowed length for a combination of a point tag key and value is 254 characters - * (255 including the '=' separating key and value). - * If the value is longer, the point is rejected and logged + * Collection of custom metadata associated with the metric.Point tags cannot be + * empty. Valid characters for keys: alphanumeric, hyphen ('-'), underscore ('_'), dot + * ('.'). For values any character is allowed, including spaces. To include a double + * quote, escape it with a backslash, A backslash cannot be the last character in the + * tag value. Maximum allowed length for a combination of a point tag key and value is + * 254 characters (255 including the '=' separating key and value). If the value is + * longer, the point is rejected and logged */ private Map tagExpression; @@ -173,6 +173,8 @@ public void setProxyUri(String proxyUri) { @AssertTrue(message = "Exactly one of 'proxy-uri' or the pair of ('uri' and 'api-token') must be set!") public boolean isMutuallyExclusiveProxyAndDirectAccessWavefrontConfiguration() { - return StringUtils.isEmpty(getProxyUri()) ^ (StringUtils.isEmpty(getUri()) || StringUtils.isEmpty(getApiToken())); + return StringUtils.isEmpty(getProxyUri()) + ^ (StringUtils.isEmpty(getUri()) || StringUtils.isEmpty(getApiToken())); } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormat.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormat.java index 51944c0a..b3186b74 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormat.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormat.java @@ -39,6 +39,7 @@ public class WavefrontFormat { private static final Log logger = LogFactory.getLog(WavefrontFormat.class); private final WavefrontConsumerProperties properties; + private final Message message; public WavefrontFormat(final WavefrontConsumerProperties properties, Message message) { @@ -49,19 +50,22 @@ public WavefrontFormat(final WavefrontConsumerProperties properties, Message public String getFormattedString() { final Number metricValue = extractMetricValueFromPayload(); - final Map pointTagsMap = extractPointTagsMapFromPayload( - properties.getTagExpression(), message); + final Map pointTagsMap = extractPointTagsMapFromPayload(properties.getTagExpression(), message); validatePointTagsKeyValuePairs(pointTagsMap); final String formattedPointTagsPart = getFormattedPointTags(pointTagsMap); if (properties.getTimestampExpression() == null) { - return String.format("\"%s\" %s source=%s %s", properties.getMetricName(), metricValue, - properties.getSource(), formattedPointTagsPart).trim(); + return String + .format("\"%s\" %s source=%s %s", properties.getMetricName(), metricValue, properties.getSource(), + formattedPointTagsPart) + .trim(); } final Long timestamp = extractTimestampFromPayload(); - return String.format("\"%s\" %s %d source=%s %s", properties.getMetricName(), metricValue, timestamp, - properties.getSource(), formattedPointTagsPart).trim(); + return String + .format("\"%s\" %s %d source=%s %s", properties.getMetricName(), metricValue, timestamp, + properties.getSource(), formattedPointTagsPart) + .trim(); } private Long extractTimestampFromPayload() { @@ -69,8 +73,10 @@ private Long extractTimestampFromPayload() { return properties.getTimestampExpression().getValue(message, Long.class); } catch (SpelEvaluationException e) { - throw new ValidationException("The timestamp value has to be a number that reflects the epoch seconds of the " + - "metric (e.g. 1382754475).", e); + throw new ValidationException( + "The timestamp value has to be a number that reflects the epoch seconds of the " + + "metric (e.g. 1382754475).", + e); } } @@ -79,46 +85,46 @@ private Number extractMetricValueFromPayload() { return properties.getMetricExpression().getValue(message, Number.class); } catch (SpelEvaluationException e) { - throw new ValidationException("The metric value has to be a double-precision floating point number or a " + - "long integer. It can be positive, negative, or 0.", e); + throw new ValidationException("The metric value has to be a double-precision floating point number or a " + + "long integer. It can be positive, negative, or 0.", e); } } private String getFormattedPointTags(Map pointTagsMap) { - return pointTagsMap.entrySet().stream() - .map(it -> String.format("%s=\"%s\"", it.getKey(), it.getValue())) - .collect(Collectors.joining(" ")); + return pointTagsMap.entrySet() + .stream() + .map(it -> String.format("%s=\"%s\"", it.getKey(), it.getValue())) + .collect(Collectors.joining(" ")); } - private Map extractPointTagsMapFromPayload(Map pointTagsExpressionsPointValue, Message message) { - return pointTagsExpressionsPointValue.entrySet().stream() - .map(it -> { - try { - final Object pointValue = it.getValue().getValue(message); - return new AbstractMap.SimpleEntry<>(it.getKey(), pointValue); - } - catch (EvaluationException e) { - logger.warn("Unable to extract point tag for key " + it.getKey() + " from payload", e); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + private Map extractPointTagsMapFromPayload(Map pointTagsExpressionsPointValue, + Message message) { + return pointTagsExpressionsPointValue.entrySet().stream().map(it -> { + try { + final Object pointValue = it.getValue().getValue(message); + return new AbstractMap.SimpleEntry<>(it.getKey(), pointValue); + } + catch (EvaluationException e) { + logger.warn("Unable to extract point tag for key " + it.getKey() + " from payload", e); + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } private void validatePointTagsKeyValuePairs(Map pointTagsMap) { pointTagsMap.forEach((key, value) -> { if (!Pattern.matches("^[a-zA-Z0-9._-]+", key)) { - throw new ValidationException("Point tag key \"" + key + "\" contains invalid characters: Valid " + - "characters are alphanumeric, hyphen (\"-\"), underscore (\"_\"), dot (\".\")"); + throw new ValidationException("Point tag key \"" + key + "\" contains invalid characters: Valid " + + "characters are alphanumeric, hyphen (\"-\"), underscore (\"_\"), dot (\".\")"); } final int keyValueCombinationLength = key.length() + value.toString().length(); if (keyValueCombinationLength > 254) { - logger.warn("Maximum allowed length for a combination of a point tag key and value " + - "is 254 characters. The length of combination for key " + key + " is " + - keyValueCombinationLength + "."); + logger.warn("Maximum allowed length for a combination of a point tag key and value " + + "is 254 characters. The length of combination for key " + key + " is " + + keyValueCombinationLength + "."); } }); } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontService.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontService.java index d2860d3a..8a446fbc 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontService.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontService.java @@ -33,7 +33,9 @@ public class DirectConnectionWavefrontService implements WavefrontService { private static final Log logger = LogFactory.getLog(DirectConnectionWavefrontService.class); private final RestTemplate restTemplate; + private final String wavefrontDomain; + private final String wavefrontToken; public DirectConnectionWavefrontService(final RestTemplateBuilder restTemplateBuilder, @@ -53,4 +55,5 @@ public void send(String metricInWavefrontFormat) { final HttpEntity httpEntity = new HttpEntity<>(metricInWavefrontFormat, headers); restTemplate.exchange(wavefrontDomain + "/report", HttpMethod.POST, httpEntity, Void.class); } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontService.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontService.java index 1b61aebb..6c3368af 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontService.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontService.java @@ -30,6 +30,7 @@ public class ProxyConnectionWavefrontService implements WavefrontService { private static final Log logger = LogFactory.getLog(ProxyConnectionWavefrontService.class); private final RestTemplate restTemplate; + private final String wavefrontProxyUrl; public ProxyConnectionWavefrontService(final RestTemplateBuilder restTemplateBuilder, @@ -45,4 +46,5 @@ public void send(String metricInWavefrontFormat) { } restTemplate.postForEntity(wavefrontProxyUrl, metricInWavefrontFormat, Void.class); } + } diff --git a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontService.java b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontService.java index 2d75f1d9..fb61b17a 100644 --- a/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontService.java +++ b/consumer/spring-wavefront-consumer/src/main/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontService.java @@ -20,5 +20,7 @@ * @author Timo Salm */ public interface WavefrontService { + void send(String metricInWavefrontFormat); + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfigurationTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfigurationTest.java index 10e32b8a..d8544830 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfigurationTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerConfigurationTest.java @@ -35,15 +35,11 @@ /** * @author Timo Salm */ -@SpringBootTest(properties = { - "wavefront.metric-name=vehicle-location", - "wavefront.source=vehicle-api", +@SpringBootTest(properties = { "wavefront.metric-name=vehicle-location", "wavefront.source=vehicle-api", "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", "wavefront.timestamp-expression=#jsonPath(payload,'$.receivedAt')", "wavefront.tag-expression.vin=#jsonPath(payload,'$.vin')", - "wavefront.tag-expression.latitude=#jsonPath(payload,'$.location.latitude')", - "wavefront.proxy-uri=testUrl" -}) + "wavefront.tag-expression.latitude=#jsonPath(payload,'$.location.latitude')", "wavefront.proxy-uri=testUrl" }) public class WavefrontConsumerConfigurationTest { @Autowired @@ -60,17 +56,19 @@ public void init() { @Test void testWavefrontConsumer() { final long timestamp = new Date().getTime(); - final String dataJsonString = "{ \"mileage\": 1.5, \"receivedAt\": " + timestamp + ", \"vin\": \"test-vin\", " + - "\"location\": {\"latitude\": 4.53, \"longitude\": 2.89 }}"; + final String dataJsonString = "{ \"mileage\": 1.5, \"receivedAt\": " + timestamp + ", \"vin\": \"test-vin\", " + + "\"location\": {\"latitude\": 4.53, \"longitude\": 2.89 }}"; wavefrontConsumer.accept(new GenericMessage(dataJsonString.getBytes())); - final String formattedString = "\"vehicle-location\" 1.5 " + timestamp + " source=vehicle-api " + - "latitude=\"4.53\" vin=\"test-vin\""; + final String formattedString = "\"vehicle-location\" 1.5 " + timestamp + " source=vehicle-api " + + "latitude=\"4.53\" vin=\"test-vin\""; Mockito.verify(wavefrontServiceMock, Mockito.times(1)).send(formattedString); } @SpringBootApplication static class WavefrontConsumerTestApplication { + } + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerPropertiesTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerPropertiesTest.java index ac7e52b4..8d4ca901 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerPropertiesTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontConsumerPropertiesTest.java @@ -36,6 +36,7 @@ public class WavefrontConsumerPropertiesTest { private final Expression testExpression = new SpelExpressionParser().parseExpression("#jsonPath(payload,'$')"); + private Validator validator; @BeforeEach @@ -46,7 +47,8 @@ public void setUp() { @Test void testRequiredProperties() { - final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, null, null, null, "proxy"); + final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, + null, null, null, "proxy"); final List emptyValues = Arrays.asList(null, ""); emptyValues.forEach(emptyValue -> { @@ -68,8 +70,10 @@ void testRequiredProperties() { @Test void testValidMetricNameValues() { - final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, null, null, null, "proxy"); - final List validMetricNameValues = Arrays.asList("b", "B", "2", ".", "/", "_", ",", "-", "c.8W-2h_dE_,J-h/"); + final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, + null, null, null, "proxy"); + final List validMetricNameValues = Arrays.asList("b", "B", "2", ".", "/", "_", ",", "-", + "c.8W-2h_dE_,J-h/"); assertThat(validator.validate(properties).isEmpty()).isTrue(); validMetricNameValues.forEach(validMetricNameValue -> { @@ -86,7 +90,8 @@ void testValidMetricNameValues() { @Test void testValidSourceValues() { - final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, null, null, null, "proxy"); + final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("v", "v", testExpression, null, + null, null, null, "proxy"); final List validSourceValues = Arrays.asList("b", "B", "2", ".", "_", "-", "c.8W-2h_dE_J-h", createStringOfLength(128)); assertThat(validator.validate(properties).isEmpty()).isTrue(); @@ -96,7 +101,8 @@ void testValidSourceValues() { assertThat(validator.validate(properties).isEmpty()).isTrue(); }); - final List invalidSourceValues = Arrays.asList(" ", ":", "a B", "#", "/", ",", createStringOfLength(129)); + final List invalidSourceValues = Arrays.asList(" ", ":", "a B", "#", "/", ",", + createStringOfLength(129)); invalidSourceValues.forEach(invalidSourceValue -> { properties.setSource(invalidSourceValue); assertThat(validator.validate(properties).isEmpty()).isFalse(); @@ -108,4 +114,5 @@ private String createStringOfLength(int length) { Arrays.fill(chars, 'a'); return new String(chars); } + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormatTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormatTest.java index 8983f267..578b5a6c 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormatTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/WavefrontFormatTest.java @@ -64,29 +64,31 @@ void testGetFormattedString() { final String dataJsonString = "{ \"value\": 1.5, \"timestamp\": " + timestamp + ", " + "\"testProp1\": \"testvalue1\", \"testProp2\": \"testvalue2\" }"; - final Map pointTagsExpressionsPointValueMap = Stream.of( - new AbstractMap.SimpleEntry<>("testpoint1", expression("$.testProp1")), - new AbstractMap.SimpleEntry<>("testpoint2", expression("$.testProp2")) - ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final Map pointTagsExpressionsPointValueMap = Stream + .of(new AbstractMap.SimpleEntry<>("testpoint1", expression("$.testProp1")), + new AbstractMap.SimpleEntry<>("testpoint2", expression("$.testProp2"))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", expression("$.value"), expression("$.timestamp"), pointTagsExpressionsPointValueMap, null, null, null); - final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString(); - assertThat(result).isEqualTo("\"testMetricName\" 1.5 " + timestamp + " source=testSource testpoint2=\"testvalue2\"" - + " testpoint1=\"testvalue1\"", result); + final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)) + .getFormattedString(); + assertThat(result).isEqualTo("\"testMetricName\" 1.5 " + timestamp + + " source=testSource testpoint2=\"testvalue2\"" + " testpoint1=\"testvalue1\"", result); } @Test void testGetFormattedStringWithoutTimeStamp() { final String dataJsonString = "{ \"value\": 1.5, \"testProp1\": \"testvalue1\", \"testProp2\": \"testvalue2\" }"; - final Map pointTagsExpressionsPointValueMap = - Stream.of(new AbstractMap.SimpleEntry<>("testpoint1", expression("$.testProp1"))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final Map pointTagsExpressionsPointValueMap = Stream + .of(new AbstractMap.SimpleEntry<>("testpoint1", expression("$.testProp1"))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); - final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString(); + final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)) + .getFormattedString(); assertThat(result).isEqualTo("\"testMetricName\" 1.5 source=testSource testpoint1=\"testvalue1\""); } @@ -98,7 +100,8 @@ void testGetFormattedStringWithoutPointTags() { final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", expression("$.value"), expression("$.timestamp"), Collections.emptyMap(), null, null, null); - final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString(); + final String result = new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)) + .getFormattedString(); assertThat(result).isEqualTo("\"testMetricName\" 1.5 " + timestamp + " source=testSource"); } @@ -107,10 +110,10 @@ void testInvalidMetricValue() { final String dataJsonString = "{ \"value\": a}"; final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", expression("$.value"), null, Collections.emptyMap(), null, null, null); - final Exception exception = Assertions.assertThrows(RuntimeException.class, () -> - new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString()); + final Exception exception = Assertions.assertThrows(RuntimeException.class, + () -> new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString()); assertThat(exception.getLocalizedMessage().startsWith("The metric value has to be a double-precision floating")) - .isTrue(); + .isTrue(); } @Test @@ -132,27 +135,27 @@ void testInvalidPointTagsLengthWarning() { final String testPointTagKey = createStringOfLength(127); - final Map pointTagsExpressionsPointValueMap = - Stream.of(new AbstractMap.SimpleEntry<>(testPointTagKey, expression("$.testPoint1"))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final Map pointTagsExpressionsPointValueMap = Stream + .of(new AbstractMap.SimpleEntry<>(testPointTagKey, expression("$.testPoint1"))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); - final String dataJsonString = "{ \"value\": 1.5, \"testPoint1\": \"" + - createStringOfLength(254 - testPointTagKey.length()) + "\" }"; + final String dataJsonString = "{ \"value\": 1.5, \"testPoint1\": \"" + + createStringOfLength(254 - testPointTagKey.length()) + "\" }"; new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString(); assertThat(listAppender.list.stream() - .filter(event -> event.getMessage().startsWith("Maximum allowed length for a combination")) - .count()).isEqualTo(0); + .filter(event -> event.getMessage().startsWith("Maximum allowed length for a combination")) + .count()).isEqualTo(0); - final String dataJsonStringWithTooLongValue = "{ \"value\": 1.5, \"testPoint1\": \"" + - createStringOfLength(255 - testPointTagKey.length()) + "\" }"; + final String dataJsonStringWithTooLongValue = "{ \"value\": 1.5, \"testPoint1\": \"" + + createStringOfLength(255 - testPointTagKey.length()) + "\" }"; new WavefrontFormat(properties, new GenericMessage<>(dataJsonStringWithTooLongValue)).getFormattedString(); assertThat(listAppender.list.stream() - .filter(event -> event.getMessage().startsWith("Maximum allowed length for a combination") - && event.getLevel().equals(Level.WARN)) - .count()).isEqualTo(1); + .filter(event -> event.getMessage().startsWith("Maximum allowed length for a combination") + && event.getLevel().equals(Level.WARN)) + .count()).isEqualTo(1); } @Test @@ -161,27 +164,27 @@ void testInvalidPointTagKeys() { final List validPointTagKeys = Arrays.asList("b", "B", "2", ".", "_", "-", "c.8W-2h_dE_J-h"); for (String validPointTagKey : validPointTagKeys) { - final Map pointTagsExpressionsPointValueMap = - Stream.of(new AbstractMap.SimpleEntry<>(validPointTagKey, expression("$.testPoint1"))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", - expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); + final Map pointTagsExpressionsPointValueMap = Stream + .of(new AbstractMap.SimpleEntry<>(validPointTagKey, expression("$.testPoint1"))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", + "testSource", expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString(); } final List invalidPointTagKeys = Arrays.asList(" ", ":", "a B", "#", "/", ","); invalidPointTagKeys.forEach(invalidPointTagKey -> { - final Map pointTagsExpressionsPointValueMap = - Stream.of(new AbstractMap.SimpleEntry<>(invalidPointTagKey, expression("$.testPoint1"))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", "testSource", - expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); + final Map pointTagsExpressionsPointValueMap = Stream + .of(new AbstractMap.SimpleEntry<>(invalidPointTagKey, expression("$.testPoint1"))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final WavefrontConsumerProperties properties = new WavefrontConsumerProperties("testMetricName", + "testSource", expression("$.value"), null, pointTagsExpressionsPointValueMap, null, null, null); final Exception exception = Assertions.assertThrows(RuntimeException.class, () -> new WavefrontFormat(properties, new GenericMessage<>(dataJsonString)).getFormattedString()); assertThat(exception.getLocalizedMessage() - .startsWith("Point tag key \"" + invalidPointTagKey + "\" contains invalid characters")).isTrue(); + .startsWith("Point tag key \"" + invalidPointTagKey + "\" contains invalid characters")).isTrue(); }); } @@ -193,8 +196,11 @@ private String createStringOfLength(int length) { private Expression expression(final String jsonPathExpression) { final Expression expression = parser.parseExpression("#jsonPath(payload,'" + jsonPathExpression + "')"); - final StandardEvaluationContext evaluationContext = (StandardEvaluationContext) ((SpelExpression) expression).getEvaluationContext(); - evaluationContext.registerFunction("jsonPath", Objects.requireNonNull(BeanUtils.resolveSignature("evaluate", JsonPathUtils.class))); + final StandardEvaluationContext evaluationContext = (StandardEvaluationContext) ((SpelExpression) expression) + .getEvaluationContext(); + evaluationContext.registerFunction("jsonPath", + Objects.requireNonNull(BeanUtils.resolveSignature("evaluate", JsonPathUtils.class))); return expression; } + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontServiceTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontServiceTest.java index 968ccd58..3a48bc00 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontServiceTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/DirectConnectionWavefrontServiceTest.java @@ -33,7 +33,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; - /** * @author Timo Salm */ @@ -54,11 +53,11 @@ void testSendMetricInWavefrontFormat() { service.send(metricInWavefrontFormat); final ArgumentCaptor argument = ArgumentCaptor.forClass(HttpEntity.class); - verify(restTemplateMock, Mockito.times(1)) - .exchange(eq(wavefrontServerUri + "/report"), eq(HttpMethod.POST), argument.capture(), - eq(Void.class)); + verify(restTemplateMock, Mockito.times(1)).exchange(eq(wavefrontServerUri + "/report"), eq(HttpMethod.POST), + argument.capture(), eq(Void.class)); assertThat(Objects.requireNonNull(argument.getValue().getHeaders().get("Authorization")).get(0)) - .isEqualTo("Bearer " + wavefrontApiToken); + .isEqualTo("Bearer " + wavefrontApiToken); assertThat(Objects.requireNonNull(argument.getValue().getBody())).isEqualTo(metricInWavefrontFormat); } + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontServiceTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontServiceTest.java index 3f8f60bd..8f8183e3 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontServiceTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/ProxyConnectionWavefrontServiceTest.java @@ -41,10 +41,12 @@ void testSendMetricInWavefrontFormat() { final String metricInWavefrontFormat = "testMetric"; final String wavefrontProxyUrl = "testWavefrontProxyUrl"; - final WavefrontService service = new ProxyConnectionWavefrontService(restTemplateBuilderMock, wavefrontProxyUrl); + final WavefrontService service = new ProxyConnectionWavefrontService(restTemplateBuilderMock, + wavefrontProxyUrl); service.send(metricInWavefrontFormat); - verify(restTemplateMock, Mockito.times(1)) - .postForEntity(eq(wavefrontProxyUrl), eq(metricInWavefrontFormat), eq(Void.class)); + verify(restTemplateMock, Mockito.times(1)).postForEntity(eq(wavefrontProxyUrl), eq(metricInWavefrontFormat), + eq(Void.class)); } + } diff --git a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontServiceConditionTest.java b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontServiceConditionTest.java index 7cbb224e..7ce1ff82 100644 --- a/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontServiceConditionTest.java +++ b/consumer/spring-wavefront-consumer/src/test/java/org/springframework/cloud/fn/consumer/wavefront/service/WavefrontServiceConditionTest.java @@ -34,71 +34,59 @@ */ public class WavefrontServiceConditionTest { - private final ApplicationContextRunner runner = new ApplicationContextRunner() - .withConfiguration(UserConfigurations.of(WavefrontConsumerConfiguration.class, - SpelExpressionConverterConfiguration.class)); + private final ApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration( + UserConfigurations.of(WavefrontConsumerConfiguration.class, SpelExpressionConverterConfiguration.class)); @Test public void proxyConnectionShouldBeUsedIfWavefrontProxyAddressSet() { - runner.withPropertyValues( - "wavefront.metric-name=vehicle-location", - "wavefront.source=vehicle-api", + runner.withPropertyValues("wavefront.metric-name=vehicle-location", "wavefront.source=vehicle-api", "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", - "wavefront.proxy-uri=http://wavefront-proxy.internal:2878", - "wavefront.uri=", - "wavefront.api-token=" - ).run(context -> { - assertThat(context).hasSingleBean(ProxyConnectionWavefrontService.class); - assertThat(context).doesNotHaveBean(DirectConnectionWavefrontService.class); - }); + "wavefront.proxy-uri=http://wavefront-proxy.internal:2878", "wavefront.uri=", "wavefront.api-token=") + .run(context -> { + assertThat(context).hasSingleBean(ProxyConnectionWavefrontService.class); + assertThat(context).doesNotHaveBean(DirectConnectionWavefrontService.class); + }); } @Test public void proxyConnectionShouldBeUsedIfWavefrontProxyAddressAndDomainAndTokenSet() { - runner.withPropertyValues( - "wavefront.metric-name=vehicle-location", - "wavefront.source=vehicle-api", - "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", - "wavefront.proxy-uri=http://wavefront-proxy.internal:2878", - "wavefront.uri=https://my.wavefront.com", - "wavefront.api-token=" + UUID.randomUUID() - ).run(context -> { - assertThat(context).hasFailed(); - final Throwable rootCause = NestedExceptionUtils.getRootCause(context.getStartupFailure()); - assertThat(Objects.requireNonNull(rootCause).getLocalizedMessage()) + runner + .withPropertyValues("wavefront.metric-name=vehicle-location", "wavefront.source=vehicle-api", + "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", + "wavefront.proxy-uri=http://wavefront-proxy.internal:2878", + "wavefront.uri=https://my.wavefront.com", "wavefront.api-token=" + UUID.randomUUID()) + .run(context -> { + assertThat(context).hasFailed(); + final Throwable rootCause = NestedExceptionUtils.getRootCause(context.getStartupFailure()); + assertThat(Objects.requireNonNull(rootCause).getLocalizedMessage()) .contains("Exactly one of 'proxy-uri' or the pair of ('uri' and 'api-token') must be set!"); - }); + }); } @Test public void directConnectionShouldBeUsedIfWavefrontDomainAndTokenSet() { - runner.withPropertyValues( - "wavefront.metric-name=vehicle-location", - "wavefront.source=vehicle-api", - "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", - "wavefront.proxy-uri=", - "wavefront.uri=https://my.wavefront.com", - "wavefront.api-token=" + UUID.randomUUID() - ).run(context -> { - assertThat(context).hasSingleBean(DirectConnectionWavefrontService.class); - assertThat(context).doesNotHaveBean(ProxyConnectionWavefrontService.class); - }); + runner + .withPropertyValues("wavefront.metric-name=vehicle-location", "wavefront.source=vehicle-api", + "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", "wavefront.proxy-uri=", + "wavefront.uri=https://my.wavefront.com", "wavefront.api-token=" + UUID.randomUUID()) + .run(context -> { + assertThat(context).hasSingleBean(DirectConnectionWavefrontService.class); + assertThat(context).doesNotHaveBean(ProxyConnectionWavefrontService.class); + }); } @Test public void applicationStartupShouldFailWithMeaningfulErrorMessageIfWavefrontProxyAddressOrDomainAndTokenNotSet() { - runner.withPropertyValues( - "wavefront.metric-name=vehicle-location", - "wavefront.source=vehicle-api", - "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", - "wavefront.proxy-uri=", - "wavefront.uri=", - "wavefront.api-token=" - ).run(context -> { - assertThat(context).hasFailed(); - final Throwable rootCause = NestedExceptionUtils.getRootCause(context.getStartupFailure()); - assertThat(Objects.requireNonNull(rootCause).getLocalizedMessage()) + runner + .withPropertyValues("wavefront.metric-name=vehicle-location", "wavefront.source=vehicle-api", + "wavefront.metric-expression=#jsonPath(payload,'$.mileage')", "wavefront.proxy-uri=", + "wavefront.uri=", "wavefront.api-token=") + .run(context -> { + assertThat(context).hasFailed(); + final Throwable rootCause = NestedExceptionUtils.getRootCause(context.getStartupFailure()); + assertThat(Objects.requireNonNull(rootCause).getLocalizedMessage()) .contains("Exactly one of 'proxy-uri' or the pair of ('uri' and 'api-token') must be set!"); - }); + }); } + } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerConfiguration.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerConfiguration.java index 37908f5e..3b30038e 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerConfiguration.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerConfiguration.java @@ -78,7 +78,8 @@ public Consumer> websocketConsumer(InMemoryTraceRepository websocketT String messagePayload = message.getPayload().toString(); for (Channel channel : WebsocketConsumerServer.channels) { if (logger.isTraceEnabled()) { - logger.trace(String.format("Writing message %s to channel %s", messagePayload, channel.localAddress())); + logger.trace( + String.format("Writing message %s to channel %s", messagePayload, channel.localAddress())); } channel.write(new TextWebSocketFrame(messagePayload)); @@ -102,13 +103,15 @@ private void addMessageToTraceRepository(InMemoryTraceRepository websocketTraceR @Configuration static class WebsocketConsumerServerConfiguration { + @Bean public InMemoryTraceRepository websocketTraceRepository() { return new InMemoryTraceRepository(); } @Bean - public WebsocketConsumerServer server(WebsocketConsumerProperties properties, WebsocketConsumerServerInitializer initializer) { + public WebsocketConsumerServer server(WebsocketConsumerProperties properties, + WebsocketConsumerServerInitializer initializer) { return new WebsocketConsumerServer(properties, initializer); } @@ -116,6 +119,7 @@ public WebsocketConsumerServer server(WebsocketConsumerProperties properties, We public WebsocketConsumerServerInitializer initializer(InMemoryTraceRepository websocketTraceRepository) { return new WebsocketConsumerServerInitializer(websocketTraceRepository); } + } } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerProperties.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerProperties.java index 4c881c36..263ef471 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerProperties.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerProperties.java @@ -58,7 +58,8 @@ public class WebsocketConsumerProperties { int port = DEFAULT_PORT; /** - * the number of threads for the Netty {@link io.netty.channel.EventLoopGroup}. Default is 1 + * the number of threads for the Netty {@link io.netty.channel.EventLoopGroup}. + * Default is 1 */ int threads = DEFAULT_THREADS; @@ -68,7 +69,8 @@ public class WebsocketConsumerProperties { String logLevel = DEFAULT_LOGLEVEL; /** - * the path on which a WebsocketSink consumer needs to connect. Default is /websocket + * the path on which a WebsocketSink consumer needs to connect. Default is + * /websocket */ String path = DEFAULT_PATH; @@ -111,4 +113,5 @@ public String getPath() { public void setPath(String path) { this.path = path; } + } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServer.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServer.java index 1ac4844d..ee30ea58 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServer.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServer.java @@ -33,9 +33,9 @@ import org.apache.commons.logging.LogFactory; /** - * Bootstraps a Netty server using the {@link WebsocketConsumerServerInitializer}. Also adds - * a {@link LoggingHandler} and uses the logLevel - * from {@link WebsocketConsumerProperties#logLevel}. + * Bootstraps a Netty server using the {@link WebsocketConsumerServerInitializer}. Also + * adds a {@link LoggingHandler} and uses the logLevel from + * {@link WebsocketConsumerProperties#logLevel}. * * @author Oliver Moser * @author Gary Russell @@ -57,7 +57,8 @@ public class WebsocketConsumerServer { private int port; - public WebsocketConsumerServer(WebsocketConsumerProperties properties, WebsocketConsumerServerInitializer initializer) { + public WebsocketConsumerServer(WebsocketConsumerProperties properties, + WebsocketConsumerServerInitializer initializer) { this.properties = properties; this.initializer = initializer; } @@ -80,12 +81,12 @@ public void shutdown() { public void run() throws InterruptedException { NioServerSocketChannel channel = (NioServerSocketChannel) new ServerBootstrap().group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .handler(new LoggingHandler(nettyLogLevel())) - .childHandler(initializer) - .bind(properties.getPort()) - .sync() - .channel(); + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(nettyLogLevel())) + .childHandler(initializer) + .bind(properties.getPort()) + .sync() + .channel(); this.port = channel.localAddress().getPort(); dumpProperties(); } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerHandler.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerHandler.java index a1856df6..c8c7a0f1 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerHandler.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerHandler.java @@ -49,7 +49,8 @@ import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /** - * Handles handshakes and messages. Based on the Netty websocket examples. + * Handles handshakes and messages. Based on the Netty + * websocket examples. * * @author Netty Project * @author Oliver Moser @@ -69,8 +70,7 @@ public class WebsocketConsumerServerHandler extends SimpleChannelInboundHandler< private WebSocketServerHandshaker handshaker; public WebsocketConsumerServerHandler(InMemoryTraceRepository websocketTraceRepository, - WebsocketConsumerProperties properties, - boolean traceEnabled) { + WebsocketConsumerProperties properties, boolean traceEnabled) { this.websocketTraceRepository = websocketTraceRepository; this.properties = properties; @@ -113,8 +113,8 @@ private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { } // Handshake - WebSocketServerHandshakerFactory wsFactory - = new WebSocketServerHandshakerFactory(getWebSocketLocation(req), null, true); + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(getWebSocketLocation(req), + null, true); this.handshaker = wsFactory.newHandshaker(req); if (this.handshaker == null) { @@ -139,8 +139,8 @@ private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame fram return; } if (!(frame instanceof TextWebSocketFrame)) { - throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() - .getName())); + throw new UnsupportedOperationException( + String.format("%s frame types not supported", frame.getClass().getName())); } // todo [om] think about BinaryWebsocketFrame @@ -209,4 +209,5 @@ private String getWebSocketLocation(FullHttpRequest req) { return "ws://" + location; } } + } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerInitializer.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerInitializer.java index ffdefc02..61fba2d3 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerInitializer.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerServerInitializer.java @@ -37,8 +37,10 @@ * Does some basic initialization and setup. * *
    - *
  • Configure the {@link SslContext} based on {@link WebsocketConsumerProperties#ssl}
  • - *
  • add the {@link WebsocketConsumerServerHandler} to the underlying {@link ChannelPipeline}
  • + *
  • Configure the {@link SslContext} based on + * {@link WebsocketConsumerProperties#ssl}
  • + *
  • add the {@link WebsocketConsumerServerHandler} to the underlying + * {@link ChannelPipeline}
  • *
* * @author Oliver Moser @@ -87,4 +89,5 @@ private SslContext configureSslContext() throws CertificateException, SSLExcepti return null; } } + } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/actuator/WebsocketConsumerTraceEndpoint.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/actuator/WebsocketConsumerTraceEndpoint.java index 1609956a..b6475f5a 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/actuator/WebsocketConsumerTraceEndpoint.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/actuator/WebsocketConsumerTraceEndpoint.java @@ -29,8 +29,8 @@ import org.springframework.cloud.fn.consumer.websocket.trace.Trace; /** - * Simple Spring Boot Actuator {@link Endpoint} implementation that - * provides access to Websocket messages last sent/received. + * Simple Spring Boot Actuator {@link Endpoint} implementation that provides access to + * Websocket messages last sent/received. * * @author Oliver Moser * @author Artem Bilan diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/InMemoryTraceRepository.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/InMemoryTraceRepository.java index bdd47f11..53db610a 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/InMemoryTraceRepository.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/InMemoryTraceRepository.java @@ -25,13 +25,12 @@ /** * A repository for {@link Trace}s. * - * It is a copy of {@code InMemoryTraceRepository} from Spring Boot 1.5.x. - * Since Spring Boot 2.0 traces are only available for HTTP. + * It is a copy of {@code InMemoryTraceRepository} from Spring Boot 1.5.x. Since Spring + * Boot 2.0 traces are only available for HTTP. * * @author Dave Syer * @author Olivier Bourgain * @author Artem Bilan - * * @since 2.0 */ public class InMemoryTraceRepository { @@ -82,4 +81,5 @@ public void add(Map map) { } } } + } diff --git a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/Trace.java b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/Trace.java index 636fbe3f..1ae9f9fb 100644 --- a/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/Trace.java +++ b/consumer/spring-websocket-consumer/src/main/java/org/springframework/cloud/fn/consumer/websocket/trace/Trace.java @@ -25,12 +25,12 @@ * A value object representing a trace event: at a particular time with a simple (map) * information. Can be used for analyzing contextual information such as HTTP headers. * - *

It is a copy of {@code InMemoryTraceRepository} from Spring Boot 1.5.x. - * Since Spring Boot 2.0 traces are only available for HTTP. + *

+ * It is a copy of {@code InMemoryTraceRepository} from Spring Boot 1.5.x. Since Spring + * Boot 2.0 traces are only available for HTTP. * * @author Dave Syer * @author Artem Bilan - * * @since 2.0 */ public class Trace { @@ -53,4 +53,5 @@ public Date getTimestamp() { public Map getInfo() { return this.info; } + } diff --git a/consumer/spring-websocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerTests.java b/consumer/spring-websocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerTests.java index 07bcf7c0..31e35425 100644 --- a/consumer/spring-websocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerTests.java +++ b/consumer/spring-websocket-consumer/src/test/java/org/springframework/cloud/fn/consumer/websocket/WebsocketConsumerTests.java @@ -44,12 +44,8 @@ * @author Corneil du Plessis */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { - "websocket.consumer.port=0", - "websocket.consumer.path=/some_websocket_path", - "websocket.consumer.logLevel=DEBUG", - "websocket.consumer.threads=2" - }) + properties = { "websocket.consumer.port=0", "websocket.consumer.path=/some_websocket_path", + "websocket.consumer.logLevel=DEBUG", "websocket.consumer.threads=2" }) @DirtiesContext public class WebsocketConsumerTests { @@ -79,7 +75,8 @@ public void checkCmdlineArgs() { @Test @Timeout(TIMEOUT) public void testMultipleMessageSingleSubscriber() throws Exception { - WebsocketConsumerClientHandler handler = new WebsocketConsumerClientHandler("handler_0", MESSAGE_COUNT, TIMEOUT); + WebsocketConsumerClientHandler handler = new WebsocketConsumerClientHandler("handler_0", MESSAGE_COUNT, + TIMEOUT); doHandshake(handler); List messagesToSend = submitMultipleMessages(MESSAGE_COUNT); @@ -115,7 +112,7 @@ public void testMultipleMessagesMultipleSubscribers() throws Exception { // create multiple handlers List handlers = createHandlerList(CLIENT_COUNT, MESSAGE_COUNT); - // submit mulitple message + // submit mulitple message List messagesReceived = submitMultipleMessages(MESSAGE_COUNT); // wait on each handle @@ -145,13 +142,13 @@ private List submitMultipleMessages(int messageCount) { return messagesToSend; } - private List createHandlerList(int handlerCount, int messageCount) throws - InterruptedException, - ExecutionException { + private List createHandlerList(int handlerCount, int messageCount) + throws InterruptedException, ExecutionException { List handlers = new ArrayList<>(handlerCount); for (int i = 0; i < handlerCount; i++) { - WebsocketConsumerClientHandler handler = new WebsocketConsumerClientHandler("handler_" + i, messageCount, TIMEOUT); + WebsocketConsumerClientHandler handler = new WebsocketConsumerClientHandler("handler_" + i, messageCount, + TIMEOUT); WebSocketSession session = doHandshake(handler); assertThat(session.isOpen()); handlers.add(handler); @@ -163,4 +160,5 @@ private List createHandlerList(int handlerCount, public static class WebsocketConsumerTestApplication { } + } diff --git a/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfiguration.java b/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfiguration.java index 9827a575..2f1f3fb2 100644 --- a/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfiguration.java +++ b/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfiguration.java @@ -31,7 +31,6 @@ import org.springframework.messaging.support.MessageBuilder; /** - * * @author Daniel Frey * @since 4.0.0 */ @@ -47,13 +46,13 @@ public ChatMessageSendingMessageHandler chatMessageSendingMessageHandler(XMPPCon } @Bean - public Consumer> xmppConsumer(ChatMessageSendingMessageHandler chatMessageSendingMessageHandler, XmppConsumerProperties properties) { + public Consumer> xmppConsumer(ChatMessageSendingMessageHandler chatMessageSendingMessageHandler, + XmppConsumerProperties properties) { return message -> { - var send = MessageBuilder - .fromMessage(message) - .setHeaderIfAbsent(XmppHeaders.TO, properties.getChatTo()) - .build(); + var send = MessageBuilder.fromMessage(message) + .setHeaderIfAbsent(XmppHeaders.TO, properties.getChatTo()) + .build(); chatMessageSendingMessageHandler.handleMessage(send); diff --git a/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerProperties.java b/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerProperties.java index 32a44dfb..62c11715 100644 --- a/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerProperties.java +++ b/consumer/spring-xmpp-consumer/src/main/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerProperties.java @@ -20,7 +20,6 @@ import org.springframework.validation.annotation.Validated; /** - * * @author Daniel Frey * @since 4.0.0 */ diff --git a/consumer/spring-xmpp-consumer/src/test/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfigurationTests.java b/consumer/spring-xmpp-consumer/src/test/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfigurationTests.java index 6bb0b6b8..d884deed 100644 --- a/consumer/spring-xmpp-consumer/src/test/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfigurationTests.java +++ b/consumer/spring-xmpp-consumer/src/test/java/org/springframework/cloud/fn/consumer/xmpp/XmppConsumerConfigurationTests.java @@ -55,14 +55,8 @@ * @author Daniel Frey * @author Chris Bono */ -@SpringBootTest( - properties = { - "xmpp.factory.user=" + JOHN_USER, - "xmpp.factory.password=" + USER_PW, - "xmpp.factory.service-name=" + SERVICE_NAME, - "xmpp.factory.security-mode=disabled" - } -) +@SpringBootTest(properties = { "xmpp.factory.user=" + JOHN_USER, "xmpp.factory.password=" + USER_PW, + "xmpp.factory.service-name=" + SERVICE_NAME, "xmpp.factory.security-mode=disabled" }) @DirtiesContext public class XmppConsumerConfigurationTests implements XmppTestContainerSupport { @@ -76,7 +70,7 @@ static void registerConfigurationProperties(DynamicPropertyRegistry registry) { private Consumer> xmppConsumer; // A client connection is needed to receive the message from the xmpp server - // to verify it was received successfully + // to verify it was received successfully private XMPPTCPConnection clientConnection; @BeforeEach @@ -87,8 +81,7 @@ void setup() throws IOException, SmackException, XMPPException, InterruptedExcep builder.setHost(XmppTestContainerSupport.getXmppHost()); builder.setPort(XmppTestContainerSupport.getXmppMappedPort()); builder.setResource(SERVICE_NAME); - builder.setUsernameAndPassword(JANE_USER, USER_PW) - .setXmppDomain(SERVICE_NAME); + builder.setUsernameAndPassword(JANE_USER, USER_PW).setXmppDomain(SERVICE_NAME); this.clientConnection = new XMPPTCPConnection(builder.build()); this.clientConnection.connect(); this.clientConnection.login(); @@ -102,37 +95,35 @@ void teardown() { @Test void messageHandlerConfiguration() { - var collector - = this.clientConnection.createStanzaCollector(StanzaTypeFilter.MESSAGE); - - var testMessage = - MessageBuilder.withPayload("test") - .setHeader(XmppHeaders.TO, JANE_USER + "@" + SERVICE_NAME) - .build(); - - await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)) - .untilAsserted(() -> { - xmppConsumer.accept(testMessage); - Stanza stanza = collector.nextResult(); - assertStanza(stanza); - }); + var collector = this.clientConnection.createStanzaCollector(StanzaTypeFilter.MESSAGE); + + var testMessage = MessageBuilder.withPayload("test") + .setHeader(XmppHeaders.TO, JANE_USER + "@" + SERVICE_NAME) + .build(); + + await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)).untilAsserted(() -> { + xmppConsumer.accept(testMessage); + Stanza stanza = collector.nextResult(); + assertStanza(stanza); + }); } @Test void xmppMessageHandlerConfiguration() throws XmppStringprepException { - var collector - = this.clientConnection.createStanzaCollector(StanzaTypeFilter.MESSAGE); - - var testMessage = - MessageBuilder.withPayload(org.jivesoftware.smack.packet.MessageBuilder.buildMessage().addBody("en_us", "test").to(JANE_USER + "@" + SERVICE_NAME).build()) - .build(); - - await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)) - .untilAsserted(() -> { - xmppConsumer.accept(testMessage); - Stanza stanza = collector.nextResult(); - assertStanza(stanza); - }); + var collector = this.clientConnection.createStanzaCollector(StanzaTypeFilter.MESSAGE); + + var testMessage = MessageBuilder + .withPayload(org.jivesoftware.smack.packet.MessageBuilder.buildMessage() + .addBody("en_us", "test") + .to(JANE_USER + "@" + SERVICE_NAME) + .build()) + .build(); + + await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)).untilAsserted(() -> { + xmppConsumer.accept(testMessage); + Stanza stanza = collector.nextResult(); + assertStanza(stanza); + }); } private void assertStanza(Stanza stanza) { @@ -151,6 +142,8 @@ private void assertFrom(Stanza stanza) { @SpringBootConfiguration @EnableAutoConfiguration @Import(XmppConsumerConfiguration.class) - static class XmppConsumerTestApplication { } + static class XmppConsumerTestApplication { + + } } diff --git a/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfiguration.java b/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfiguration.java index 035ba3f7..5adbd444 100644 --- a/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfiguration.java +++ b/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfiguration.java @@ -33,7 +33,6 @@ import org.springframework.messaging.Message; /** - * * @author Daniel Frey * @since 3.1.0 */ @@ -70,8 +69,7 @@ public ZeroMqMessageHandler zeromqMessageHandler(ZeroMqConsumerProperties proper @Bean public Function>, Mono> zeromqConsumer(ZeroMqMessageHandler zeromqMessageHandler) { - return input -> input.flatMap(zeromqMessageHandler::handleMessage) - .ignoreElements(); + return input -> input.flatMap(zeromqMessageHandler::handleMessage).ignoreElements(); } } diff --git a/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerProperties.java b/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerProperties.java index 330968f2..3b91d5c4 100644 --- a/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerProperties.java +++ b/consumer/spring-zeromq-consumer/src/main/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerProperties.java @@ -25,7 +25,6 @@ import org.springframework.validation.annotation.Validated; /** - * * @author Daniel Frey * @since 3.1.0 */ diff --git a/consumer/spring-zeromq-consumer/src/test/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfigurationTests.java b/consumer/spring-zeromq-consumer/src/test/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfigurationTests.java index 445c3986..dce07377 100644 --- a/consumer/spring-zeromq-consumer/src/test/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfigurationTests.java +++ b/consumer/spring-zeromq-consumer/src/test/java/org/springframework/cloud/fn/consumer/zeromq/ZeroMqConsumerConfigurationTests.java @@ -41,7 +41,6 @@ /** * @author Daniel Frey * @author Artem Bilan - * * @since 3.1 */ @SpringBootTest(properties = "zeromq.consumer.topic='test-topic'") @@ -74,15 +73,14 @@ static void tearDown() { void testMessageHandlerConfiguration() { Message testMessage = MessageBuilder.withPayload("test").setHeader("topic", "test-topic").build(); - await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)) - .untilAsserted(() -> { - socket.subscribe("test-topic"); - subject.apply(Flux.just(testMessage)).subscribe(); - String topic = socket.recvStr(); - assertThat(topic).isEqualTo("test-topic"); - assertThat(socket.recvStr()).isEmpty(); - assertThat(socket.recvStr()).isEqualTo("test"); - }); + await().atMost(Duration.ofSeconds(20)).pollDelay(Duration.ofMillis(100)).untilAsserted(() -> { + socket.subscribe("test-topic"); + subject.apply(Flux.just(testMessage)).subscribe(); + String topic = socket.recvStr(); + assertThat(topic).isEqualTo("test-topic"); + assertThat(socket.recvStr()).isEmpty(); + assertThat(socket.recvStr()).isEqualTo("test"); + }); } diff --git a/etc/checkstyle/checkstyle-header.txt b/etc/checkstyle/checkstyle-header.txt new file mode 100644 index 00000000..7cd20a67 --- /dev/null +++ b/etc/checkstyle/checkstyle-header.txt @@ -0,0 +1,17 @@ +^\Q/*\E$ +^\Q * Copyright \E20\d\d(\-20\d\d)?\Q the original author or authors.\E$ +^\Q *\E$ +^\Q * Licensed under the Apache License, Version 2.0 (the "License");\E$ +^\Q * you may not use this file except in compliance with the License.\E$ +^\Q * You may obtain a copy of the License at\E$ +^\Q *\E$ +^\Q * https://www.apache.org/licenses/LICENSE-2.0\E$ +^\Q *\E$ +^\Q * Unless required by applicable law or agreed to in writing, software\E$ +^\Q * distributed under the License is distributed on an "AS IS" BASIS,\E$ +^\Q * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\E$ +^\Q * See the License for the specific language governing permissions and\E$ +^\Q * limitations under the License.\E$ +^\Q */\E$ +^$ +^.*$ diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml new file mode 100644 index 00000000..6b14b36a --- /dev/null +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/etc/checkstyle/checkstyle.xml b/etc/checkstyle/checkstyle.xml new file mode 100644 index 00000000..c4631b60 --- /dev/null +++ b/etc/checkstyle/checkstyle.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java index d8907733..d296da4c 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java @@ -63,17 +63,11 @@ public class AggregatorFunctionConfiguration { private BeanFactory beanFactory; @Bean - public Function>, Flux>> aggregatorFunction( - FluxMessageChannel inputChannel, - FluxMessageChannel outputChannel - ) { + public Function>, Flux>> aggregatorFunction(FluxMessageChannel inputChannel, + FluxMessageChannel outputChannel) { return input -> Flux.from(outputChannel) - .doOnRequest((request) -> - inputChannel.subscribeTo( - input.map((inputMessage) -> - MessageBuilder.fromMessage(inputMessage) - .removeHeader("kafka_consumer") - .build()))); + .doOnRequest((request) -> inputChannel.subscribeTo(input.map(( + inputMessage) -> MessageBuilder.fromMessage(inputMessage).removeHeader("kafka_consumer").build()))); } @Bean @@ -88,13 +82,10 @@ public FluxMessageChannel outputChannel() { @Bean @ServiceActivator(inputChannel = "inputChannel") - public AggregatorFactoryBean aggregator( - @Nullable CorrelationStrategy correlationStrategy, - @Nullable ReleaseStrategy releaseStrategy, - @Nullable MessageGroupProcessor messageGroupProcessor, - @Nullable MessageGroupStore messageStore, - @Qualifier("outputChannel") MessageChannel outputChannel, - @Nullable ComponentCustomizer aggregatorCustomizer) { + public AggregatorFactoryBean aggregator(@Nullable CorrelationStrategy correlationStrategy, + @Nullable ReleaseStrategy releaseStrategy, @Nullable MessageGroupProcessor messageGroupProcessor, + @Nullable MessageGroupStore messageStore, @Qualifier("outputChannel") MessageChannel outputChannel, + @Nullable ComponentCustomizer aggregatorCustomizer) { AggregatorFactoryBean aggregator = new AggregatorFactoryBean(); aggregator.setExpireGroupsUponCompletion(true); @@ -149,14 +140,10 @@ public MessageGroupProcessor messageGroupProcessor() { return new ExpressionEvaluatingMessageGroupProcessor(this.properties.getAggregation().getExpressionString()); } - @Configuration @ConditionalOnMissingBean(MessageGroupStore.class) - @Import({ - MessageStoreConfiguration.Mongo.class, - MessageStoreConfiguration.Redis.class, - MessageStoreConfiguration.Jdbc.class - }) + @Import({ MessageStoreConfiguration.Mongo.class, MessageStoreConfiguration.Redis.class, + MessageStoreConfiguration.Jdbc.class }) protected static class MessageStoreAutoConfiguration { } diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionProperties.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionProperties.java index 0f41ff62..ad896115 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionProperties.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionProperties.java @@ -55,7 +55,8 @@ public class AggregatorFunctionProperties { private String messageStoreType = MessageStoreType.SIMPLE; /** - * Persistence message store entity: table prefix in RDBMS, collection name in MongoDb, etc. + * Persistence message store entity: table prefix in RDBMS, collection name in + * MongoDb, etc. */ private String messageStoreEntity; diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/ExcludeStoresAutoConfigurationEnvironmentPostProcessor.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/ExcludeStoresAutoConfigurationEnvironmentPostProcessor.java index 60614059..87e74aff 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/ExcludeStoresAutoConfigurationEnvironmentPostProcessor.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/ExcludeStoresAutoConfigurationEnvironmentPostProcessor.java @@ -32,8 +32,9 @@ import org.springframework.core.env.PropertiesPropertySource; /** - * An {@link EnvironmentPostProcessor} to add {@code spring.autoconfigure.exclude} property - * since we can't use {@code application.properties} from the library perspective. + * An {@link EnvironmentPostProcessor} to add {@code spring.autoconfigure.exclude} + * property since we can't use {@code application.properties} from the library + * perspective. * * @author Artem Bilan * @author Corneil du Plessis @@ -45,16 +46,14 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp MutablePropertySources propertySources = environment.getPropertySources(); Properties properties = new Properties(); - properties.setProperty("spring.autoconfigure.exclude", - DataSourceAutoConfiguration.class.getName() + ", " + - DataSourceTransactionManagerAutoConfiguration.class.getName() + ", " + - MongoAutoConfiguration.class.getName() + ", " + - MongoDataAutoConfiguration.class.getName() + ", " + - MongoRepositoriesAutoConfiguration.class.getName() + ", " + - RedisAutoConfiguration.class.getName() + ", " + - RedisRepositoriesAutoConfiguration.class.getName()); + properties.setProperty("spring.autoconfigure.exclude", DataSourceAutoConfiguration.class.getName() + ", " + + DataSourceTransactionManagerAutoConfiguration.class.getName() + ", " + + MongoAutoConfiguration.class.getName() + ", " + MongoDataAutoConfiguration.class.getName() + ", " + + MongoRepositoriesAutoConfiguration.class.getName() + ", " + RedisAutoConfiguration.class.getName() + + ", " + RedisRepositoriesAutoConfiguration.class.getName()); - propertySources.addLast(new PropertiesPropertySource("aggregator.exclude.stores.auto-configuration", properties)); + propertySources + .addLast(new PropertiesPropertySource("aggregator.exclude.stores.auto-configuration", properties)); } } diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java index c823a8c3..ea0587a9 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java @@ -40,11 +40,10 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.StringUtils; - /** - * A helper class containing configuration classes for particular technologies - * to expose an appropriate {@link org.springframework.integration.store.MessageStore} bean - * via matched configuration properties. + * A helper class containing configuration classes for particular technologies to expose + * an appropriate {@link org.springframework.integration.store.MessageStore} bean via + * matched configuration properties. * * @author Artem Bilan * @author Corneil du Plessis @@ -52,11 +51,9 @@ class MessageStoreConfiguration { @ConditionalOnClass(ConfigurableMongoDbMessageStore.class) - @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, - name = "message-store-type", + @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, name = "message-store-type", havingValue = AggregatorFunctionProperties.MessageStoreType.MONGODB) - @Import({ MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class }) + @Import({ MongoAutoConfiguration.class, MongoDataAutoConfiguration.class }) static class Mongo { @Bean @@ -72,15 +69,14 @@ public MessageGroupStore messageStore(MongoTemplate mongoTemplate, AggregatorFun @Bean @Primary public MongoCustomConversions mongoDbCustomConversions() { - return new MongoCustomConversions(Arrays.asList( - new MessageToBinaryConverter(), new BinaryToMessageConverter())); + return new MongoCustomConversions( + Arrays.asList(new MessageToBinaryConverter(), new BinaryToMessageConverter())); } } @ConditionalOnClass(RedisMessageStore.class) - @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, - name = "message-store-type", + @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, name = "message-store-type", havingValue = AggregatorFunctionProperties.MessageStoreType.REDIS) @Import(RedisAutoConfiguration.class) static class Redis { @@ -93,12 +89,9 @@ public MessageGroupStore messageStore(RedisTemplate redisTemplate) { } @ConditionalOnClass(JdbcMessageStore.class) - @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, - name = "message-store-type", + @ConditionalOnProperty(prefix = AggregatorFunctionProperties.PREFIX, name = "message-store-type", havingValue = AggregatorFunctionProperties.MessageStoreType.JDBC) - @Import({ - DataSourceAutoConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class }) + @Import({ DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) static class Jdbc { @Bean diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/AbstractAggregatorFunctionTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/AbstractAggregatorFunctionTests.java index 362d7114..689cb749 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/AbstractAggregatorFunctionTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/AbstractAggregatorFunctionTests.java @@ -48,9 +48,11 @@ public abstract class AbstractAggregatorFunctionTests { @SpringBootApplication public static class AggregatorFunctionTestApplication { + public static void main(String[] args) { SpringApplication.run(AggregatorFunctionTestApplication.class, args); } + } } diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/CustomPropsAndMongoMessageStoreAggregatorTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/CustomPropsAndMongoMessageStoreAggregatorTests.java index 06e6e072..d2b3e6dc 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/CustomPropsAndMongoMessageStoreAggregatorTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/CustomPropsAndMongoMessageStoreAggregatorTests.java @@ -38,13 +38,10 @@ /** * @author Artem Bilan */ -@TestPropertySource(properties = { - "aggregator.correlation=T(Thread).currentThread().id", +@TestPropertySource(properties = { "aggregator.correlation=T(Thread).currentThread().id", "aggregator.release=!messages.?[payload == 'bar'].empty", - "aggregator.aggregation=#this.?[payload == 'foo'].![payload]", - "aggregator.messageStoreType=mongodb", - "aggregator.message-store-entity=aggregatorTest" -}) + "aggregator.aggregation=#this.?[payload == 'foo'].![payload]", "aggregator.messageStoreType=mongodb", + "aggregator.message-store-entity=aggregatorTest" }) @AutoConfigureDataMongo public class CustomPropsAndMongoMessageStoreAggregatorTests extends AbstractAggregatorFunctionTests implements MongoDbTestContainerSupport { @@ -57,22 +54,19 @@ static void mongoDbProperties(DynamicPropertyRegistry registry) { @Test public void test() { - Flux> input = - Flux.just("foo", "bar") - .map(GenericMessage::new); + Flux> input = Flux.just("foo", "bar").map(GenericMessage::new); Flux> output = this.aggregatorFunction.apply(input); output.as(StepVerifier::create) - .assertNext((message) -> - assertThat(message) - .extracting(Message::getPayload) - .isInstanceOf(List.class) - .asList() - .hasSize(1) - .element(0).isEqualTo("foo")) - .thenCancel() - .verify(Duration.ofSeconds(10)); + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .isInstanceOf(List.class) + .asList() + .hasSize(1) + .element(0) + .isEqualTo("foo")) + .thenCancel() + .verify(Duration.ofSeconds(10)); assertThat(this.messageGroupStore).isInstanceOf(ConfigurableMongoDbMessageStore.class); assertThat(TestUtils.getPropertyValue(this.messageGroupStore, "collectionName")).isEqualTo("aggregatorTest"); diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java index 06d36570..a2f5eae8 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java @@ -40,12 +40,13 @@ @Disabled("Fails on CI sporadically") @TestPropertySource(properties = "aggregator.message-store-type=simple") public class DefaultAggregatorTests extends AbstractAggregatorFunctionTests { + private static final Logger logger = LoggerFactory.getLogger(DefaultAggregatorTests.class); @Test public void test() { - Flux> input = - Flux.just(MessageBuilder.withPayload("2") + Flux> input = Flux.just( + MessageBuilder.withPayload("2") .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 2) .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) @@ -57,20 +58,13 @@ public void test() { .build()); Flux> output = this.aggregatorFunction.apply(input.log("DefaultAggregatorTests:input")); - output.log("DefaultAggregatorTests:output") - .as(StepVerifier::create) - .assertNext((message) -> { - assertThat(message) - .extracting(Message::getPayload) - .asList() - .hasSize(2) - .contains("1", "2"); - }) - .thenCancel() - .verify(Duration.ofSeconds(30)); + output.log("DefaultAggregatorTests:output").as(StepVerifier::create).assertNext((message) -> { + assertThat(message).extracting(Message::getPayload).asList().hasSize(2).contains("1", "2"); + }).thenCancel().verify(Duration.ofSeconds(30)); assertThat(this.messageGroupStore).isNull(); assertThat(this.aggregatingMessageHandler.getMessageStore()).isInstanceOf(SimpleMessageStore.class); } + } diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/JdbcMessageStoreAggregatorTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/JdbcMessageStoreAggregatorTests.java index d009270f..fd402c98 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/JdbcMessageStoreAggregatorTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/JdbcMessageStoreAggregatorTests.java @@ -40,30 +40,28 @@ public class JdbcMessageStoreAggregatorTests extends AbstractAggregatorFunctionT @Test public void test() { - Flux> input = - Flux.just(MessageBuilder.withPayload("2") - .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") - .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 2) - .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) - .build(), - MessageBuilder.withPayload("1") - .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") - .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 1) - .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) - .build()); + Flux> input = Flux.just( + MessageBuilder.withPayload("2") + .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") + .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 2) + .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) + .build(), + MessageBuilder.withPayload("1") + .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") + .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 1) + .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) + .build()); Flux> output = this.aggregatorFunction.apply(input); output.as(StepVerifier::create) - .assertNext((message) -> - assertThat(message) - .extracting(Message::getPayload) - .isInstanceOf(List.class) - .asList() - .hasSize(2) - .contains("1", "2")) - .thenCancel() - .verify(Duration.ofSeconds(10)); + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .isInstanceOf(List.class) + .asList() + .hasSize(2) + .contains("1", "2")) + .thenCancel() + .verify(Duration.ofSeconds(10)); assertThat(this.messageGroupStore).isInstanceOf(JdbcMessageStore.class); diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/RedisMessageStoreAggregatorTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/RedisMessageStoreAggregatorTests.java index 685c91d2..b7bbfb64 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/RedisMessageStoreAggregatorTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/RedisMessageStoreAggregatorTests.java @@ -41,7 +41,8 @@ * @author Artem Bilan */ @TestPropertySource(properties = "aggregator.message-store-type=redis") -public class RedisMessageStoreAggregatorTests extends AbstractAggregatorFunctionTests implements RedisTestContainerSupport { +public class RedisMessageStoreAggregatorTests extends AbstractAggregatorFunctionTests + implements RedisTestContainerSupport { @DynamicPropertySource static void redisProperties(DynamicPropertyRegistry registry) { @@ -52,8 +53,8 @@ static void redisProperties(DynamicPropertyRegistry registry) { public void test() { InputStream fakeNonSerializableKafkaConsumer = new ByteArrayInputStream(new byte[0]); - Flux> input = - Flux.just(MessageBuilder.withPayload("2") + Flux> input = Flux.just( + MessageBuilder.withPayload("2") .setHeader(IntegrationMessageHeaderAccessor.CORRELATION_ID, "my_correlation") .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_NUMBER, 2) .setHeader(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE, 2) @@ -68,13 +69,11 @@ public void test() { Flux> output = this.aggregatorFunction.apply(input); output.as(StepVerifier::create) - .assertNext((message) -> - assertThat(message) - .extracting(Message::getPayload) - .isInstanceOf(List.class) - .asList() - .hasSize(2) - .contains("1", "2")) + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .isInstanceOf(List.class) + .asList() + .hasSize(2) + .contains("1", "2")) .thenCancel() .verify(Duration.ofSeconds(10)); diff --git a/function/spring-filter-function/src/main/java/org/springframework/cloud/fn/filter/FilterFunctionConfiguration.java b/function/spring-filter-function/src/main/java/org/springframework/cloud/fn/filter/FilterFunctionConfiguration.java index cef6f671..23000808 100644 --- a/function/spring-filter-function/src/main/java/org/springframework/cloud/fn/filter/FilterFunctionConfiguration.java +++ b/function/spring-filter-function/src/main/java/org/springframework/cloud/fn/filter/FilterFunctionConfiguration.java @@ -34,7 +34,7 @@ public class FilterFunctionConfiguration { @Bean public Function, Message> filterFunction( - ExpressionEvaluatingTransformer filterExpressionEvaluatingTransformer) { + ExpressionEvaluatingTransformer filterExpressionEvaluatingTransformer) { return message -> { if ((Boolean) filterExpressionEvaluatingTransformer.transform(message).getPayload()) { @@ -48,7 +48,7 @@ public Function, Message> filterFunction( @Bean public ExpressionEvaluatingTransformer filterExpressionEvaluatingTransformer( - FilterFunctionProperties filterFunctionProperties) { + FilterFunctionProperties filterFunctionProperties) { return new ExpressionEvaluatingTransformer(filterFunctionProperties.getExpression()); } diff --git a/function/spring-filter-function/src/test/java/org/springframework/cloud/fn/filter/FilterFunctionApplicationTests.java b/function/spring-filter-function/src/test/java/org/springframework/cloud/fn/filter/FilterFunctionApplicationTests.java index 6cf98aa6..bd1e7e20 100644 --- a/function/spring-filter-function/src/test/java/org/springframework/cloud/fn/filter/FilterFunctionApplicationTests.java +++ b/function/spring-filter-function/src/test/java/org/springframework/cloud/fn/filter/FilterFunctionApplicationTests.java @@ -21,11 +21,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; - import org.junit.jupiter.api.Test; - - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -50,10 +47,9 @@ public class FilterFunctionApplicationTests { @Test public void testFilter() { - Stream> messages = List.of("hello", "hello world") - .stream() - .map(GenericMessage::new); - List> result = messages.filter(message -> this.filter.apply(message) != null).collect(Collectors.toList()); + Stream> messages = List.of("hello", "hello world").stream().map(GenericMessage::new); + List> result = messages.filter(message -> this.filter.apply(message) != null) + .collect(Collectors.toList()); assertThat(result.size()).isEqualTo(1); assertThat(result.get(0).getPayload()).isNotNull(); assertThat(result.get(0).getPayload()).isEqualTo("hello world"); diff --git a/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionConfiguration.java b/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionConfiguration.java index 1f05aaf5..938c5dad 100644 --- a/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionConfiguration.java +++ b/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionConfiguration.java @@ -58,8 +58,8 @@ public HeaderEnricher headerEnricher(BeanFactory beanFactory) { Enumeration enumeration = props.propertyNames(); while (enumeration.hasMoreElements()) { String propertyName = (String) enumeration.nextElement(); - ExpressionEvaluatingHeaderValueMessageProcessor headerValueMessageProcessor = - new ExpressionEvaluatingHeaderValueMessageProcessor<>(props.getProperty(propertyName), null); + ExpressionEvaluatingHeaderValueMessageProcessor headerValueMessageProcessor = new ExpressionEvaluatingHeaderValueMessageProcessor<>( + props.getProperty(propertyName), null); headerValueMessageProcessor.setBeanFactory(beanFactory); headersToAdd.put(propertyName, headerValueMessageProcessor); } diff --git a/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionProperties.java b/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionProperties.java index 7ca3d229..dde57189 100644 --- a/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionProperties.java +++ b/function/spring-header-enricher-function/src/main/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionProperties.java @@ -35,8 +35,8 @@ public class HeaderEnricherFunctionProperties { /** - * \n separated properties representing headers in which values are SpEL expressions, e.g - * foo='bar' \n baz=payload.baz. + * \n separated properties representing headers in which values are SpEL expressions, + * e.g foo='bar' \n baz=payload.baz. */ private Properties headers; diff --git a/function/spring-header-enricher-function/src/test/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionApplicationTests.java b/function/spring-header-enricher-function/src/test/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionApplicationTests.java index bf81d8ec..86729ffe 100644 --- a/function/spring-header-enricher-function/src/test/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionApplicationTests.java +++ b/function/spring-header-enricher-function/src/test/java/org/springframework/cloud/fn/header/enricher/HeaderEnricherFunctionApplicationTests.java @@ -33,12 +33,10 @@ import static org.hamcrest.Matchers.equalTo; /** - * * @author Gary Russell * @author Soby Chacko */ -@SpringBootTest(properties = { - "header.enricher.headers=foo='bar' \\n baz='fiz' \\n buz=payload \\n jaz=@value", +@SpringBootTest(properties = { "header.enricher.headers=foo='bar' \\n baz='fiz' \\n buz=payload \\n jaz=@value", "header.enricher.overwrite = true" }) @DirtiesContext public class HeaderEnricherFunctionApplicationTests { @@ -48,8 +46,7 @@ public class HeaderEnricherFunctionApplicationTests { @Test public void testDefault() { - final Message message = MessageBuilder.withPayload("hello") - .setHeader("baz", "qux").build(); + final Message message = MessageBuilder.withPayload("hello").setHeader("baz", "qux").build(); final Message enriched = headerEnricherFunction.apply(message); assertThat(enriched, HeaderMatcher.hasHeader("foo", equalTo("bar"))); diff --git a/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionConfiguration.java b/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionConfiguration.java index 2a5fdd2f..06767079 100644 --- a/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionConfiguration.java +++ b/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionConfiguration.java @@ -37,7 +37,9 @@ @EnableConfigurationProperties(HeaderFilterFunctionProperties.class) @ConditionalOnExpression("'${header.filter.remove}'!='' or '${header.filter.delete-all}' != ''") public class HeaderFilterFunctionConfiguration { + private final HeaderFilterFunctionProperties properties; + public HeaderFilterFunctionConfiguration(HeaderFilterFunctionProperties properties) { this.properties = properties; } @@ -46,7 +48,7 @@ public HeaderFilterFunctionConfiguration(HeaderFilterFunctionProperties properti public Function, Message> headerFilterFunction() { if (properties.isDeleteAll()) { return (message) -> { - var accessor = new IntegrationMessageHeaderAccessor(message); + var accessor = new IntegrationMessageHeaderAccessor(message); var headers = new HashSet<>(message.getHeaders().keySet()); headers.removeIf(accessor::isReadOnly); HeaderFilter filter = new HeaderFilter(headers.toArray(new String[0])); diff --git a/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionProperties.java b/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionProperties.java index e0a873ec..138c0bd7 100644 --- a/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionProperties.java +++ b/function/spring-header-filter-function/src/main/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionProperties.java @@ -20,18 +20,20 @@ /** * Properties for configuration of header-filter-function. + * * @author Corneil du Plessis */ @ConfigurationProperties("header.filter") public class HeaderFilterFunctionProperties { + /** * Indicates the need to remove all headers. */ private boolean deleteAll = false; /** - * Remove all headers named. A comma, space separated list of header names. - * The names may contain patterns. + * Remove all headers named. A comma, space separated list of header names. The names + * may contain patterns. */ private String remove; @@ -50,4 +52,5 @@ public String getRemove() { public void setRemove(String remove) { this.remove = remove; } + } diff --git a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationDeleteAllTests.java b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationDeleteAllTests.java index df7debf1..d3cf6cef 100644 --- a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationDeleteAllTests.java +++ b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationDeleteAllTests.java @@ -30,13 +30,10 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(classes = { - HeaderFilterFunctionApplicationDeleteAllTests.HeaderFilterFunctionTestApplication.class, - HeaderFilterFunctionConfiguration.class -}, - properties = {"header.filter.delete-all=true"} -) +@SpringBootTest(classes = { HeaderFilterFunctionApplicationDeleteAllTests.HeaderFilterFunctionTestApplication.class, + HeaderFilterFunctionConfiguration.class }, properties = { "header.filter.delete-all=true" }) public class HeaderFilterFunctionApplicationDeleteAllTests { + @Autowired protected Function, Message> headerFilter; @@ -54,9 +51,11 @@ public void testRemoveLeavesIdTimestampAll() { @SpringBootApplication static class HeaderFilterFunctionTestApplication { + public static void main(String[] args) throws Exception { SpringApplication.main(args); } + } } diff --git a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationTests.java b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationTests.java index 6c7ca30f..3cc112d4 100644 --- a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationTests.java +++ b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderFilterFunctionApplicationTests.java @@ -29,13 +29,10 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(classes = { - HeaderFilterFunctionApplicationTests.HeaderFilterFunctionTestApplication.class, - HeaderFilterFunctionConfiguration.class -}, - properties = {"header.filter.remove=foo,bar,pf-*"} -) +@SpringBootTest(classes = { HeaderFilterFunctionApplicationTests.HeaderFilterFunctionTestApplication.class, + HeaderFilterFunctionConfiguration.class }, properties = { "header.filter.remove=foo,bar,pf-*" }) public class HeaderFilterFunctionApplicationTests { + @Autowired protected Function, Message> headerFilter; @@ -93,9 +90,11 @@ public void testRemoveLeavesIdTimestampAll() { @SpringBootApplication static class HeaderFilterFunctionTestApplication { + public static void main(String[] main) { } + } } diff --git a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderUtils.java b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderUtils.java index d5ac05ce..927bb69d 100644 --- a/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderUtils.java +++ b/function/spring-header-filter-function/src/test/java/org/springframework/cloud/fn/header/filter/HeaderUtils.java @@ -25,6 +25,7 @@ import org.springframework.messaging.Message; final public class HeaderUtils { + private HeaderUtils() { } @@ -35,4 +36,5 @@ public static Set getNonReadOnlyHeaders(Message message) { headers.removeIf(accessor::isReadOnly); return headers; } + } diff --git a/function/spring-http-request-function/src/main/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionConfiguration.java b/function/spring-http-request-function/src/main/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionConfiguration.java index 1b5e6c86..67c3e973 100644 --- a/function/spring-http-request-function/src/main/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionConfiguration.java +++ b/function/spring-http-request-function/src/main/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionConfiguration.java @@ -33,7 +33,6 @@ import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.web.util.UriBuilderFactory; - /** * Configuration for a {@link Function} that makes HTTP requests to a resource and for * each request, returns a {@link ResponseEntity}. @@ -47,7 +46,8 @@ public class HttpRequestFunctionConfiguration { @Bean - public HttpRequestFunction httpRequestFunction(WebClient.Builder webClientBuilder, HttpRequestFunctionProperties properties) { + public HttpRequestFunction httpRequestFunction(WebClient.Builder webClientBuilder, + HttpRequestFunctionProperties properties) { return new HttpRequestFunction(webClientBuilder.build(), properties); } @@ -76,8 +76,7 @@ public HttpRequestFunction(WebClient webClient, HttpRequestFunctionProperties pr @Override public Object apply(Message message) { - return this.webClient - .method(resolveHttpMethod(message)) + return this.webClient.method(resolveHttpMethod(message)) .uri(uriBuilderFactory.uriString(resolveUrl(message)).build()) .bodyValue(resolveBody(message)) .headers(httpHeaders -> httpHeaders.addAll(resolveHeaders(message))) @@ -98,7 +97,7 @@ private HttpMethod resolveHttpMethod(Message message) { private Object resolveBody(Message message) { return properties.getBodyExpression() != null ? properties.getBodyExpression().getValue(message) - : message.getPayload(); + : message.getPayload(); } private HttpHeaders resolveHeaders(Message message) { @@ -107,8 +106,7 @@ private HttpHeaders resolveHeaders(Message message) { Map headersMap = properties.getHeadersExpression().getValue(message, Map.class); for (Map.Entry header : headersMap.entrySet()) { if (header.getKey() != null && header.getValue() != null) { - headers.add(header.getKey().toString(), - header.getValue().toString()); + headers.add(header.getKey().toString(), header.getValue().toString()); } } } @@ -123,5 +121,7 @@ public static class HttpMethodConverter implements Converter public HttpMethod convert(String source) { return HttpMethod.valueOf(source); } + } + } diff --git a/function/spring-http-request-function/src/test/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionTestApplicationTests.java b/function/spring-http-request-function/src/test/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionTestApplicationTests.java index 1747d217..307e0861 100644 --- a/function/spring-http-request-function/src/test/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionTestApplicationTests.java +++ b/function/spring-http-request-function/src/test/java/org/springframework/cloud/fn/http/request/HttpRequestFunctionTestApplicationTests.java @@ -43,25 +43,21 @@ import static org.assertj.core.api.Assertions.fail; public class HttpRequestFunctionTestApplicationTests { + private MockWebServer server = new MockWebServer(); private ApplicationContextRunner runner; @BeforeEach void setup() { - this.runner = new ApplicationContextRunner() - .withUserConfiguration(HttpRequestFunctionTestApplication.class) - .withPropertyValues( - "http.request.reply-expression=#root", - "http.request.url-expression='" + url() + "'"); + this.runner = new ApplicationContextRunner().withUserConfiguration(HttpRequestFunctionTestApplication.class) + .withPropertyValues("http.request.reply-expression=#root", "http.request.url-expression='" + url() + "'"); } @Test void shouldReturnString() { - server.enqueue(new MockResponse() - .setResponseCode(HttpStatus.OK.value()) - .setBody("hello")); + server.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value()).setBody("hello")); runner.withPropertyValues("http.request.http-method-expression='POST'").run(context -> { HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); @@ -78,26 +74,27 @@ void shouldPostJson() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, - recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .setBody(recordedRequest.getBody()) .setResponseCode(HttpStatus.CREATED.value()); } }); - runner.withPropertyValues("http.request.http-method-expression='POST'", - "http.request.headers-expression={'Content-Type':'application/json'}").run(context -> { - HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); - String json = "{\"hello\":\"world\"}"; - Message message = MessageBuilder.withPayload(json) - .build(); - ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); - assertThat(r.getBody()).isEqualTo(json); - assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); - assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); - RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); - assertThat(request.getMethod()).isEqualTo("POST"); - }); + runner + .withPropertyValues("http.request.http-method-expression='POST'", + "http.request.headers-expression={'Content-Type':'application/json'}") + .run(context -> { + HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); + String json = "{\"hello\":\"world\"}"; + Message message = MessageBuilder.withPayload(json).build(); + ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); + assertThat(r.getBody()).isEqualTo(json); + assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); + assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); + assertThat(request.getMethod()).isEqualTo("POST"); + }); } @Test @@ -106,26 +103,27 @@ void shouldPostPojoAsJson() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, - recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) .setBody(recordedRequest.getBody()) .setResponseCode(HttpStatus.CREATED.value()); } }); - runner.withPropertyValues("http.request.http-method-expression='POST'", - "http.request.expected-response-type=" + Map.class.getName()).run(context -> { - HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); - Map json = Collections.singletonMap("hello", "world"); - Message message = MessageBuilder.withPayload(json) - .build(); - ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); - assertThat(r.getBody()).isEqualTo(json); - assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); - assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); - RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); - assertThat(request.getMethod()).isEqualTo("POST"); - }); + runner + .withPropertyValues("http.request.http-method-expression='POST'", + "http.request.expected-response-type=" + Map.class.getName()) + .run(context -> { + HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); + Map json = Collections.singletonMap("hello", "world"); + Message message = MessageBuilder.withPayload(json).build(); + ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); + assertThat(r.getBody()).isEqualTo(json); + assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); + assertThat(r.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); + assertThat(request.getMethod()).isEqualTo("POST"); + }); } @Test @@ -133,24 +131,25 @@ void shouldDelete() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, - recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) - .setBody(recordedRequest.getBody()) - .setResponseCode(HttpStatus.ACCEPTED.value()); + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) + .setBody(recordedRequest.getBody()) + .setResponseCode(HttpStatus.ACCEPTED.value()); } }); - runner.withPropertyValues("http.request.http-method-expression='DELETE'", - "http.request.expected-response-type=" + Void.class.getName()).run(context -> { - HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); - Message message = MessageBuilder.withPayload("") - .build(); - ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); - assertThat(r.getBody()).isNull(); - assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); - RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); - assertThat(request.getMethod()).isEqualTo("DELETE"); - }); + runner + .withPropertyValues("http.request.http-method-expression='DELETE'", + "http.request.expected-response-type=" + Void.class.getName()) + .run(context -> { + HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); + Message message = MessageBuilder.withPayload("").build(); + ResponseEntity r = (ResponseEntity) httpRequestFunction.apply(message); + assertThat(r.getBody()).isNull(); + assertThat(r.getStatusCode().is2xxSuccessful()).isTrue(); + RecordedRequest request = server.takeRequest(100, TimeUnit.MILLISECONDS); + assertThat(request.getMethod()).isEqualTo("DELETE"); + }); } @Test @@ -173,17 +172,15 @@ void requestUsingExpressions() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, - recordedRequest.getHeader(HttpHeaders.ACCEPT)) - .setBody(recordedRequest.getBody()) - .setResponseCode(HttpStatus.OK.value()); + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, recordedRequest.getHeader(HttpHeaders.ACCEPT)) + .setBody(recordedRequest.getBody()) + .setResponseCode(HttpStatus.OK.value()); } }); - runner.withPropertyValues( - "http.request.url-expression=headers['url']", - "http.request.http-method-expression=headers['method']", - "http.request.body-expression=headers['body']", + runner.withPropertyValues("http.request.url-expression=headers['url']", + "http.request.http-method-expression=headers['method']", "http.request.body-expression=headers['body']", "http.request.headers-expression={Accept:'application/json'}") .run(context -> { Message message = MessageBuilder.withPayload("") @@ -196,8 +193,7 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isEqualTo(message.getHeaders().get("body")); - assertThat(responseEntity.getHeaders().getContentType()) - .isEqualTo(MediaType.APPLICATION_JSON); + assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); }); } @@ -206,25 +202,23 @@ void requestUsingReturnType() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, - recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) - .setBody(recordedRequest.getBody()) - .setResponseCode(HttpStatus.OK.value()); + return new MockResponse() + .setHeader(HttpHeaders.CONTENT_TYPE, recordedRequest.getHeader(HttpHeaders.CONTENT_TYPE)) + .setBody(recordedRequest.getBody()) + .setResponseCode(HttpStatus.OK.value()); } }); - runner.withPropertyValues( - "http.request..http-method-expression='POST'", - "http.request.headers-expression={'Content-Type':'application/octet-stream'}", - "http.request.expected-response-type=byte[]") + runner + .withPropertyValues("http.request..http-method-expression='POST'", + "http.request.headers-expression={'Content-Type':'application/octet-stream'}", + "http.request.expected-response-type=byte[]") .run(context -> { - Message message = MessageBuilder.withPayload("hello") - .build(); + Message message = MessageBuilder.withPayload("hello").build(); HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isEqualTo("hello".getBytes()); - assertThat(responseEntity.getHeaders().getContentType()) - .isEqualTo(MediaType.APPLICATION_OCTET_STREAM); + assertThat(responseEntity.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_OCTET_STREAM); }); } @@ -233,17 +227,14 @@ void requestUsingJsonPathMethodExpression() { server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest recordedRequest) { - return new MockResponse() - .setBody(recordedRequest.getBody()) - .setHeader("method", recordedRequest.getMethod()) - .setResponseCode(HttpStatus.OK.value()); + return new MockResponse().setBody(recordedRequest.getBody()) + .setHeader("method", recordedRequest.getMethod()) + .setResponseCode(HttpStatus.OK.value()); } }); - runner.withPropertyValues( - "http.request.http-method-expression=#jsonPath(payload,'$.myMethod')") + runner.withPropertyValues("http.request.http-method-expression=#jsonPath(payload,'$.myMethod')") .run(context -> { - Message message = MessageBuilder - .withPayload("{\"name\":\"Fred\",\"age\":41, \"myMethod\":\"POST\"}") + Message message = MessageBuilder.withPayload("{\"name\":\"Fred\",\"age\":41, \"myMethod\":\"POST\"}") .build(); HttpRequestFunction httpRequestFunction = context.getBean(HttpRequestFunction.class); ResponseEntity responseEntity = (ResponseEntity) httpRequestFunction.apply(message); @@ -258,5 +249,7 @@ private String url() { @SpringBootApplication static class HttpRequestFunctionTestApplication { + } + } diff --git a/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognition.java b/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognition.java index f93f3933..17fc3655 100644 --- a/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognition.java +++ b/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognition.java @@ -46,23 +46,29 @@ public class ImageRecognition implements AutoCloseable { private final List labels; + private final GraphRunner imageNormalization; + private final GraphRunner imageRecognition; + private final GraphRunner maxProbability; + private final GraphRunner topKProbabilities; /** - * Instead of creating the {@link ImageRecognition} service explicitly via the constructor, - * you should consider the convenience factory methods below. E.g. - * - * {@link #inception(String, int, int, boolean)} - * {@link #mobileNetV1(String, int, int, boolean)} - * {@link #mobileNetV2(String, int, int, boolean)} + * Instead of creating the {@link ImageRecognition} service explicitly via the + * constructor, you should consider the convenience factory methods below. E.g. * + * {@link #inception(String, int, int, boolean)} + * {@link #mobileNetV1(String, int, int, boolean)} + * {@link #mobileNetV2(String, int, int, boolean)} * @param modelUri location of the pre-trained model to use. - * @param labelsUri location of the list fromMemory pre-trained categories used by the model. - * @param imageRecognitionGraphInputName name of the Model's input node to send the input image to. - * @param imageRecognitionGraphOutputName name of the Model's output node to retrieve the predictions from. + * @param labelsUri location of the list fromMemory pre-trained categories used by the + * model. + * @param imageRecognitionGraphInputName name of the Model's input node to send the + * input image to. + * @param imageRecognitionGraphOutputName name of the Model's output node to retrieve + * the predictions from. * @param imageHeight normalized image height. * @param imageWidth normalized image width. * @param mean mean value to normalize the input image. @@ -71,62 +77,66 @@ public class ImageRecognition implements AutoCloseable { * @param cacheModel if true the pre-trained model is cached on the local file system. */ public ImageRecognition(String modelUri, String labelsUri, int imageHeight, int imageWidth, float mean, float scale, - String imageRecognitionGraphInputName, String imageRecognitionGraphOutputName, int responseSize, boolean cacheModel) { + String imageRecognitionGraphInputName, String imageRecognitionGraphOutputName, int responseSize, + boolean cacheModel) { this.labels = labels(labelsUri); /** - * Normalizes the raw input image into format expected by the pre-trained Inception/MobileNetV1/MobileNetV2 models. - * Typically the model is trained fromMemory images scaled to certain size. Usually it is 224x224 pixels, but can be - * also 192x192, 160x160, 128128, 92x92. Use the (imageHeight, imageWidth) to set the desired size. - * The colors, represented as R, G, B in 1-byte each were converted to float using (Value - Mean)/Scale. + * Normalizes the raw input image into format expected by the pre-trained + * Inception/MobileNetV1/MobileNetV2 models. Typically the model is trained + * fromMemory images scaled to certain size. Usually it is 224x224 pixels, but can + * be also 192x192, 160x160, 128128, 92x92. Use the (imageHeight, imageWidth) to + * set the desired size. The colors, represented as R, G, B in 1-byte each were + * converted to float using (Value - Mean)/Scale. * - * imageHeight normalized image height. - * imageWidth normalized image width. - * mean mean value to normalize the input image. - * scale scale to normalize the input image. + * imageHeight normalized image height. imageWidth normalized image width. mean + * mean value to normalize the input image. scale scale to normalize the input + * image. */ - this.imageNormalization = new GraphRunner("raw_image", "normalized_image") - .withGraphDefinition(tf -> { - Placeholder input = tf.withName("raw_image").placeholder(String.class); - final Operand decodedImage = - tf.dtypes.cast(tf.image.decodeJpeg(input, DecodeJpeg.channels(3L)), Float.class); - final Operand resizedImage = tf.image.resizeBilinear( - tf.expandDims(decodedImage, tf.constant(0)), - tf.constant(new int[] { imageHeight, imageWidth })); - tf.withName("normalized_image").math.div(tf.math.sub(resizedImage, tf.constant(mean)), tf.constant(scale)); - }); + this.imageNormalization = new GraphRunner("raw_image", "normalized_image").withGraphDefinition(tf -> { + Placeholder input = tf.withName("raw_image").placeholder(String.class); + final Operand decodedImage = tf.dtypes.cast(tf.image.decodeJpeg(input, DecodeJpeg.channels(3L)), + Float.class); + final Operand resizedImage = tf.image.resizeBilinear(tf.expandDims(decodedImage, tf.constant(0)), + tf.constant(new int[] { imageHeight, imageWidth })); + tf.withName("normalized_image").math.div(tf.math.sub(resizedImage, tf.constant(mean)), tf.constant(scale)); + }); this.imageRecognition = new GraphRunner(imageRecognitionGraphInputName, imageRecognitionGraphOutputName) - .withGraphDefinition(new ProtoBufGraphDefinition(toResource(modelUri), cacheModel)); - - this.maxProbability = new GraphRunner(Arrays.asList("recognition_result"), Arrays.asList("category", "probability")) - .withGraphDefinition(tf -> { - Placeholder input = tf.withName("recognition_result").placeholder(Float.class); - tf.withName("category").math.argMax(input, tf.constant(1)); - tf.withName("probability").max(input, tf.constant(1)); - }); - - this.topKProbabilities = new GraphRunner("recognition_result", "topK") - .withGraphDefinition(tf -> { - Placeholder input = tf.withName("recognition_result").placeholder(Float.class); - tf.withName("topK").nn.topK(input, tf.constant(responseSize), TopK.sorted(true)); - }); + .withGraphDefinition(new ProtoBufGraphDefinition(toResource(modelUri), cacheModel)); + + this.maxProbability = new GraphRunner(Arrays.asList("recognition_result"), + Arrays.asList("category", "probability")) + .withGraphDefinition(tf -> { + Placeholder input = tf.withName("recognition_result").placeholder(Float.class); + tf.withName("category").math.argMax(input, tf.constant(1)); + tf.withName("probability").max(input, tf.constant(1)); + }); + + this.topKProbabilities = new GraphRunner("recognition_result", "topK").withGraphDefinition(tf -> { + Placeholder input = tf.withName("recognition_result").placeholder(Float.class); + tf.withName("topK").nn.topK(input, tf.constant(responseSize), TopK.sorted(true)); + }); } /** - * Takes an byte encoded image and returns the most probable category recognized in the image along fromMemory its probability. + * Takes an byte encoded image and returns the most probable category recognized in + * the image along fromMemory its probability. * @param inputImage Byte array encoded image to recognize. - * @return Returns a single map entry containing the names of the recognized categories as key and the confidence as value. + * @return Returns a single map entry containing the names of the recognized + * categories as key and the confidence as value. */ public Map recognizeMax(byte[] inputImage) { try (Tensor inputTensor = Tensor.create(inputImage); GraphRunnerMemory memorize = new GraphRunnerMemory()) { Map> max = this.imageNormalization.andThen(memorize) - .andThen(this.imageRecognition).andThen(memorize) - .andThen(this.maxProbability).andThen(memorize) - .apply(Collections.singletonMap("raw_image", inputTensor)); + .andThen(this.imageRecognition) + .andThen(memorize) + .andThen(this.maxProbability) + .andThen(memorize) + .apply(Collections.singletonMap("raw_image", inputTensor)); long[] category = new long[1]; max.get("category").copyTo(category); @@ -138,26 +148,28 @@ public Map recognizeMax(byte[] inputImage) { } /** - * Takes an byte encoded input image and returns the top K most probable categories recognized in the image - * along fromMemory their probabilities. - * + * Takes an byte encoded input image and returns the top K most probable categories + * recognized in the image along fromMemory their probabilities. * @param inputImage Byte array encoded image to recognize. - * @return Returns a list of key-value pairs. Every key-value pair represents a single category recognized. - * The key stands for the name(s) of the category while the value states the confidence that there is an - * object of this category. The entries in the Map are ordered from the higher to the lower confidences. + * @return Returns a list of key-value pairs. Every key-value pair represents a single + * category recognized. The key stands for the name(s) of the category while the value + * states the confidence that there is an object of this category. The entries in the + * Map are ordered from the higher to the lower confidences. */ public Map recognizeTopK(byte[] inputImage) { try (Tensor inputTensor = Tensor.create(inputImage); GraphRunnerMemory memorize = new GraphRunnerMemory()) { - Map> topKResults = - this.imageNormalization.andThen(memorize) - .andThen(this.imageRecognition).andThen(memorize) - .andThen(this.topKProbabilities).andThen(memorize) - .apply(Collections.singletonMap("raw_image", inputTensor)); + Map> topKResults = this.imageNormalization.andThen(memorize) + .andThen(this.imageRecognition) + .andThen(memorize) + .andThen(this.topKProbabilities) + .andThen(memorize) + .apply(Collections.singletonMap("raw_image", inputTensor)); Tensor recognizedImagesTensor = memorize.getTensorMap().get(this.imageRecognition.getSingleFetchName()); - float[][] results = new float[(int) recognizedImagesTensor.shape()[0]][(int) recognizedImagesTensor.shape()[1]]; + float[][] results = new float[(int) recognizedImagesTensor.shape()[0]][(int) recognizedImagesTensor + .shape()[1]]; recognizedImagesTensor.copyTo(results); Tensor topKTensor = topKResults.get("topK").expect(Float.class); @@ -204,12 +216,10 @@ private List labels(String labelsUri) { * The Inception graph uses "input" as input and "output" as output. * */ - public static ImageRecognition inception(String inceptionModelUri, - int normalizedImageSize, int responseSize, boolean cacheModel) { - return new ImageRecognition(inceptionModelUri, "classpath:/labels/inception_labels.txt", - normalizedImageSize, normalizedImageSize, 117f, 1f, - "input", "output", - responseSize, cacheModel); + public static ImageRecognition inception(String inceptionModelUri, int normalizedImageSize, int responseSize, + boolean cacheModel) { + return new ImageRecognition(inceptionModelUri, "classpath:/labels/inception_labels.txt", normalizedImageSize, + normalizedImageSize, 117f, 1f, "input", "output", responseSize, cacheModel); } /** @@ -218,48 +228,50 @@ public static ImageRecognition inception(String inceptionModelUri, * * The normalized image size is always square (e.g. H=W) * - * The MobileNetV2 graph uses "input" as input and "MobilenetV2/Predictions/Reshape_1" as output. - * + * The MobileNetV2 graph uses "input" as input and "MobilenetV2/Predictions/Reshape_1" + * as output. * @param mobileNetV2ModelUri model uri - * @param normalizedImageSize Depends on the pre-trained model used. Usually 224px is used. + * @param normalizedImageSize Depends on the pre-trained model used. Usually 224px is + * used. * @param responseSize Number of responses fot topK requests. * @param cacheModel cache model - * @return ImageRecognition instance configured fromMemory a MobileNetV2 pre-trained model. + * @return ImageRecognition instance configured fromMemory a MobileNetV2 pre-trained + * model. */ - public static ImageRecognition mobileNetV2(String mobileNetV2ModelUri, - int normalizedImageSize, int responseSize, boolean cacheModel) { - return new ImageRecognition(mobileNetV2ModelUri, "classpath:/labels/mobilenet_labels.txt", - normalizedImageSize, normalizedImageSize, 0f, 127f, - "input", "MobilenetV2/Predictions/Reshape_1", - responseSize, cacheModel); + public static ImageRecognition mobileNetV2(String mobileNetV2ModelUri, int normalizedImageSize, int responseSize, + boolean cacheModel) { + return new ImageRecognition(mobileNetV2ModelUri, "classpath:/labels/mobilenet_labels.txt", normalizedImageSize, + normalizedImageSize, 0f, 127f, "input", "MobilenetV2/Predictions/Reshape_1", responseSize, cacheModel); } /** * Convenience for MobileNetV1 pre-trained models: * https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md#pre-trained-models * - * The MobileNetV1 graph uses "input" as input and "MobilenetV1/Predictions/Reshape_1" as output. + * The MobileNetV1 graph uses "input" as input and "MobilenetV1/Predictions/Reshape_1" + * as output. * */ - public static ImageRecognition mobileNetV1(String mobileNetV1ModelUri, - int normalizedImageSize, int responseSize, boolean cacheModel) { - return new ImageRecognition(mobileNetV1ModelUri, "classpath:/labels/mobilenet_labels.txt", - normalizedImageSize, normalizedImageSize, - 0f, 127f, - "input", "MobilenetV1/Predictions/Reshape_1", - responseSize, cacheModel); + public static ImageRecognition mobileNetV1(String mobileNetV1ModelUri, int normalizedImageSize, int responseSize, + boolean cacheModel) { + return new ImageRecognition(mobileNetV1ModelUri, "classpath:/labels/mobilenet_labels.txt", normalizedImageSize, + normalizedImageSize, 0f, 127f, "input", "MobilenetV1/Predictions/Reshape_1", responseSize, cacheModel); } /** * Convert image recognition results into {@link RecognitionResponse} domain list. - * @param recognitionMap map containing the category mames and its probability. Returned by the - * {@link ImageRecognition#recognizeMax(byte[])} and the ImageRecognition{@link #recognizeTopK(byte[])} methods - * @return List of {@link RecognitionResponse} objects representing the name-to-probability pairs in the input map. + * @param recognitionMap map containing the category mames and its probability. + * Returned by the {@link ImageRecognition#recognizeMax(byte[])} and the + * ImageRecognition{@link #recognizeTopK(byte[])} methods + * @return List of {@link RecognitionResponse} objects representing the + * name-to-probability pairs in the input map. */ public static List toRecognitionResponse(Map recognitionMap) { - return recognitionMap.entrySet().stream() - .map(nameProbabilityPair -> new RecognitionResponse(nameProbabilityPair.getKey(), nameProbabilityPair.getValue())) - .collect(Collectors.toList()); + return recognitionMap.entrySet() + .stream() + .map(nameProbabilityPair -> new RecognitionResponse(nameProbabilityPair.getKey(), + nameProbabilityPair.getValue())) + .collect(Collectors.toList()); } @Override @@ -269,4 +281,5 @@ public void close() { this.maxProbability.close(); this.topKProbabilities.close(); } + } diff --git a/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionAugmenter.java b/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionAugmenter.java index 6ffae73f..de28b526 100644 --- a/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionAugmenter.java +++ b/function/spring-image-recognition-function/src/main/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionAugmenter.java @@ -33,7 +33,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - /** * Ability to to augment the input image fromMemory the recognized labels. * @@ -47,6 +46,7 @@ public class ImageRecognitionAugmenter implements BiFunction synsetList = Arrays.asList(StreamUtils.copyToString(synsetIs, utf8) - .split("\n")).stream().map(l -> l.trim()).collect(Collectors.toList()); + List synsetList = Arrays.asList(StreamUtils.copyToString(synsetIs, utf8).split("\n")) + .stream() + .map(l -> l.trim()) + .collect(Collectors.toList()); Assert.notNull(synsetList, "Failed to initialize the labels list"); - Assert.isTrue(synsetList.size() == 1000, "Labels list is expected to be of " + - "size 1000 but was:" + synsetList.size()); + Assert.isTrue(synsetList.size() == 1000, + "Labels list is expected to be of " + "size 1000 but was:" + synsetList.size()); - Map synsetToHuman = Arrays.asList(StreamUtils.copyToString(synsetToHumanIs, utf8) - .split("\n")).stream().map(s2h -> s2h.split("\t")).collect(Collectors.toMap(s -> s[0], s -> s[1])); + Map synsetToHuman = Arrays + .asList(StreamUtils.copyToString(synsetToHumanIs, utf8).split("\n")) + .stream() + .map(s2h -> s2h.split("\t")) + .collect(Collectors.toMap(s -> s[0], s -> s[1])); Assert.notNull(synsetToHuman, "Failed to initialize the synsetToHuman"); - Assert.isTrue(synsetToHuman.size() == 21842, "synsetToHuman is expected to be of " + - "size 21842 but was:" + synsetToHuman.size()); + Assert.isTrue(synsetToHuman.size() == 21842, + "synsetToHuman is expected to be of " + "size 21842 but was:" + synsetToHuman.size()); List l = synsetList.stream().map(id -> synsetToHuman.get(id)).collect(Collectors.toList()); @@ -102,4 +107,5 @@ public static void main(String[] args) { public static Resource toResource(String uri) { return new DefaultResourceLoader().getResource(uri); } + } diff --git a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample.java b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample.java index 4f441f53..8144f045 100644 --- a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample.java +++ b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample.java @@ -42,62 +42,51 @@ public static void main(String[] args) throws IOException { // MmobileNetV2 models // https://github.com/tensorflow/models/tree/master/research/slim/nets/mobilenet#pretrained-models String mobilenet_v2_modelUri = "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_1.4_224.tgz#mobilenet_v2_1.4_224_frozen.pb"; - //String mobilenet_v2_modelUri = "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_0.35_96.tgz#mobilenet_v2_0.35_96_frozen.pb"; - try (ImageRecognition imageRecognition = ImageRecognition.mobileNetV2( - mobilenet_v2_modelUri, - 224, - 5, - true)) { + // String mobilenet_v2_modelUri = + // "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_0.35_96.tgz#mobilenet_v2_0.35_96_frozen.pb"; + try (ImageRecognition imageRecognition = ImageRecognition.mobileNetV2(mobilenet_v2_modelUri, 224, 5, true)) { - List recognizedObjects = - ImageRecognition.toRecognitionResponse(imageRecognition.recognizeTopK(inputImage)); + List recognizedObjects = ImageRecognition + .toRecognitionResponse(imageRecognition.recognizeTopK(inputImage)); // Draw the predicted labels on top of the input image. byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects); - IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV2.jpg")); - + IOUtils.write(augmentedImage, + new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV2.jpg")); String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects); System.out.println("mobilnetV2 result:" + jsonRecognizedObjects); } - String mobilenet_v1_modelUri = "https://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224.tgz#mobilenet_v1_1.0_224_frozen.pb"; - try (ImageRecognition recognitionService = ImageRecognition.mobileNetV1( - mobilenet_v1_modelUri, - 224, - 5, - true)) { + try (ImageRecognition recognitionService = ImageRecognition.mobileNetV1(mobilenet_v1_modelUri, 224, 5, true)) { - List recognizedObjects = - ImageRecognition.toRecognitionResponse(recognitionService.recognizeTopK(inputImage)); + List recognizedObjects = ImageRecognition + .toRecognitionResponse(recognitionService.recognizeTopK(inputImage)); // Draw the predicted labels on top of the input image. byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects); - IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV1.jpg")); - + IOUtils.write(augmentedImage, + new FileOutputStream("./image-recognition/target/image-augmented-mobilnetV1.jpg")); String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects); System.out.println("mobilnetV1 result:" + jsonRecognizedObjects); } String inception_modelUri = "https://storage.googleapis.com/scdf-tensorflow-models/image-recognition/tensorflow_inception_graph.pb"; - try (ImageRecognition recognitionService = ImageRecognition.inception( - inception_modelUri, - 224, - 5, - true)) { + try (ImageRecognition recognitionService = ImageRecognition.inception(inception_modelUri, 224, 5, true)) { - List recognizedObjects = - ImageRecognition.toRecognitionResponse(recognitionService.recognizeTopK(inputImage)); + List recognizedObjects = ImageRecognition + .toRecognitionResponse(recognitionService.recognizeTopK(inputImage)); // Draw the predicted labels on top of the input image. byte[] augmentedImage = new ImageRecognitionAugmenter().apply(inputImage, recognizedObjects); - IOUtils.write(augmentedImage, new FileOutputStream("./image-recognition/target/image-augmented-inception.jpg")); - + IOUtils.write(augmentedImage, + new FileOutputStream("./image-recognition/target/image-augmented-inception.jpg")); String jsonRecognizedObjects = new JsonMapperFunction().apply(recognizedObjects); System.out.println("inception result:" + jsonRecognizedObjects); } } + } diff --git a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample2.java b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample2.java index 089927b3..e995b08c 100644 --- a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample2.java +++ b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/ImageRecognitionExample2.java @@ -45,8 +45,11 @@ public static void main(String[] args) throws IOException { System.out.println(inceptions.recognizeTopK(inputImage)); System.out.println(ImageRecognition.toRecognitionResponse(inceptions.recognizeTopK(inputImage))); - IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(inceptions.recognizeTopK(inputImage))), - new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-inceptions.jpg")); + IOUtils.write( + augmenter.apply(inputImage, + ImageRecognition.toRecognitionResponse(inceptions.recognizeTopK(inputImage))), + new FileOutputStream( + "./functions/function/image-recognition-function/target/image-augmented-inceptions.jpg")); inceptions.close(); ImageRecognition mobileNetV2 = ImageRecognition.mobileNetV2( @@ -54,8 +57,11 @@ public static void main(String[] args) throws IOException { 224, 10, true); System.out.println(mobileNetV2.recognizeMax(inputImage)); System.out.println(mobileNetV2.recognizeTopK(inputImage)); - IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(mobileNetV2.recognizeTopK(inputImage))), - new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-mobilnetV2.jpg")); + IOUtils.write( + augmenter.apply(inputImage, + ImageRecognition.toRecognitionResponse(mobileNetV2.recognizeTopK(inputImage))), + new FileOutputStream( + "./functions/function/image-recognition-function/target/image-augmented-mobilnetV2.jpg")); mobileNetV2.close(); ImageRecognition mobileNetV1 = ImageRecognition.mobileNetV1( @@ -63,8 +69,12 @@ public static void main(String[] args) throws IOException { 224, 10, true); System.out.println(mobileNetV1.recognizeMax(inputImage)); System.out.println(mobileNetV1.recognizeTopK(inputImage)); - IOUtils.write(augmenter.apply(inputImage, ImageRecognition.toRecognitionResponse(mobileNetV1.recognizeTopK(inputImage))), - new FileOutputStream("./functions/function/image-recognition-function/target/image-augmented-mobilnetV1.jpg")); + IOUtils.write( + augmenter.apply(inputImage, + ImageRecognition.toRecognitionResponse(mobileNetV1.recognizeTopK(inputImage))), + new FileOutputStream( + "./functions/function/image-recognition-function/target/image-augmented-mobilnetV1.jpg")); mobileNetV1.close(); } + } diff --git a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/SavedModelTest.java b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/SavedModelTest.java index 8af8c42b..ef5665ae 100644 --- a/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/SavedModelTest.java +++ b/function/spring-image-recognition-function/src/test/java/org/springframework/cloud/fn/image/recognition/SavedModelTest.java @@ -18,7 +18,6 @@ import java.util.Map; - import com.google.protobuf.InvalidProtocolBufferException; import org.tensorflow.SavedModelBundle; import org.tensorflow.framework.MetaGraphDef; @@ -40,11 +39,13 @@ private SavedModelTest() { * */ public static void main(String[] args) throws InvalidProtocolBufferException { - SavedModelBundle savedModelBundle = - SavedModelBundle.load("/Users/ctzolov/Downloads/ssd_mobilenet_v1_coco_2017_11_17/saved_model", "serve"); - //SavedModelBundle.load("/Users/ctzolov/Downloads/aiy_vision_classifier_plants_V1_1/", "serve"); - //SavedModelBundle savedModelBundle = - // SavedModelBundle.load("/Users/ctzolov/Downloads/mnasnet-a1/saved_model", "serve"); + SavedModelBundle savedModelBundle = SavedModelBundle + .load("/Users/ctzolov/Downloads/ssd_mobilenet_v1_coco_2017_11_17/saved_model", "serve"); + // SavedModelBundle.load("/Users/ctzolov/Downloads/aiy_vision_classifier_plants_V1_1/", + // "serve"); + // SavedModelBundle savedModelBundle = + // SavedModelBundle.load("/Users/ctzolov/Downloads/mnasnet-a1/saved_model", + // "serve"); MetaGraphDef meta = MetaGraphDef.parseFrom(savedModelBundle.metaGraphDef()); @@ -54,10 +55,11 @@ public static void main(String[] args) throws InvalidProtocolBufferException { savedModelBundle.session(); - //Iterator itr = savedModelBundle.graph().operations(); + // Iterator itr = savedModelBundle.graph().operations(); // - //while (itr.hasNext()) { - // System.out.println("Operation: " + itr.next()); - //} + // while (itr.hasNext()) { + // System.out.println("Operation: " + itr.next()); + // } } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionImageAugmenter.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionImageAugmenter.java index 76fd15d3..71d6a808 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionImageAugmenter.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionImageAugmenter.java @@ -33,8 +33,8 @@ import org.springframework.util.CollectionUtils; /** - * Augment the input image fromMemory detected object bounding boxes and categories. - * For mask models and withMask set to true it draws the instance segmentation image as well. + * Augment the input image fromMemory detected object bounding boxes and categories. For + * mask models and withMask set to true it draws the instance segmentation image as well. * * @author Christian Tzolov */ @@ -48,6 +48,7 @@ public class ObjectDetectionImageAugmenter implements BiFunction objectDetections) { float[][] mask = od.getMask(); if (mask != null) { Color maskColor = this.agnosticColors ? null : GraphicsUtils.getClassColor(cid); - BufferedImage maskImage = GraphicsUtils.createMaskImage( - mask, x2 - x1, y2 - y1, maskColor); + BufferedImage maskImage = GraphicsUtils.createMaskImage(mask, x2 - x1, y2 - y1, maskColor); GraphicsUtils.overlayImages(bufferedImage, maskImage, x1, y1); } } @@ -116,4 +116,5 @@ public byte[] apply(byte[] imageBytes, List objectDetections) { // Null mend that QR image is found and not output message will be send. return imageBytes; } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputAdapter.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputAdapter.java index 8b505841..58058e4e 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputAdapter.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputAdapter.java @@ -41,8 +41,10 @@ public class ObjectDetectionInputAdapter implements Function { - Placeholder rawImage = tf.withName(RAW_IMAGE).placeholder(String.class); - Operand decodedImage = tf.dtypes.cast( - tf.image.decodeJpeg(rawImage, DecodeJpeg.channels(CHANNELS)), UInt8.class); - // Expand dimensions since the model expects images to have shape: [1, H, W, 3] - tf.withName(NORMALIZED_IMAGE).expandDims(decodedImage, tf.constant(0)); - }); + this.imageLoaderGraph = new GraphRunner(RAW_IMAGE, NORMALIZED_IMAGE).withGraphDefinition(tf -> { + Placeholder rawImage = tf.withName(RAW_IMAGE).placeholder(String.class); + Operand decodedImage = tf.dtypes.cast(tf.image.decodeJpeg(rawImage, DecodeJpeg.channels(CHANNELS)), + UInt8.class); + // Expand dimensions since the model expects images to have shape: [1, H, W, + // 3] + tf.withName(NORMALIZED_IMAGE).expandDims(decodedImage, tf.constant(0)); + }); } @Override @@ -73,4 +75,5 @@ public void close() { this.imageLoaderGraph.close(); } } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputConverter.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputConverter.java index 7f55e593..d65006f8 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputConverter.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionInputConverter.java @@ -35,8 +35,8 @@ import org.springframework.cloud.fn.common.tensorflow.deprecated.GraphicsUtils; /** - * Converts byte array image into a input Tensor for the Object Detection API. The computed image tensors uses the - * 'image_tensor' model placeholder. + * Converts byte array image into a input Tensor for the Object Detection API. The + * computed image tensors uses the 'image_tensor' model placeholder. * * @author Christian Tzolov */ @@ -95,4 +95,5 @@ private static void bgrToRgb(byte[] data) { data[i + 2] = tmp; } } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionOutputConverter.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionOutputConverter.java index 2c4d3801..42cd376d 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionOutputConverter.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionOutputConverter.java @@ -37,21 +37,22 @@ import org.springframework.util.StringUtils; /** - * Converts the Tensorflow Object Detection result into {@link ObjectDetection} list. - * The pre-trained Object Detection models (http://bit.ly/2osxMAY) produce 3 tensor outputs: - * (1) detection_classes - containing the ids of detected objects, (2) detection_scores - confidence probabilities of the - * detected object and (3) detection_boxes - the object bounding boxes withing the images. + * Converts the Tensorflow Object Detection result into {@link ObjectDetection} list. The + * pre-trained Object Detection models (http://bit.ly/2osxMAY) produce 3 tensor outputs: + * (1) detection_classes - containing the ids of detected objects, (2) detection_scores - + * confidence probabilities of the detected object and (3) detection_boxes - the object + * bounding boxes withing the images. * - * The MASK based models provide to 2 additional tensors: (4) num_detections and (5) detection_masks. + * The MASK based models provide to 2 additional tensors: (4) num_detections and (5) + * detection_masks. * - * All outputs tensors are float arrays, having: - * - 1 as the first dimension - * - maxObjects as the second dimension - * While boxesT will have 4 as the third dimension (2 sets of (x, y) coordinates). - * This can be verified by looking at scoresT.shape() etc. + * All outputs tensors are float arrays, having: - 1 as the first dimension - maxObjects + * as the second dimension While boxesT will have 4 as the third dimension (2 sets of (x, + * y) coordinates). This can be verified by looking at scoresT.shape() etc. * - * The format detected classes (e.g. labels) names is defined by the 'string_int_labels_map.proto'. The input list - * is available at: https://github.com/tensorflow/models/tree/master/research/object_detection/data + * The format detected classes (e.g. labels) names is defined by the + * 'string_int_labels_map.proto'. The input list is available at: + * https://github.com/tensorflow/models/tree/master/research/object_detection/data * * @author Christian Tzolov */ @@ -61,17 +62,23 @@ public class ObjectDetectionOutputConverter implements Function modelFetch; public ObjectDetectionOutputConverter(Resource labelsResource, float confidence, List modelFetch) { @@ -96,15 +103,16 @@ public ObjectDetectionOutputConverter(Resource labelsResource, float confidence, private static String[] loadLabels(Resource labelsResource) throws Exception { try (InputStream is = labelsResource.getInputStream()) { String text = StreamUtils.copyToString(is, Charset.forName("UTF-8")); - StringIntLabelMapOuterClass.StringIntLabelMap.Builder builder = - StringIntLabelMapOuterClass.StringIntLabelMap.newBuilder(); + StringIntLabelMapOuterClass.StringIntLabelMap.Builder builder = StringIntLabelMapOuterClass.StringIntLabelMap + .newBuilder(); TextFormat.merge(text, builder); StringIntLabelMapOuterClass.StringIntLabelMap proto = builder.build(); - int maxLabelId = proto.getItemList().stream() - .map(StringIntLabelMapOuterClass.StringIntLabelMapItem::getId) - .max(Comparator.comparing(i -> i)) - .orElse(-1); + int maxLabelId = proto.getItemList() + .stream() + .map(StringIntLabelMapOuterClass.StringIntLabelMapItem::getId) + .max(Comparator.comparing(i -> i)) + .orElse(-1); String[] labelIdToNameMap = new String[maxLabelId + 1]; for (StringIntLabelMapOuterClass.StringIntLabelMapItem item : proto.getItemList()) { @@ -112,7 +120,8 @@ private static String[] loadLabels(Resource labelsResource) throws Exception { labelIdToNameMap[item.getId()] = item.getDisplayName(); } else { - // Common practice is to set the name to a MID or Synsets Id. Synset is a set of synonyms that + // Common practice is to set the name to a MID or Synsets Id. Synset + // is a set of synonyms that // share a common meaning: https://en.wikipedia.org/wiki/WordNet labelIdToNameMap[item.getId()] = item.getName(); } @@ -125,13 +134,13 @@ private static String[] loadLabels(Resource labelsResource) throws Exception { public List> apply(Map> tensorMap) { try (Tensor scoresTensor = tensorMap.get(DETECTION_SCORES).expect(Float.class); - Tensor classesTensor = tensorMap.get(DETECTION_CLASSES).expect(Float.class); - Tensor boxesTensor = tensorMap.get(DETECTION_BOXES).expect(Float.class) - ) { + Tensor classesTensor = tensorMap.get(DETECTION_CLASSES).expect(Float.class); + Tensor boxesTensor = tensorMap.get(DETECTION_BOXES).expect(Float.class)) { // All these tensors have: // - 1 as the first dimension // - maxObjects as the second dimension - // While boxesT will have 4 as the third dimension (2 sets of (x, y) coordinates). + // While boxesT will have 4 as the third dimension (2 sets of (x, y) + // coordinates). // This can be verified by looking at scoresT.shape() etc. int batchSize = (int) scoresTensor.shape()[0]; int maxObjects = (int) scoresTensor.shape()[1]; @@ -143,10 +152,10 @@ public List> apply(Map> tensorMap) { for (int batchIndex = 0; batchIndex < batchSize; batchIndex++) { - List objectDetections = new ArrayList<>(); - // Collect only the objects whose scores are at above the configured confidence threshold. + // Collect only the objects whose scores are at above the configured + // confidence threshold. for (int i = 0; i < scores[batchIndex].length; ++i) { if (scores[batchIndex][i] >= confidence) { String category = labels[(int) classes[batchIndex][i]]; @@ -169,7 +178,8 @@ public List> apply(Map> tensorMap) { if (masksTensor != null) { long[] shape = masksTensor.shape(); - float[][][][] masks = masksTensor.copyTo(new float[(int) shape[0]][(int) shape[1]][(int) shape[2]][(int) shape[3]]); + float[][][][] masks = masksTensor + .copyTo(new float[(int) shape[0]][(int) shape[1]][(int) shape[2]][(int) shape[3]]); od.setMask(masks[batchIndex][i]); logger.debug(String.format("Num detections: %s, Masks: %s", nd, masks)); } @@ -184,4 +194,5 @@ public List> apply(Map> tensorMap) { return batchObjectDetections; } } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService.java index 2b3fa10b..18ab2d46 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService.java @@ -29,66 +29,79 @@ import org.springframework.util.StreamUtils; /** - * Convenience class that leverages the the {@link ObjectDetectionInputConverter}, {@link ObjectDetectionOutputConverter} and {@link TensorFlowService} - * in combination fromMemory the Tensorflow Object Detection API (https://github.com/tensorflow/models/tree/master/research/object_detection) - * models for detection objects in input images. + * Convenience class that leverages the the {@link ObjectDetectionInputConverter}, + * {@link ObjectDetectionOutputConverter} and {@link TensorFlowService} in combination + * fromMemory the Tensorflow Object Detection API + * (https://github.com/tensorflow/models/tree/master/research/object_detection) models for + * detection objects in input images. * - * All pre-trained models (https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md) and labels are supported. + * All pre-trained models + * (https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md) + * and labels are supported. * - * You can download pre-trained models directly from the zoo: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md - * Just use the URI notation: (zoo model tar.gz url)#(name of the frozen model file name). To speedup the bootstrap - * performance you should consider downloading the models locally and use the file:/"path to my model" URI instead! + * You can download pre-trained models directly from the zoo: + * https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md + * Just use the URI notation: (zoo model tar.gz url)#(name of the frozen model file name). + * To speedup the bootstrap performance you should consider downloading the models locally + * and use the file:/"path to my model" URI instead! * - * The object category labels for the pre-trained models are available at: https://github.com/tensorflow/models/tree/master/research/object_detection/data - * Use the labels applicable for the model. Also, for performance reasons you may consider to download the labels - * and load them from file: instead. + * The object category labels for the pre-trained models are available at: + * https://github.com/tensorflow/models/tree/master/research/object_detection/data Use the + * labels applicable for the model. Also, for performance reasons you may consider to + * download the labels and load them from file: instead. * * @author Christian Tzolov */ public class ObjectDetectionService { /** Default list of fetch names for Box models. */ - public static List FETCH_NAMES = Arrays.asList( - ObjectDetectionOutputConverter.DETECTION_SCORES, ObjectDetectionOutputConverter.DETECTION_CLASSES, - ObjectDetectionOutputConverter.DETECTION_BOXES, ObjectDetectionOutputConverter.NUM_DETECTIONS); + public static List FETCH_NAMES = Arrays.asList(ObjectDetectionOutputConverter.DETECTION_SCORES, + ObjectDetectionOutputConverter.DETECTION_CLASSES, ObjectDetectionOutputConverter.DETECTION_BOXES, + ObjectDetectionOutputConverter.NUM_DETECTIONS); /** Default list of fetch names for mask supporting models. */ - public static List FETCH_NAMES_WITH_MASKS = Arrays.asList( - ObjectDetectionOutputConverter.DETECTION_SCORES, ObjectDetectionOutputConverter.DETECTION_CLASSES, - ObjectDetectionOutputConverter.DETECTION_BOXES, ObjectDetectionOutputConverter.DETECTION_MASKS, - ObjectDetectionOutputConverter.NUM_DETECTIONS); + public static List FETCH_NAMES_WITH_MASKS = Arrays.asList(ObjectDetectionOutputConverter.DETECTION_SCORES, + ObjectDetectionOutputConverter.DETECTION_CLASSES, ObjectDetectionOutputConverter.DETECTION_BOXES, + ObjectDetectionOutputConverter.DETECTION_MASKS, ObjectDetectionOutputConverter.NUM_DETECTIONS); private final ObjectDetectionInputConverter inputConverter; + private final ObjectDetectionOutputConverter outputConverter; + private final TensorFlowService tensorFlowService; public ObjectDetectionService() { this("https://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz#frozen_inference_graph.pb", - "https://storage.googleapis.com/scdf-tensorflow-models/object-detection/mscoco_label_map.pbtxt", - 0.4f, false, true); + "https://storage.googleapis.com/scdf-tensorflow-models/object-detection/mscoco_label_map.pbtxt", 0.4f, + false, true); } /** * Convenience constructor that would initialize all necessary internal components. * @param modelUri URI of the pre-trained, frozen Tensorflow model. * @param labelsUri URI of the pre-trained category labels. - * @param confidence Confidence threshold. Only objects detected wth confidence above this threshold will be returned. - * @param withMasks If a Mask model is selected then you can use this flag to extract the instance segmentation masks as well. + * @param confidence Confidence threshold. Only objects detected wth confidence above + * this threshold will be returned. + * @param withMasks If a Mask model is selected then you can use this flag to extract + * the instance segmentation masks as well. */ - public ObjectDetectionService(String modelUri, String labelsUri, - float confidence, boolean withMasks, boolean cacheModel) { + public ObjectDetectionService(String modelUri, String labelsUri, float confidence, boolean withMasks, + boolean cacheModel) { this.inputConverter = new ObjectDetectionInputConverter(); List fetchNames = withMasks ? FETCH_NAMES_WITH_MASKS : FETCH_NAMES; - this.outputConverter = new ObjectDetectionOutputConverter( - new DefaultResourceLoader().getResource(labelsUri), confidence, fetchNames); - this.tensorFlowService = new TensorFlowService( - new DefaultResourceLoader().getResource(modelUri), fetchNames, cacheModel); + this.outputConverter = new ObjectDetectionOutputConverter(new DefaultResourceLoader().getResource(labelsUri), + confidence, fetchNames); + this.tensorFlowService = new TensorFlowService(new DefaultResourceLoader().getResource(modelUri), fetchNames, + cacheModel); } /** - * Generic constructor thea allow the converter to be pre-configured before passed to the service. - * @param inputConverter Converter from byte array to object detection input image tensor - * @param outputConverter Covets the object detection output tensors into {@link ObjectDetection } list + * Generic constructor thea allow the converter to be pre-configured before passed to + * the service. + * @param inputConverter Converter from byte array to object detection input image + * tensor + * @param outputConverter Covets the object detection output tensors into + * {@link ObjectDetection } list * @param tensorFlowService Java tensorflow runner instance */ public ObjectDetectionService(ObjectDetectionInputConverter inputConverter, @@ -100,9 +113,9 @@ public ObjectDetectionService(ObjectDetectionInputConverter inputConverter, /** * Detects objects in a single input image identified by its URI. - * * @param imageUri input image's URI - * @return Returns a list of {@link ObjectDetection} domain objects representing detected objects + * @return Returns a list of {@link ObjectDetection} domain objects representing + * detected objects */ public List detect(String imageUri) { try (InputStream is = new DefaultResourceLoader().getResource(imageUri).getInputStream()) { @@ -116,10 +129,11 @@ public List detect(String imageUri) { /** * Detects objects in a single {@link BufferedImage}. - * * @param image Input image to detect objects from. - * @param format Image format (e.g. jpg, png ...) to use when converting the buffer into byte array. - * @return Returns a list of {@link ObjectDetection} domain objects representing detected objects in the input image + * @param format Image format (e.g. jpg, png ...) to use when converting the buffer + * into byte array. + * @return Returns a list of {@link ObjectDetection} domain objects representing + * detected objects in the input image */ public List detect(BufferedImage image, String format) { return this.detect(GraphicsUtils.toImageByteArray(image, format)); @@ -127,21 +141,27 @@ public List detect(BufferedImage image, String format) { /** * Detects objects from a single input image encoded as byte array. - * * @param image Input image encoded as byte array - * @return Returns a list of {@link ObjectDetection} domain objects representing detected objects in the input image + * @return Returns a list of {@link ObjectDetection} domain objects representing + * detected objects in the input image */ public List detect(byte[] image) { - return this.inputConverter.andThen(this.tensorFlowService).andThen(this.outputConverter).apply(new byte[][] { image }).get(0); + return this.inputConverter.andThen(this.tensorFlowService) + .andThen(this.outputConverter) + .apply(new byte[][] { image }) + .get(0); } /** * Uses detects objects from a batch of input images encoded as byte array. - * - * @param batchedImages Batch of input images encoded as byte arrays. First dimension is the batch size and second the image bytes. - * @return Returns list of lists. For every input image in the batch a list of {@link ObjectDetection} domain objects representing detected objects in the input image. + * @param batchedImages Batch of input images encoded as byte arrays. First dimension + * is the batch size and second the image bytes. + * @return Returns list of lists. For every input image in the batch a list of + * {@link ObjectDetection} domain objects representing detected objects in the input + * image. */ public List> detect(byte[][] batchedImages) { return this.inputConverter.andThen(this.tensorFlowService).andThen(this.outputConverter).apply(batchedImages); } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService2.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService2.java index 09c3cc92..34bcb136 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService2.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/ObjectDetectionService2.java @@ -40,35 +40,34 @@ public class ObjectDetectionService2 implements AutoCloseable { /** Default Box models fetch names. */ - public static List FETCH_NAMES = Arrays.asList( - ObjectDetectionOutputConverter.DETECTION_SCORES, ObjectDetectionOutputConverter.DETECTION_CLASSES, - ObjectDetectionOutputConverter.DETECTION_BOXES, ObjectDetectionOutputConverter.NUM_DETECTIONS); + public static List FETCH_NAMES = Arrays.asList(ObjectDetectionOutputConverter.DETECTION_SCORES, + ObjectDetectionOutputConverter.DETECTION_CLASSES, ObjectDetectionOutputConverter.DETECTION_BOXES, + ObjectDetectionOutputConverter.NUM_DETECTIONS); /** Default Models models fetch names. */ - public static List FETCH_NAMES_WITH_MASKS = Arrays.asList( - ObjectDetectionOutputConverter.DETECTION_SCORES, ObjectDetectionOutputConverter.DETECTION_CLASSES, - ObjectDetectionOutputConverter.DETECTION_BOXES, ObjectDetectionOutputConverter.DETECTION_MASKS, - ObjectDetectionOutputConverter.NUM_DETECTIONS); + public static List FETCH_NAMES_WITH_MASKS = Arrays.asList(ObjectDetectionOutputConverter.DETECTION_SCORES, + ObjectDetectionOutputConverter.DETECTION_CLASSES, ObjectDetectionOutputConverter.DETECTION_BOXES, + ObjectDetectionOutputConverter.DETECTION_MASKS, ObjectDetectionOutputConverter.NUM_DETECTIONS); private final GraphRunner imageNormalization; + private final GraphRunner objectDetection; - private final ObjectDetectionOutputConverter outputConverter; + private final ObjectDetectionOutputConverter outputConverter; public ObjectDetectionService2(String modelUri, ObjectDetectionOutputConverter outputConverter) { - this.imageNormalization = new GraphRunner("raw_image", "normalized_image") - .withGraphDefinition(tf -> { - Placeholder rawImage = tf.withName("raw_image").placeholder(String.class); - Operand decodedImage = tf.dtypes.cast( - tf.image.decodeJpeg(rawImage, DecodeJpeg.channels(3L)), UInt8.class); - // Expand dimensions since the model expects images to have shape: [1, H, W, 3] - tf.withName("normalized_image").expandDims(decodedImage, tf.constant(0)); - }); + this.imageNormalization = new GraphRunner("raw_image", "normalized_image").withGraphDefinition(tf -> { + Placeholder rawImage = tf.withName("raw_image").placeholder(String.class); + Operand decodedImage = tf.dtypes.cast(tf.image.decodeJpeg(rawImage, DecodeJpeg.channels(3L)), + UInt8.class); + // Expand dimensions since the model expects images to have shape: [1, H, W, + // 3] + tf.withName("normalized_image").expandDims(decodedImage, tf.constant(0)); + }); this.objectDetection = new GraphRunner(Arrays.asList("image_tensor"), FETCH_NAMES) - .withGraphDefinition(new ProtoBufGraphDefinition( - new DefaultResourceLoader().getResource(modelUri), true)); + .withGraphDefinition(new ProtoBufGraphDefinition(new DefaultResourceLoader().getResource(modelUri), true)); this.outputConverter = outputConverter; } @@ -77,9 +76,10 @@ public List detect(byte[] image) { try (Tensor inputTensor = Tensor.create(image); GraphRunnerMemory memorize = new GraphRunnerMemory()) { List> out = this.imageNormalization.andThen(memorize) - .andThen(this.objectDetection).andThen(memorize) - .andThen(outputConverter) - .apply(Collections.singletonMap("raw_image", inputTensor)); + .andThen(this.objectDetection) + .andThen(memorize) + .andThen(outputConverter) + .apply(Collections.singletonMap("raw_image", inputTensor)); return out.get(0); @@ -90,7 +90,7 @@ public List detect(byte[] image) { public void close() { this.imageNormalization.close(); this.objectDetection.close(); - //this.outputConverter.close(); + // this.outputConverter.close(); } public static void main(String[] args) throws IOException { @@ -100,7 +100,8 @@ public static void main(String[] args) throws IOException { ObjectDetectionOutputConverter outputAdapter = new ObjectDetectionOutputConverter( new DefaultResourceLoader().getResource(labelUri), 0.4f, FETCH_NAMES); - //byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/object-detection.jpg"); + // byte[] inputImage = + // GraphicsUtils.loadAsByteArray("classpath:/images/object-detection.jpg"); byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/wild-animals-15.jpg"); try (ObjectDetectionService2 objectDetectionService2 = new ObjectDetectionService2(modelUri, outputAdapter)) { @@ -110,4 +111,5 @@ public static void main(String[] args) throws IOException { System.out.println(boza); } } + } diff --git a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/domain/ObjectDetection.java b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/domain/ObjectDetection.java index 15e10758..2a2c6014 100644 --- a/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/domain/ObjectDetection.java +++ b/function/spring-object-detection-function/src/main/java/org/springframework/cloud/fn/object/detection/domain/ObjectDetection.java @@ -28,12 +28,19 @@ public class ObjectDetection { private String name; + private float confidence; + private float x1; + private float y1; + private float x2; + private float y2; + private float[][] mask; + private int cid; public String getName() { @@ -102,15 +109,8 @@ public void setMask(float[][] mask) { @Override public String toString() { - return "ObjectDetection{" + - "name='" + name + '\'' + - ", confidence=" + confidence + - ", x1=" + x1 + - ", y1=" + y1 + - ", x2=" + x2 + - ", y2=" + y2 + - ", mask=" + Arrays.toString(mask) + - ", cid=" + cid + - '}'; + return "ObjectDetection{" + "name='" + name + '\'' + ", confidence=" + confidence + ", x1=" + x1 + ", y1=" + y1 + + ", x2=" + x2 + ", y2=" + y2 + ", mask=" + Arrays.toString(mask) + ", cid=" + cid + '}'; } + } diff --git a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleInstanceSegmentation.java b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleInstanceSegmentation.java index c5185bd7..0b5d892c 100644 --- a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleInstanceSegmentation.java +++ b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleInstanceSegmentation.java @@ -32,15 +32,15 @@ import org.springframework.core.io.ResourceLoader; /** - * 4 of the pre-trained model in the model zoo (https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md) + * 4 of the pre-trained model in the model zoo + * (https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md) * can also compute the masks of the detected objects, providing instance segmentation. *

* Here are the models that can be used for instance segmentation. *

- * mask_rcnn_inception_resnet_v2_atrous_coco 771 36 Masks - * mask_rcnn_inception_v2_coco 79 25 Masks - * mask_rcnn_resnet101_atrous_coco 470 33 Masks - * mask_rcnn_resnet50_atrous_coco 343 29 Masks + * mask_rcnn_inception_resnet_v2_atrous_coco 771 36 Masks mask_rcnn_inception_v2_coco 79 + * 25 Masks mask_rcnn_resnet101_atrous_coco 470 33 Masks mask_rcnn_resnet50_atrous_coco + * 343 29 Masks * * @author Christian Tzolov */ @@ -50,44 +50,53 @@ public static void main(String[] args) throws IOException { ResourceLoader resourceLoader = new DefaultResourceLoader(); - // You can download pre-trained models directly from the zoo: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md - // Just use the notation # - // For performance reasons you may consider downloading the model locally and use the file:/ URI instead! + // You can download pre-trained models directly from the zoo: + // https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md + // Just use the notation # + // For performance reasons you may consider downloading the model locally and use + // the file:/ URI instead! String model = "https://download.tensorflow.org/models/object_detection/mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28.tar.gz#frozen_inference_graph.pb"; // All labels for the pre-trained models are available at: // https://github.com/tensorflow/models/tree/master/research/object_detection/data // Use the labels applicable for the model. - // Also, for performance reasons you may consider to download the labels and load them from file: instead. + // Also, for performance reasons you may consider to download the labels and load + // them from file: instead. String labels = "https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/mscoco_label_map.pbtxt"; - // You can cache the TF model on the local file system to improve the bootstrap performance on consecutive runs! + // You can cache the TF model on the local file system to improve the bootstrap + // performance on consecutive runs! boolean CACHE_TF_MODEL = true; - // For the pre-trained models fromMemory mask you can set the INSTANCE_SEGMENTATION to enable object instance segmentation as well + // For the pre-trained models fromMemory mask you can set the + // INSTANCE_SEGMENTATION to enable object instance segmentation as well boolean INSTANCE_SEGMENTATION = true; // Only object fromMemory confidence above the threshold are returned float CONFIDENCE_THRESHOLD = 0.4f; - ObjectDetectionService detectionService = - new ObjectDetectionService(model, labels, CONFIDENCE_THRESHOLD, INSTANCE_SEGMENTATION, CACHE_TF_MODEL); + ObjectDetectionService detectionService = new ObjectDetectionService(model, labels, CONFIDENCE_THRESHOLD, + INSTANCE_SEGMENTATION, CACHE_TF_MODEL); // You can use file:, http: or classpath: to provide the path to the input image. byte[] image = GraphicsUtils.loadAsByteArray("classpath:/images/object-detection.jpg"); - // Returns a list ObjectDetection domain classes to allow programmatic accesses to the detected objects's metadata + // Returns a list ObjectDetection domain classes to allow programmatic accesses to + // the detected objects's metadata List detectedObjects = detectionService.detect(image); // Get JSON representation of the detected objects String jsonObjectDetections = new JsonMapperFunction().apply(detectedObjects); System.out.println(jsonObjectDetections); - // Draw the detected object metadata on top of the original image and store the result + // Draw the detected object metadata on top of the original image and store the + // result byte[] annotatedImage = new ObjectDetectionImageAugmenter(INSTANCE_SEGMENTATION).apply(image, detectedObjects); File projectDir = new File("functions/function/object-detection-function"); File output = new File(projectDir, "target/object-detection-segmentation-augmented.jpg"); IOUtils.write(annotatedImage, new FileOutputStream(output)); System.out.println("Created:" + output.getPath()); } + } diff --git a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleObjectDetection.java b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleObjectDetection.java index 7a8899e1..e4df6e11 100644 --- a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleObjectDetection.java +++ b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/ExampleObjectDetection.java @@ -37,31 +37,40 @@ public class ExampleObjectDetection { public static void main(String[] args) throws IOException { - // You can download pre-trained models directly from the zoo: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md - // Just use the notation # - // For performance reasons you may consider downloading the model locally and use the file:/ URI instead! + // You can download pre-trained models directly from the zoo: + // https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md + // Just use the notation # + // For performance reasons you may consider downloading the model locally and use + // the file:/ URI instead! String model = "https://download.tensorflow.org/models/object_detection/faster_rcnn_nas_coco_2018_01_28.tar.gz#frozen_inference_graph.pb"; - //Resource model = resourceLoader.getResource("https://download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_fgvc_2018_07_19.tar.gz#frozen_inference_graph.pb"); - //Resource model = resourceLoader.getResource("https://download.tensorflow.org/models/object_detection/faster_rcnn_resnet50_fgvc_2018_07_19.tar.gz#frozen_inference_graph.pb"); + // Resource model = + // resourceLoader.getResource("https://download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_fgvc_2018_07_19.tar.gz#frozen_inference_graph.pb"); + // Resource model = + // resourceLoader.getResource("https://download.tensorflow.org/models/object_detection/faster_rcnn_resnet50_fgvc_2018_07_19.tar.gz#frozen_inference_graph.pb"); // All labels for the pre-trained models are available at: // https://github.com/tensorflow/models/tree/master/research/object_detection/data // Use the labels applicable for the model. - // Also, for performance reasons you may consider to download the labels and load them from file: instead. + // Also, for performance reasons you may consider to download the labels and load + // them from file: instead. String labels = "https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/mscoco_label_map.pbtxt"; - //Resource labels = resourceLoader.getResource("https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/fgvc_2854_classes_label_map.pbtxt"); + // Resource labels = + // resourceLoader.getResource("https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/fgvc_2854_classes_label_map.pbtxt"); - // You can cache the TF model on the local file system to improve the bootstrap performance on consecutive runs! + // You can cache the TF model on the local file system to improve the bootstrap + // performance on consecutive runs! boolean CACHE_TF_MODEL = true; - // For the pre-trained models fromMemory mask you can set the INSTANCE_SEGMENTATION to enable object instance segmentation as well + // For the pre-trained models fromMemory mask you can set the + // INSTANCE_SEGMENTATION to enable object instance segmentation as well boolean NO_INSTANCE_SEGMENTATION = false; // Only object fromMemory confidence above the threshold are returned float CONFIDENCE_THRESHOLD = 0.4f; - ObjectDetectionService detectionService = - new ObjectDetectionService(model, labels, CONFIDENCE_THRESHOLD, NO_INSTANCE_SEGMENTATION, CACHE_TF_MODEL); + ObjectDetectionService detectionService = new ObjectDetectionService(model, labels, CONFIDENCE_THRESHOLD, + NO_INSTANCE_SEGMENTATION, CACHE_TF_MODEL); // You can use file:, http: or classpath: to provide the path to the input image. String inputImageUri = "classpath:/images/object-detection.jpg"; @@ -69,16 +78,21 @@ public static void main(String[] args) throws IOException { byte[] image = StreamUtils.copyToByteArray(is); - // Returns a list ObjectDetection domain classes to allow programmatic accesses to the detected objects's metadata + // Returns a list ObjectDetection domain classes to allow programmatic + // accesses to the detected objects's metadata List detectedObjects = detectionService.detect(image); // Get JSON representation of the detected objects String jsonObjectDetections = new JsonMapperFunction().apply(detectedObjects); System.out.println(jsonObjectDetections); - // Draw the detected object metadata on top of the original image and store the result - byte[] annotatedImage = new ObjectDetectionImageAugmenter(NO_INSTANCE_SEGMENTATION).apply(image, detectedObjects); - IOUtils.write(annotatedImage, new FileOutputStream("./object-detection-function/target/object-detection-augmented.jpg")); + // Draw the detected object metadata on top of the original image and store + // the result + byte[] annotatedImage = new ObjectDetectionImageAugmenter(NO_INSTANCE_SEGMENTATION).apply(image, + detectedObjects); + IOUtils.write(annotatedImage, + new FileOutputStream("./object-detection-function/target/object-detection-augmented.jpg")); } } + } diff --git a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/SimpleExample.java b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/SimpleExample.java index 039cd8dc..2d1d41ed 100644 --- a/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/SimpleExample.java +++ b/function/spring-object-detection-function/src/test/java/org/springframework/cloud/fn/object/detection/examples/SimpleExample.java @@ -16,7 +16,6 @@ package org.springframework.cloud.fn.object.detection.examples; - import java.util.List; import org.springframework.cloud.fn.object.detection.ObjectDetectionService; @@ -28,15 +27,30 @@ public class SimpleExample { public static void main(String[] args) { - // Select a pre-trained model from the model zoo: https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md - // Just use the notation # + // Select a pre-trained model from the model zoo: + // https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md + // Just use the notation # String model = "https://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_ppn_shared_box_predictor_300x300_coco14_sync_2018_07_03.tar.gz#frozen_inference_graph.pb"; - // All labels for the pre-trained models are available at: https://github.com/tensorflow/models/tree/master/research/object_detection/data + // All labels for the pre-trained models are available at: + // https://github.com/tensorflow/models/tree/master/research/object_detection/data String labels = "https://raw.githubusercontent.com/tensorflow/models/master/research/object_detection/data/mscoco_label_map.pbtxt"; - ObjectDetectionService detectionService = new ObjectDetectionService(model, labels, - 0.4f, // Only object fromMemory confidence above the threshold are returned. Confidence range is [0, 1]. + ObjectDetectionService detectionService = new ObjectDetectionService(model, labels, 0.4f, // Only + // object + // fromMemory + // confidence + // above + // the + // threshold + // are + // returned. + // Confidence + // range + // is + // [0, + // 1]. false, // No instance segmentation true); // cache the TF model locally @@ -44,4 +58,5 @@ public static void main(String[] args) { List detectedObjects = detectionService.detect("classpath:/images/object-detection.jpg"); detectedObjects.stream().map(o -> o.toString()).forEach(System.out::println); } + } diff --git a/function/spring-payload-converter-function/src/main/java/functions/ByteArrayTextToString.java b/function/spring-payload-converter-function/src/main/java/functions/ByteArrayTextToString.java index d087db26..352fcc2a 100644 --- a/function/spring-payload-converter-function/src/main/java/functions/ByteArrayTextToString.java +++ b/function/spring-payload-converter-function/src/main/java/functions/ByteArrayTextToString.java @@ -24,7 +24,6 @@ import org.springframework.util.MimeTypeUtils; /** - * * @author Christian Tzolov */ public class ByteArrayTextToString implements Function, Message> { @@ -35,17 +34,17 @@ public Message apply(Message message) { if (message.getPayload() instanceof byte[]) { final MessageHeaders headers = message.getHeaders(); String contentType = headers.containsKey(MessageHeaders.CONTENT_TYPE) - ? headers.get(MessageHeaders.CONTENT_TYPE).toString() - : MimeTypeUtils.APPLICATION_JSON_VALUE; + ? headers.get(MessageHeaders.CONTENT_TYPE).toString() : MimeTypeUtils.APPLICATION_JSON_VALUE; - if (contentType.contains("text") || contentType.contains("json") || contentType.contains("x-spring-tuple")) { + if (contentType.contains("text") || contentType.contains("json") + || contentType.contains("x-spring-tuple")) { message = MessageBuilder.withPayload(new String(((byte[]) message.getPayload()))) - .copyHeaders(message.getHeaders()) - .build(); + .copyHeaders(message.getHeaders()) + .build(); } } return message; } -} +} diff --git a/function/spring-payload-converter-function/src/main/java/functions/JsonBytesToMap.java b/function/spring-payload-converter-function/src/main/java/functions/JsonBytesToMap.java index a1bdc9df..c4fb24eb 100644 --- a/function/spring-payload-converter-function/src/main/java/functions/JsonBytesToMap.java +++ b/function/spring-payload-converter-function/src/main/java/functions/JsonBytesToMap.java @@ -29,12 +29,11 @@ import org.springframework.util.MimeTypeUtils; /** - * The {@link Function} to deserialize {@code byte[]} payload into a Map - * if {@link MessageHeaders#CONTENT_TYPE} header is JSON. - * Otherwise, the message is returned as is. + * The {@link Function} to deserialize {@code byte[]} payload into a Map if + * {@link MessageHeaders#CONTENT_TYPE} header is JSON. Otherwise, the message is returned + * as is. * * @author Artem Bilan - * * @since 4.0 */ public class JsonBytesToMap implements Function, Message> { @@ -51,15 +50,13 @@ public JsonBytesToMap(ObjectMapper objectMapper) { public Message apply(Message message) { if (message.getPayload() instanceof byte[] payload) { MessageHeaders headers = message.getHeaders(); - String contentType = - headers.containsKey(MessageHeaders.CONTENT_TYPE) - ? headers.get(MessageHeaders.CONTENT_TYPE).toString() - : MimeTypeUtils.APPLICATION_JSON_VALUE; + String contentType = headers.containsKey(MessageHeaders.CONTENT_TYPE) + ? headers.get(MessageHeaders.CONTENT_TYPE).toString() : MimeTypeUtils.APPLICATION_JSON_VALUE; if (contentType.contains("json")) { message = MessageBuilder.withPayload(payloadToMapIfCan(payload)) - .copyHeaders(message.getHeaders()) - .build(); + .copyHeaders(message.getHeaders()) + .build(); } } diff --git a/function/spring-payload-converter-function/src/test/java/functions/ByteArrayTextToStringTests.java b/function/spring-payload-converter-function/src/test/java/functions/ByteArrayTextToStringTests.java index f6492f0e..0c3f8e10 100644 --- a/function/spring-payload-converter-function/src/test/java/functions/ByteArrayTextToStringTests.java +++ b/function/spring-payload-converter-function/src/test/java/functions/ByteArrayTextToStringTests.java @@ -32,6 +32,7 @@ public class ByteArrayTextToStringTests { private static final String MESSAGE = "hello world"; + private static Function, Message> converter; @BeforeAll diff --git a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/NativeImageUtils.java b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/NativeImageUtils.java index b9ba1eeb..a8e5be3a 100644 --- a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/NativeImageUtils.java +++ b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/NativeImageUtils.java @@ -43,11 +43,10 @@ private NativeImageUtils() { * https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/ops/image_ops_impl.py#L1536 */ public static Operand grayscaleToRgb(Ops tf, Operand images) { - ExpandDims rank_1 = tf.expandDims( - tf.math.sub(tf.rank(images), tf.constant(1)), - tf.constant(0)); + ExpandDims rank_1 = tf.expandDims(tf.math.sub(tf.rank(images), tf.constant(1)), tf.constant(0)); // Create once 1D vector of the shape defined by the rank_1. - // E.g. for rank [2] will produce matrix [1, 1]. For [3] rank will produce a cube [1, 1, 1] + // E.g. for rank [2] will produce matrix [1, 1]. For [3] rank will produce a cube + // [1, 1, 1] Add ones = tf.math.add(tf.zeros(rank_1, Integer.class), tf.constant(1)); // Convert scalar 3 into 1D array [3] ExpandDims channelsAs1D = tf.expandDims(tf.constant(3), tf.constant(0)); @@ -59,49 +58,57 @@ public static Operand grayscaleToRgb(Ops tf, Operand images) { public static Operand normalizeMask(Ops tf, Operand mask, float newValue) { // generate array representing the axis indexes. // For example of tensor of rank K the axisRange is {0, 1, 2 ...K} - Range axisRange = tf.range(tf.constant(0), // from + Range axisRange = tf.range(tf.constant(0), // from tf.dtypes.cast(tf.rank(mask), Integer.class), // to tf.constant(1)); // step ReduceMax max = tf.reduceMax(mask, axisRange); - //Mul input2Float1 = tf.math.mul(tf.math.div(input2Float, max), tf.constant(1f)); + // Mul input2Float1 = tf.math.mul(tf.math.div(input2Float, max), + // tf.constant(1f)); Mul normalizedMask = tf.math.mul(tf.math.div(mask, max), tf.constant(newValue)); return normalizedMask; } /** - * Alpha Blending . - * https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending + * Alpha Blending . https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending */ - public static Operand alphaBlending(Ops tf, Operand srcRgb, Operand dstRgb, Operand srcAlpha) { + public static Operand alphaBlending(Ops tf, Operand srcRgb, Operand dstRgb, + Operand srcAlpha) { Sub alpha = tf.math.sub(tf.onesLike(srcRgb), srcAlpha); Mul src = tf.math.mul(srcRgb, alpha); Mul dst = tf.math.mul(dstRgb, tf.math.sub(tf.constant(1.0f), alpha)); Add out = tf.math.add(dst, src); - //Mul out = tf.math.mul(srcRgbNormalized, dstRgb); - //Squeeze squeeze = tf.withName("squeeze").squeeze(out, Squeeze.axis(Arrays.asList(0L))); + // Mul out = tf.math.mul(srcRgbNormalized, dstRgb); + // Squeeze squeeze = tf.withName("squeeze").squeeze(out, + // Squeeze.axis(Arrays.asList(0L))); return out; } /** - * The mask can contain label values larger than the list of colors provided in the color map. - * To avoid out-of-index errors we will "normalize" the label values in the mask to MOD max-color-table-value. + * The mask can contain label values larger than the list of colors provided in the + * color map. To avoid out-of-index errors we will "normalize" the label values in the + * mask to MOD max-color-table-value. * @param tf - tensorflow - * @param colorTable Color map of shape [n, 3]. n is the count of label entries and 3 is the RGB color assigned - * to that label. + * @param colorTable Color map of shape [n, 3]. n is the count of label entries and 3 + * is the RGB color assigned to that label. * @param mask Mask of shape [h, w] containing label vales. * @return Mask of shape [h, w] fromMemory values normalized between [0, n] */ public static Operand normalizeMaskLabels(Ops tf, Operand colorTable, Operand mask) { - // The mask can contain label values larger than the list of colors provided in the color map. - // To avoid out-of-index errors we will "normalize" the label values in the mask to MOD max-color-table-value. + // The mask can contain label values larger than the list of colors provided in + // the color map. + // To avoid out-of-index errors we will "normalize" the label values in the mask + // to MOD max-color-table-value. Sub colorTableShape = tf.math.sub(tf.shape(colorTable, Long.class), tf.constant(1L)); - // Color tables have shape [N, 3], where N is the count of label entries. Therefore the max label id is (N - 1). + // Color tables have shape [N, 3], where N is the count of label entries. + // Therefore the max label id is (N - 1). Gather colorTableSize = tf.gather(colorTableShape, tf.constant(new int[] { 0 }), tf.constant(0)); - // Normalize the label values in the mask so they don't exceed the max value in the color map. + // Normalize the label values in the mask so they don't exceed the max value in + // the color map. return tf.math.mod(mask, colorTableSize); } + } diff --git a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SegmentationColorMap.java b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SegmentationColorMap.java index 7c42e179..fd71a9e6 100644 --- a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SegmentationColorMap.java +++ b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SegmentationColorMap.java @@ -25,16 +25,17 @@ /** * - * Visualizes the segmentation results via specified color map. - * Color maps helping to visualize the semantic segmentation results for the different datasets. + * Visualizes the segmentation results via specified color map. Color maps helping to + * visualize the semantic segmentation results for the different datasets. * - * Supported colormaps are: - * - ADE20K (http://groups.csail.mit.edu/vision/datasets/ADE20K/). - * - Cityscapes dataset (https://www.cityscapes-dataset.com). - * - Mapillary Vistas (https://research.mapillary.com). - * - PASCAL VOC 2012 (http://host.robots.ox.ac.uk/pascal/VOC/). + * Supported colormaps are: - ADE20K + * (http://groups.csail.mit.edu/vision/datasets/ADE20K/). - Cityscapes dataset + * (https://www.cityscapes-dataset.com). - Mapillary Vistas + * (https://research.mapillary.com). - PASCAL VOC 2012 + * (http://host.robots.ox.ac.uk/pascal/VOC/). * - * Based on: https://github.com/tensorflow/models/blob/master/research/deeplab/utils/get_dataset_colormap.py + * Based on: + * https://github.com/tensorflow/models/blob/master/research/deeplab/utils/get_dataset_colormap.py * * @author Christian Tzolov */ @@ -45,238 +46,51 @@ private SegmentationColorMap() { } /** MAPILLARY_COLORMAP . */ - public static final int[][] MAPILLARY_COLORMAP = new int[][] { - { 165, 42, 42 }, - { 0, 192, 0 }, - { 196, 196, 196 }, - { 190, 153, 153 }, - { 180, 165, 180 }, - { 102, 102, 156 }, - { 102, 102, 156 }, - { 128, 64, 255 }, - { 140, 140, 200 }, - { 170, 170, 170 }, - { 250, 170, 160 }, - { 96, 96, 96 }, - { 230, 150, 140 }, - { 128, 64, 128 }, - { 110, 110, 110 }, - { 244, 35, 232 }, - { 150, 100, 100 }, - { 70, 70, 70 }, - { 150, 120, 90 }, - { 220, 20, 60 }, - { 255, 0, 0 }, - { 255, 0, 0 }, - { 255, 0, 0 }, - { 200, 128, 128 }, - { 255, 255, 255 }, - { 64, 170, 64 }, - { 128, 64, 64 }, - { 70, 130, 180 }, - { 255, 255, 255 }, - { 152, 251, 152 }, - { 107, 142, 35 }, - { 0, 170, 30 }, - { 255, 255, 128 }, - { 250, 0, 30 }, - { 0, 0, 0 }, - { 220, 220, 220 }, - { 170, 170, 170 }, - { 222, 40, 40 }, - { 100, 170, 30 }, - { 40, 40, 40 }, - { 33, 33, 33 }, - { 170, 170, 170 }, - { 0, 0, 142 }, - { 170, 170, 170 }, - { 210, 170, 100 }, - { 153, 153, 153 }, - { 128, 128, 128 }, - { 0, 0, 142 }, - { 250, 170, 30 }, - { 192, 192, 192 }, - { 220, 220, 0 }, - { 180, 165, 180 }, - { 119, 11, 32 }, - { 0, 0, 142 }, - { 0, 60, 100 }, - { 0, 0, 142 }, - { 0, 0, 90 }, - { 0, 0, 230 }, - { 0, 80, 100 }, - { 128, 64, 64 }, - { 0, 0, 110 }, - { 0, 0, 70 }, - { 0, 0, 192 }, - { 32, 32, 32 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }; + public static final int[][] MAPILLARY_COLORMAP = new int[][] { { 165, 42, 42 }, { 0, 192, 0 }, { 196, 196, 196 }, + { 190, 153, 153 }, { 180, 165, 180 }, { 102, 102, 156 }, { 102, 102, 156 }, { 128, 64, 255 }, + { 140, 140, 200 }, { 170, 170, 170 }, { 250, 170, 160 }, { 96, 96, 96 }, { 230, 150, 140 }, + { 128, 64, 128 }, { 110, 110, 110 }, { 244, 35, 232 }, { 150, 100, 100 }, { 70, 70, 70 }, { 150, 120, 90 }, + { 220, 20, 60 }, { 255, 0, 0 }, { 255, 0, 0 }, { 255, 0, 0 }, { 200, 128, 128 }, { 255, 255, 255 }, + { 64, 170, 64 }, { 128, 64, 64 }, { 70, 130, 180 }, { 255, 255, 255 }, { 152, 251, 152 }, { 107, 142, 35 }, + { 0, 170, 30 }, { 255, 255, 128 }, { 250, 0, 30 }, { 0, 0, 0 }, { 220, 220, 220 }, { 170, 170, 170 }, + { 222, 40, 40 }, { 100, 170, 30 }, { 40, 40, 40 }, { 33, 33, 33 }, { 170, 170, 170 }, { 0, 0, 142 }, + { 170, 170, 170 }, { 210, 170, 100 }, { 153, 153, 153 }, { 128, 128, 128 }, { 0, 0, 142 }, { 250, 170, 30 }, + { 192, 192, 192 }, { 220, 220, 0 }, { 180, 165, 180 }, { 119, 11, 32 }, { 0, 0, 142 }, { 0, 60, 100 }, + { 0, 0, 142 }, { 0, 0, 90 }, { 0, 0, 230 }, { 0, 80, 100 }, { 128, 64, 64 }, { 0, 0, 110 }, { 0, 0, 70 }, + { 0, 0, 192 }, { 32, 32, 32 }, { 0, 0, 0 }, { 0, 0, 0 }, }; /** * Label colormap used in ADE20K segmentation benchmark. */ - public static final int[][] ADE20K_COLORMAP = new int[][] { - { 0, 0, 0 }, - { 120, 120, 120 }, - { 180, 120, 120 }, - { 6, 230, 230 }, - { 80, 50, 50 }, - { 4, 200, 3 }, - { 120, 120, 80 }, - { 140, 140, 140 }, - { 204, 5, 255 }, - { 230, 230, 230 }, - { 4, 250, 7 }, - { 224, 5, 255 }, - { 235, 255, 7 }, - { 150, 5, 61 }, - { 120, 120, 70 }, - { 8, 255, 51 }, - { 255, 6, 82 }, - { 143, 255, 140 }, - { 204, 255, 4 }, - { 255, 51, 7 }, - { 204, 70, 3 }, - { 0, 102, 200 }, - { 61, 230, 250 }, - { 255, 6, 51 }, - { 11, 102, 255 }, - { 255, 7, 71 }, - { 255, 9, 224 }, - { 9, 7, 230 }, - { 220, 220, 220 }, - { 255, 9, 92 }, - { 112, 9, 255 }, - { 8, 255, 214 }, - { 7, 255, 224 }, - { 255, 184, 6 }, - { 10, 255, 71 }, - { 255, 41, 10 }, - { 7, 255, 255 }, - { 224, 255, 8 }, - { 102, 8, 255 }, - { 255, 61, 6 }, - { 255, 194, 7 }, - { 255, 122, 8 }, - { 0, 255, 20 }, - { 255, 8, 41 }, - { 255, 5, 153 }, - { 6, 51, 255 }, - { 235, 12, 255 }, - { 160, 150, 20 }, - { 0, 163, 255 }, - { 140, 140, 140 }, - { 250, 10, 15 }, - { 20, 255, 0 }, - { 31, 255, 0 }, - { 255, 31, 0 }, - { 255, 224, 0 }, - { 153, 255, 0 }, - { 0, 0, 255 }, - { 255, 71, 0 }, - { 0, 235, 255 }, - { 0, 173, 255 }, - { 31, 0, 255 }, - { 11, 200, 200 }, - { 255, 82, 0 }, - { 0, 255, 245 }, - { 0, 61, 255 }, - { 0, 255, 112 }, - { 0, 255, 133 }, - { 255, 0, 0 }, - { 255, 163, 0 }, - { 255, 102, 0 }, - { 194, 255, 0 }, - { 0, 143, 255 }, - { 51, 255, 0 }, - { 0, 82, 255 }, - { 0, 255, 41 }, - { 0, 255, 173 }, - { 10, 0, 255 }, - { 173, 255, 0 }, - { 0, 255, 153 }, - { 255, 92, 0 }, - { 255, 0, 255 }, - { 255, 0, 245 }, - { 255, 0, 102 }, - { 255, 173, 0 }, - { 255, 0, 20 }, - { 255, 184, 184 }, - { 0, 31, 255 }, - { 0, 255, 61 }, - { 0, 71, 255 }, - { 255, 0, 204 }, - { 0, 255, 194 }, - { 0, 255, 82 }, - { 0, 10, 255 }, - { 0, 112, 255 }, - { 51, 0, 255 }, - { 0, 194, 255 }, - { 0, 122, 255 }, - { 0, 255, 163 }, - { 255, 153, 0 }, - { 0, 255, 10 }, - { 255, 112, 0 }, - { 143, 255, 0 }, - { 82, 0, 255 }, - { 163, 255, 0 }, - { 255, 235, 0 }, - { 8, 184, 170 }, - { 133, 0, 255 }, - { 0, 255, 92 }, - { 184, 0, 255 }, - { 255, 0, 31 }, - { 0, 184, 255 }, - { 0, 214, 255 }, - { 255, 0, 112 }, - { 92, 255, 0 }, - { 0, 224, 255 }, - { 112, 224, 255 }, - { 70, 184, 160 }, - { 163, 0, 255 }, - { 153, 0, 255 }, - { 71, 255, 0 }, - { 255, 0, 163 }, - { 255, 204, 0 }, - { 255, 0, 143 }, - { 0, 255, 235 }, - { 133, 255, 0 }, - { 255, 0, 235 }, - { 245, 0, 255 }, - { 255, 0, 122 }, - { 255, 245, 0 }, - { 10, 190, 212 }, - { 214, 255, 0 }, - { 0, 204, 255 }, - { 20, 0, 255 }, - { 255, 255, 0 }, - { 0, 153, 255 }, - { 0, 41, 255 }, - { 0, 255, 204 }, - { 41, 0, 255 }, - { 41, 255, 0 }, - { 173, 0, 255 }, - { 0, 245, 255 }, - { 71, 0, 255 }, - { 122, 0, 255 }, - { 0, 255, 184 }, - { 0, 92, 255 }, - { 184, 255, 0 }, - { 0, 133, 255 }, - { 255, 214, 0 }, - { 25, 194, 194 }, - { 102, 255, 0 }, - { 92, 0, 255 }, - }; + public static final int[][] ADE20K_COLORMAP = new int[][] { { 0, 0, 0 }, { 120, 120, 120 }, { 180, 120, 120 }, + { 6, 230, 230 }, { 80, 50, 50 }, { 4, 200, 3 }, { 120, 120, 80 }, { 140, 140, 140 }, { 204, 5, 255 }, + { 230, 230, 230 }, { 4, 250, 7 }, { 224, 5, 255 }, { 235, 255, 7 }, { 150, 5, 61 }, { 120, 120, 70 }, + { 8, 255, 51 }, { 255, 6, 82 }, { 143, 255, 140 }, { 204, 255, 4 }, { 255, 51, 7 }, { 204, 70, 3 }, + { 0, 102, 200 }, { 61, 230, 250 }, { 255, 6, 51 }, { 11, 102, 255 }, { 255, 7, 71 }, { 255, 9, 224 }, + { 9, 7, 230 }, { 220, 220, 220 }, { 255, 9, 92 }, { 112, 9, 255 }, { 8, 255, 214 }, { 7, 255, 224 }, + { 255, 184, 6 }, { 10, 255, 71 }, { 255, 41, 10 }, { 7, 255, 255 }, { 224, 255, 8 }, { 102, 8, 255 }, + { 255, 61, 6 }, { 255, 194, 7 }, { 255, 122, 8 }, { 0, 255, 20 }, { 255, 8, 41 }, { 255, 5, 153 }, + { 6, 51, 255 }, { 235, 12, 255 }, { 160, 150, 20 }, { 0, 163, 255 }, { 140, 140, 140 }, { 250, 10, 15 }, + { 20, 255, 0 }, { 31, 255, 0 }, { 255, 31, 0 }, { 255, 224, 0 }, { 153, 255, 0 }, { 0, 0, 255 }, + { 255, 71, 0 }, { 0, 235, 255 }, { 0, 173, 255 }, { 31, 0, 255 }, { 11, 200, 200 }, { 255, 82, 0 }, + { 0, 255, 245 }, { 0, 61, 255 }, { 0, 255, 112 }, { 0, 255, 133 }, { 255, 0, 0 }, { 255, 163, 0 }, + { 255, 102, 0 }, { 194, 255, 0 }, { 0, 143, 255 }, { 51, 255, 0 }, { 0, 82, 255 }, { 0, 255, 41 }, + { 0, 255, 173 }, { 10, 0, 255 }, { 173, 255, 0 }, { 0, 255, 153 }, { 255, 92, 0 }, { 255, 0, 255 }, + { 255, 0, 245 }, { 255, 0, 102 }, { 255, 173, 0 }, { 255, 0, 20 }, { 255, 184, 184 }, { 0, 31, 255 }, + { 0, 255, 61 }, { 0, 71, 255 }, { 255, 0, 204 }, { 0, 255, 194 }, { 0, 255, 82 }, { 0, 10, 255 }, + { 0, 112, 255 }, { 51, 0, 255 }, { 0, 194, 255 }, { 0, 122, 255 }, { 0, 255, 163 }, { 255, 153, 0 }, + { 0, 255, 10 }, { 255, 112, 0 }, { 143, 255, 0 }, { 82, 0, 255 }, { 163, 255, 0 }, { 255, 235, 0 }, + { 8, 184, 170 }, { 133, 0, 255 }, { 0, 255, 92 }, { 184, 0, 255 }, { 255, 0, 31 }, { 0, 184, 255 }, + { 0, 214, 255 }, { 255, 0, 112 }, { 92, 255, 0 }, { 0, 224, 255 }, { 112, 224, 255 }, { 70, 184, 160 }, + { 163, 0, 255 }, { 153, 0, 255 }, { 71, 255, 0 }, { 255, 0, 163 }, { 255, 204, 0 }, { 255, 0, 143 }, + { 0, 255, 235 }, { 133, 255, 0 }, { 255, 0, 235 }, { 245, 0, 255 }, { 255, 0, 122 }, { 255, 245, 0 }, + { 10, 190, 212 }, { 214, 255, 0 }, { 0, 204, 255 }, { 20, 0, 255 }, { 255, 255, 0 }, { 0, 153, 255 }, + { 0, 41, 255 }, { 0, 255, 204 }, { 41, 0, 255 }, { 41, 255, 0 }, { 173, 0, 255 }, { 0, 245, 255 }, + { 71, 0, 255 }, { 122, 0, 255 }, { 0, 255, 184 }, { 0, 92, 255 }, { 184, 255, 0 }, { 0, 133, 255 }, + { 255, 214, 0 }, { 25, 194, 194 }, { 102, 255, 0 }, { 92, 0, 255 }, }; /** BLACK_WHITE_COLORMAP . */ - public static int[][] BLACK_WHITE_COLORMAP = new int[][] { - { 0, 0, 0 }, - { 127, 127, 127 }, - { 255, 255, 255 }, - }; + public static int[][] BLACK_WHITE_COLORMAP = new int[][] { { 0, 0, 0 }, { 127, 127, 127 }, { 255, 255, 255 }, }; /** CITYMAP_COLORMAP . */ public static final int[][] CITYMAP_COLORMAP = new int[255][3]; @@ -284,27 +98,10 @@ private SegmentationColorMap() { static { // Initialize citymap - int[][] _CITYMAP_COLORMAP = new int[][] { - { 128, 64, 128 }, - { 244, 35, 232 }, - { 70, 70, 70 }, - { 102, 102, 156 }, - { 190, 153, 153 }, - { 153, 153, 153 }, - { 250, 170, 30 }, - { 220, 220, 0 }, - { 107, 142, 35 }, - { 152, 251, 152 }, - { 70, 130, 180 }, - { 220, 20, 60 }, - { 255, 0, 0 }, - { 0, 0, 142 }, - { 0, 0, 70 }, - { 0, 60, 100 }, - { 0, 80, 100 }, - { 0, 0, 230 }, - { 119, 11, 32 } - }; + int[][] _CITYMAP_COLORMAP = new int[][] { { 128, 64, 128 }, { 244, 35, 232 }, { 70, 70, 70 }, { 102, 102, 156 }, + { 190, 153, 153 }, { 153, 153, 153 }, { 250, 170, 30 }, { 220, 220, 0 }, { 107, 142, 35 }, + { 152, 251, 152 }, { 70, 130, 180 }, { 220, 20, 60 }, { 255, 0, 0 }, { 0, 0, 142 }, { 0, 0, 70 }, + { 0, 60, 100 }, { 0, 80, 100 }, { 0, 0, 230 }, { 119, 11, 32 } }; for (int i = 0; i < _CITYMAP_COLORMAP.length; i++) { System.arraycopy(_CITYMAP_COLORMAP[i], 0, CITYMAP_COLORMAP[i], 0, _CITYMAP_COLORMAP[i].length); @@ -323,8 +120,11 @@ public static int[][] loadColorMap(String resourceUri) { } public static class ColorMap { + private String name; + private String info; + private int[][] colormap; public String getName() { @@ -353,11 +153,10 @@ public void setColormap(int[][] colormap) { @Override public String toString() { - return "ColorMap{" + - "name='" + name + '\'' + - "info='" + info + '\'' + - ", colormap=" + Arrays.deepToString(colormap) + - '}'; + return "ColorMap{" + "name='" + name + '\'' + "info='" + info + '\'' + ", colormap=" + + Arrays.deepToString(colormap) + '}'; } + } + } diff --git a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SemanticSegmentation.java b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SemanticSegmentation.java index 35171889..7bb8c018 100644 --- a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SemanticSegmentation.java +++ b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/SemanticSegmentation.java @@ -54,12 +54,19 @@ public class SemanticSegmentation implements AutoCloseable { private static final long CHANNELS = 3; + private static final float REQUIRED_INPUT_IMAGE_SIZE = 513f; + private final GraphRunner imageNormalization; + private final GraphRunner semanticSegmentation; + private final GraphRunner maskImageEncoding; + private final GraphRunner alphaBlending; + private final Tensor colorMapTensor; + private final Tensor maskTransparencyTensor; @Override @@ -75,95 +82,134 @@ public void close() { public SemanticSegmentation(String modelUrl, int[][] colorMap, long[] labelFilter, float maskTransparency) { - this.imageNormalization = new GraphRunner("input_image", "resized_image") - .withGraphDefinition(tf -> { - Placeholder input = tf.withName("input_image").placeholder(String.class); - ExtractJpegShape imageShapeAndChannel = tf.image.extractJpegShape(input); - Gather imageShape = tf.gather(imageShapeAndChannel, tf.constant(new int[] { 0, 1 }), tf.constant(0)); + this.imageNormalization = new GraphRunner("input_image", "resized_image").withGraphDefinition(tf -> { + Placeholder input = tf.withName("input_image").placeholder(String.class); + ExtractJpegShape imageShapeAndChannel = tf.image.extractJpegShape(input); + Gather imageShape = tf.gather(imageShapeAndChannel, tf.constant(new int[] { 0, 1 }), + tf.constant(0)); - Cast maxSize = tf.dtypes.cast(tf.max(imageShape, tf.constant(0)), Float.class); - Div scale = tf.math.div(tf.constant(REQUIRED_INPUT_IMAGE_SIZE), maxSize); - Cast newSize = tf.dtypes.cast(tf.math.mul(scale, tf.dtypes.cast(imageShape, Float.class)), Integer.class); + Cast maxSize = tf.dtypes.cast(tf.max(imageShape, tf.constant(0)), Float.class); + Div scale = tf.math.div(tf.constant(REQUIRED_INPUT_IMAGE_SIZE), maxSize); + Cast newSize = tf.dtypes.cast(tf.math.mul(scale, tf.dtypes.cast(imageShape, Float.class)), + Integer.class); - final Operand decodedImage = - tf.dtypes.cast(tf.image.decodeJpeg(input, DecodeJpeg.channels(CHANNELS)), Float.class); + final Operand decodedImage = tf.dtypes + .cast(tf.image.decodeJpeg(input, DecodeJpeg.channels(CHANNELS)), Float.class); - final Operand resizedImageFloat = - tf.image.resizeBilinear(tf.expandDims(decodedImage, tf.constant(0)), newSize); + final Operand resizedImageFloat = tf.image + .resizeBilinear(tf.expandDims(decodedImage, tf.constant(0)), newSize); - tf.withName("resized_image").dtypes.cast(resizedImageFloat, UInt8.class); - }); + tf.withName("resized_image").dtypes.cast(resizedImageFloat, UInt8.class); + }); this.semanticSegmentation = new GraphRunner("ImageTensor:0", "SemanticPredictions:0") - .withGraphDefinition(new ProtoBufGraphDefinition(new DefaultResourceLoader().getResource(modelUrl), true)); + .withGraphDefinition(new ProtoBufGraphDefinition(new DefaultResourceLoader().getResource(modelUrl), true)); this.colorMapTensor = Tensor.create(colorMap).expect(Integer.class); - this.maskImageEncoding = new GraphRunner(Arrays.asList("color_map", "mask_pixels"), Arrays.asList("mask_png", "mask_rgb")) - .withGraphDefinition(tf -> { - Placeholder colorTable = tf.withName("color_map").placeholder(Integer.class); + this.maskImageEncoding = new GraphRunner(Arrays.asList("color_map", "mask_pixels"), + Arrays.asList("mask_png", "mask_rgb")) + .withGraphDefinition(tf -> { + Placeholder colorTable = tf.withName("color_map").placeholder(Integer.class); - Placeholder batchedMask = tf.withName("mask_pixels").placeholder(Long.class); - // Remove batch dimension - Squeeze mask = tf.squeeze(batchedMask, Squeeze.axis(Arrays.asList(0L))); + Placeholder batchedMask = tf.withName("mask_pixels").placeholder(Long.class); + // Remove batch dimension + Squeeze mask = tf.squeeze(batchedMask, Squeeze.axis(Arrays.asList(0L))); - Operand filteredMask = labelFilter(tf, mask, labelFilter); + Operand filteredMask = labelFilter(tf, mask, labelFilter); - // The mask can contain label values larger than the list of colors provided in the color map. - // To avoid out-of-index errors we will "normalize" the label values in the mask to MOD max-color-table-value. - Operand mask3 = NativeImageUtils.normalizeMaskLabels(tf, colorTable, filteredMask); + // The mask can contain label values larger than the list of colors + // provided in the color map. + // To avoid out-of-index errors we will "normalize" the label values in + // the mask to MOD max-color-table-value. + Operand mask3 = NativeImageUtils.normalizeMaskLabels(tf, colorTable, filteredMask); - Gather maskRgb = tf.withName("mask_rgb").gather(colorTable, mask3, tf.constant(0)); + Gather maskRgb = tf.withName("mask_rgb").gather(colorTable, mask3, tf.constant(0)); - Operand png = tf.withName("mask_png").image.encodePng(tf.dtypes.cast(maskRgb, UInt8.class)); + Operand png = tf.withName("mask_png").image.encodePng(tf.dtypes.cast(maskRgb, UInt8.class)); - }); + }); this.maskTransparencyTensor = Tensor.create(maskTransparency).expect(Float.class); - this.alphaBlending = new GraphRunner( - Arrays.asList("input_image", "mask_image", "mask_transparency"), Arrays.asList("blended_png")) - .withGraphDefinition(tf -> { - // Input image [B, H, W, 3] - Cast inputImageRgb = tf.dtypes.cast(tf.withName("input_image").placeholder(UInt8.class), Float.class); + this.alphaBlending = new GraphRunner(Arrays.asList("input_image", "mask_image", "mask_transparency"), + Arrays.asList("blended_png")) + .withGraphDefinition(tf -> { + // Input image [B, H, W, 3] + Cast inputImageRgb = tf.dtypes.cast(tf.withName("input_image").placeholder(UInt8.class), + Float.class); - Placeholder a = tf.withName("mask_image").placeholder(Integer.class); - Cast maskRgb = tf.dtypes.cast(a, Float.class); + Placeholder a = tf.withName("mask_image").placeholder(Integer.class); + Cast maskRgb = tf.dtypes.cast(a, Float.class); - Squeeze inputImageRgb2 = tf.squeeze(inputImageRgb, Squeeze.axis(Arrays.asList(0L))); + Squeeze inputImageRgb2 = tf.squeeze(inputImageRgb, Squeeze.axis(Arrays.asList(0L))); - Placeholder maskTransparencyHolder = tf.withName("mask_transparency").placeholder(Float.class); + Placeholder maskTransparencyHolder = tf.withName("mask_transparency").placeholder(Float.class); - // Blend the transparent maskImage on top of the input image. - Operand blended = NativeImageUtils.alphaBlending(tf, maskRgb, inputImageRgb2, maskTransparencyHolder); + // Blend the transparent maskImage on top of the input image. + Operand blended = NativeImageUtils.alphaBlending(tf, maskRgb, inputImageRgb2, + maskTransparencyHolder); - // Cut - //Operand condition = tf.math.equal(a, tf.zerosLike(a)); - //Operand blended = tf.where3(condition, tf.zerosLike(maskRgb), inputImageRgb2); + // Cut + // Operand condition = tf.math.equal(a, tf.zerosLike(a)); + // Operand blended = tf.where3(condition, tf.zerosLike(maskRgb), + // inputImageRgb2); - // Encode PNG - tf.withName("blended_png").image.encodePng(tf.dtypes.cast(blended, UInt8.class)); + // Encode PNG + tf.withName("blended_png").image.encodePng(tf.dtypes.cast(blended, UInt8.class)); - }); + }); } public byte[] blendMask(byte[] image) { try (Tensor inputTensor = Tensor.create(image); GraphRunnerMemory memory = new GraphRunnerMemory()) { - Map> blendedTensors = - this.imageNormalization.andThen(memory) // (input_image) -> (resized_image) and memorize (resized_image) - .andThen(this.semanticSegmentation).andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and memorize (SemanticPredictions:0) - .andThen(Functions.rename("SemanticPredictions:0", "mask_pixels")) // (SemanticPredictions:0) -> (mask_pixels) - .andThen(Functions.enrichWith("color_map", this.colorMapTensor)) // (mask_pixels) -> (mask_pixels, color_map) - .andThen(this.maskImageEncoding).andThen(memory) // (color_map, mask_pixels) -> (mask_png, mask_rgb) and memorize (mask_png, mask_rgb) - .andThen(Functions.enrichFromMemory( - memory, "resized_image")) // (mask_png, mask_rgb) -> (mask_png, mask_rgb, resized_image), e.g. join the normalizedImageTensor - .andThen(Functions.rename( - "resized_image", "input_image", - "mask_rgb", "mask_image")) // (mask_png, mask_rgb, resized_image) -> (mask_image, input_image) - .andThen(Functions.enrichWith("mask_transparency", this.maskTransparencyTensor)) // (mask_image, input_image) -> (mask_image, input_image, mask_transparency) - .andThen(this.alphaBlending).andThen(memory) // (mask_image, input_image, mask_transparency) -> (blended_png) - .apply(Collections.singletonMap("input_image", inputTensor)); // () -> (input_image) + Map> blendedTensors = this.imageNormalization.andThen(memory) // (input_image) + // -> + // (resized_image) + // and + // memorize + // (resized_image) + .andThen(this.semanticSegmentation) + .andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and + // memorize (SemanticPredictions:0) + .andThen(Functions.rename("SemanticPredictions:0", "mask_pixels")) // (SemanticPredictions:0) + // -> + // (mask_pixels) + .andThen(Functions.enrichWith("color_map", this.colorMapTensor)) // (mask_pixels) + // -> + // (mask_pixels, + // color_map) + .andThen(this.maskImageEncoding) + .andThen(memory) // (color_map, mask_pixels) -> (mask_png, mask_rgb) and + // memorize (mask_png, mask_rgb) + .andThen(Functions.enrichFromMemory(memory, "resized_image")) // (mask_png, + // mask_rgb) + // -> + // (mask_png, + // mask_rgb, + // resized_image), + // e.g. + // join + // the + // normalizedImageTensor + .andThen(Functions.rename("resized_image", "input_image", "mask_rgb", "mask_image")) // (mask_png, + // mask_rgb, + // resized_image) + // -> + // (mask_image, + // input_image) + .andThen(Functions.enrichWith("mask_transparency", this.maskTransparencyTensor)) // (mask_image, + // input_image) + // -> + // (mask_image, + // input_image, + // mask_transparency) + .andThen(this.alphaBlending) + .andThen(memory) // (mask_image, input_image, mask_transparency) -> + // (blended_png) + .apply(Collections.singletonMap("input_image", inputTensor)); // () -> + // (input_image) byte[] blendedImage = blendedTensors.get("blended_png").bytesValue(); @@ -176,15 +222,21 @@ public byte[] blendMask(byte[] image) { public long[][] maskPixels(byte[] image) { try (Tensor inputTensor = Tensor.create(image); GraphRunnerMemory memory = new GraphRunnerMemory()) { - return this.imageNormalization.andThen(memory) // (input_image) -> (resized_image) and memorize (resized_image) - .andThen(this.semanticSegmentation).andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and memorize (SemanticPredictions:0) - .andThen(tensorMap -> { - Tensor maskTensor = tensorMap.get("SemanticPredictions:0"); - int width = (int) maskTensor.shape()[1]; - int height = (int) maskTensor.shape()[2]; - return maskTensor.copyTo(new long[1][width][height])[0]; // 1 == batch size - }) - .apply(Collections.singletonMap("input_image", inputTensor)); // () -> (input_image) + return this.imageNormalization.andThen(memory) // (input_image) -> + // (resized_image) and + // memorize (resized_image) + .andThen(this.semanticSegmentation) + .andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and + // memorize (SemanticPredictions:0) + .andThen(tensorMap -> { + Tensor maskTensor = tensorMap.get("SemanticPredictions:0"); + int width = (int) maskTensor.shape()[1]; + int height = (int) maskTensor.shape()[2]; + return maskTensor.copyTo(new long[1][width][height])[0]; // 1 == batch + // size + }) + .apply(Collections.singletonMap("input_image", inputTensor)); // () -> + // (input_image) } } @@ -192,13 +244,25 @@ public byte[] maskImage(byte[] image) { try (Tensor inputTensor = Tensor.create(image); GraphRunnerMemory memory = new GraphRunnerMemory()) { - return this.imageNormalization.andThen(memory) // (input_image) -> (resized_image) and memorize (resized_image) - .andThen(this.semanticSegmentation).andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and memorize (SemanticPredictions:0) - .andThen(Functions.rename("SemanticPredictions:0", "mask_pixels")) // (SemanticPredictions:0) -> (mask_pixels) - .andThen(Functions.enrichWith("color_map", this.colorMapTensor)) // (mask_pixels) -> (mask_pixels, color_map) - .andThen(this.maskImageEncoding).andThen(memory) // (color_map, mask_pixels) -> (mask_png, mask_rgb) and memorize (mask_png, mask_rgb) - .andThen(tensorMap -> tensorMap.get("mask_png").bytesValue()) - .apply(Collections.singletonMap("input_image", inputTensor)); // () -> (input_image) + return this.imageNormalization.andThen(memory) // (input_image) -> + // (resized_image) and + // memorize (resized_image) + .andThen(this.semanticSegmentation) + .andThen(memory) // (ImageTensor:0) -> (SemanticPredictions:0) and + // memorize (SemanticPredictions:0) + .andThen(Functions.rename("SemanticPredictions:0", "mask_pixels")) // (SemanticPredictions:0) + // -> + // (mask_pixels) + .andThen(Functions.enrichWith("color_map", this.colorMapTensor)) // (mask_pixels) + // -> + // (mask_pixels, + // color_map) + .andThen(this.maskImageEncoding) + .andThen(memory) // (color_map, mask_pixels) -> (mask_png, mask_rgb) and + // memorize (mask_png, mask_rgb) + .andThen(tensorMap -> tensorMap.get("mask_png").bytesValue()) + .apply(Collections.singletonMap("input_image", inputTensor)); // () -> + // (input_image) } } @@ -222,8 +286,7 @@ public static void main(String[] args) throws IOException { try (SemanticSegmentation segmentationService = new SemanticSegmentation( "https://download.tensorflow.org/models/deeplabv3_mnv2_cityscapes_train_2018_02_05.tar.gz#frozen_inference_graph.pb", - SegmentationColorMap.loadColorMap("classpath:/colormap/citymap_colormap.json"), null, 0.45f) - ) { + SegmentationColorMap.loadColorMap("classpath:/colormap/citymap_colormap.json"), null, 0.45f)) { byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/amsterdam-cityscape1.jpg"); // 1. Mask pixels @@ -244,8 +307,7 @@ public static void main(String[] args) throws IOException { try (SemanticSegmentation segmentationService = new SemanticSegmentation( "https://download.tensorflow.org/models/deeplabv3_xception_ade20k_train_2018_05_29.tar.gz#frozen_inference_graph.pb", - SegmentationColorMap.loadColorMap("classpath:/colormap/ade20k_colormap.json"), null, 0.45f) - ) { + SegmentationColorMap.loadColorMap("classpath:/colormap/ade20k_colormap.json"), null, 0.45f)) { byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/interior.jpg"); // 1. Mask pixels @@ -264,8 +326,7 @@ public static void main(String[] args) throws IOException { try (SemanticSegmentation segmentationService = new SemanticSegmentation( "https://download.tensorflow.org/models/deeplabv3_mnv2_pascal_trainval_2018_01_29.tar.gz#frozen_inference_graph.pb", - SegmentationColorMap.loadColorMap("classpath:/colormap/black_white_colormap.json"), null, 0.45f) - ) { + SegmentationColorMap.loadColorMap("classpath:/colormap/black_white_colormap.json"), null, 0.45f)) { byte[] inputImage = GraphicsUtils.loadAsByteArray("classpath:/images/VikiMaxiAdi.jpg"); // 1. Mask pixels @@ -283,4 +344,5 @@ public static void main(String[] args) throws IOException { } } + } diff --git a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/attic/SemanticSegmentationUtils.java b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/attic/SemanticSegmentationUtils.java index 9f0f223f..bf2f2e92 100644 --- a/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/attic/SemanticSegmentationUtils.java +++ b/function/spring-semantic-segmentation-function/src/main/java/org/springframework/cloud/fn/semantic/segmentation/attic/SemanticSegmentationUtils.java @@ -44,8 +44,8 @@ /** * - * Semantic image segmentation - the task of assigning a semantic label, such as "road", "sky", "person", "dog", to - * every pixel in an image. + * Semantic image segmentation - the task of assigning a semantic label, such as "road", + * "sky", "person", "dog", to every pixel in an image. * * https://ai.googleblog.com/2018/03/semantic-image-segmentation-with.html * https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/model_zoo.md @@ -65,11 +65,14 @@ public class SemanticSegmentationUtils { /** INPUT_TENSOR_NAME . */ public static final String INPUT_TENSOR_NAME = "ImageTensor:0"; + /** OUTPUT_TENSOR_NAME . */ public static final String OUTPUT_TENSOR_NAME = "SemanticPredictions:0"; private static final int BATCH_SIZE = 1; + private static final long CHANNELS = 3; + private static final int REQUIRED_INPUT_IMAGE_SIZE = 513; public static BufferedImage scaledImage(String imagePath) { @@ -100,9 +103,11 @@ private static BufferedImage scale(BufferedImage originalImage, double scale) { int newHeight = (int) (originalImage.getHeight() * scale); Image tmpImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT); - //BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, TYPE_INT_BGR); + // BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, + // TYPE_INT_BGR); BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, TYPE_3BYTE_BGR); - //BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, originalImage.getType()); + // BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, + // originalImage.getType()); Graphics2D g2d = resizedImage.createGraphics(); g2d.drawImage(tmpImage, 0, 0, null); @@ -125,7 +130,8 @@ public static Tensor createInputTensor(BufferedImage scaledImage) { // ImageIO.read produces BGR-encoded images, while the model expects RGB. byte[] data = bgrToRgb(toBytes(scaledImage)); - // Expand dimensions since the model expects images to have shape: [1, None, None, 3] + // Expand dimensions since the model expects images to have shape: [1, None, None, + // 3] long[] shape = new long[] { BATCH_SIZE, scaledImage.getHeight(), scaledImage.getWidth(), CHANNELS }; return Tensor.create(UInt8.class, shape, ByteBuffer.wrap(data)); @@ -201,7 +207,8 @@ public static int[][] toIntArray(long[][] longArray) { public String serializeToJson(int[][] pixels) { String masksBase64 = Base64.getEncoder().encodeToString(toBytes(pixels)); - return String.format("{ \"columns\":%d, \"rows\":%d, \"masks\":\"%s\"}", pixels.length, pixels[0].length, masksBase64); + return String.format("{ \"columns\":%d, \"rows\":%d, \"masks\":\"%s\"}", pixels.length, pixels[0].length, + masksBase64); } public int[][] deserializeToMasks(String json) throws IOException { @@ -221,7 +228,7 @@ private byte[] toBytes(int[][] pixels) { b[bi + 0] = (byte) (i >> 24); b[bi + 1] = (byte) (i >> 16); b[bi + 2] = (byte) (i >> 8); - b[bi + 3] = (byte) (i /*>> 0*/); + b[bi + 3] = (byte) (i /* >> 0 */); bi = bi + 4; } } @@ -233,10 +240,7 @@ private int[][] toInts(byte[] b, int ic, int jc) { int bi = 0; for (int i = 0; i < ic; i++) { for (int j = 0; j < jc; j++) { - intResult[i][j] = (b[bi] << 24) + - (b[bi + 1] << 16) + - (b[bi + 2] << 8) + - b[bi + 3]; + intResult[i][j] = (b[bi] << 24) + (b[bi + 1] << 16) + (b[bi + 2] << 8) + b[bi + 3]; bi = bi + 4; } } @@ -246,14 +250,16 @@ private int[][] toInts(byte[] b, int ic, int jc) { public static void main(String[] args) throws IOException { // PASCAL VOC 2012 - //String tensorflowModelLocation = "file:/Users/ctzolov/Downloads/deeplabv3_mnv2_pascal_train_aug/frozen_inference_graph.pb"; - //String imagePath = "classpath:/images/VikiMaxiAdi.jpg"; + // String tensorflowModelLocation = + // "file:/Users/ctzolov/Downloads/deeplabv3_mnv2_pascal_train_aug/frozen_inference_graph.pb"; + // String imagePath = "classpath:/images/VikiMaxiAdi.jpg"; // CITYSCAPE - //String tensorflowModelLocation = "file:/Users/ctzolov/Downloads/deeplabv3_mnv2_cityscapes_train/frozen_inference_graph.pb"; - //String imagePath = "classpath:/images/amsterdam-cityscape1.jpg"; - //String imagePath = "classpath:/images/amsterdam-channel.jpg"; - //String imagePath = "classpath:/images/landsmeer.png"; + // String tensorflowModelLocation = + // "file:/Users/ctzolov/Downloads/deeplabv3_mnv2_cityscapes_train/frozen_inference_graph.pb"; + // String imagePath = "classpath:/images/amsterdam-cityscape1.jpg"; + // String imagePath = "classpath:/images/amsterdam-channel.jpg"; + // String imagePath = "classpath:/images/landsmeer.png"; // ADE20K String tensorflowModelLocation = "file:/Users/ctzolov/Downloads/deeplabv3_xception_ade20k_train/frozen_inference_graph.pb"; @@ -261,7 +267,8 @@ public static void main(String[] args) throws IOException { BufferedImage inputImage = ImageIO.read(new DefaultResourceLoader().getResource(imagePath).getInputStream()); - TensorFlowService tf = new TensorFlowService(new DefaultResourceLoader().getResource(tensorflowModelLocation), Arrays.asList(OUTPUT_TENSOR_NAME)); + TensorFlowService tf = new TensorFlowService(new DefaultResourceLoader().getResource(tensorflowModelLocation), + Arrays.asList(OUTPUT_TENSOR_NAME)); SemanticSegmentationUtils segmentationService = new SemanticSegmentationUtils(); @@ -275,15 +282,24 @@ public static void main(String[] args) throws IOException { int height = (int) maskPixelsTensor.shape()[1]; int width = (int) maskPixelsTensor.shape()[2]; - long[][] maskPixels = maskPixelsTensor.copyTo(new long[BATCH_SIZE][height][width])[0]; // take 0 because the batch size is 1. + long[][] maskPixels = maskPixelsTensor.copyTo(new long[BATCH_SIZE][height][width])[0]; // take + // 0 + // because + // the + // batch + // size + // is + // 1. int[][] maskPixelsInt = segmentationService.toIntArray(maskPixels); - BufferedImage maskImage = segmentationService.createMaskImage(maskPixelsInt, scaledImage.getWidth(), scaledImage.getHeight(), 0.35); + BufferedImage maskImage = segmentationService.createMaskImage(maskPixelsInt, scaledImage.getWidth(), + scaledImage.getHeight(), 0.35); BufferedImage blended = segmentationService.blendMask(maskImage, scaledImage); ImageIO.write(maskImage, "png", new File("./semantic-segmentation/target/java2Dmask.jpg")); ImageIO.write(blended, "png", new File("./semantic-segmentation/target/java2Dblended.jpg")); } + } diff --git a/function/spring-spel-function/src/main/java/org/springframework/cloud/fn/spel/SpelFunctionConfiguration.java b/function/spring-spel-function/src/main/java/org/springframework/cloud/fn/spel/SpelFunctionConfiguration.java index c3279d13..cb35ef78 100644 --- a/function/spring-spel-function/src/main/java/org/springframework/cloud/fn/spel/SpelFunctionConfiguration.java +++ b/function/spring-spel-function/src/main/java/org/springframework/cloud/fn/spel/SpelFunctionConfiguration.java @@ -40,8 +40,8 @@ public Function, Message> spelFunction( public ExpressionEvaluatingTransformer expressionEvaluatingTransformer( SpelFunctionProperties spelFunctionProperties) { - return new ExpressionEvaluatingTransformer(new SpelExpressionParser() - .parseExpression(spelFunctionProperties.getExpression())); + return new ExpressionEvaluatingTransformer( + new SpelExpressionParser().parseExpression(spelFunctionProperties.getExpression())); } } diff --git a/function/spring-spel-function/src/test/java/org/springframework/cloud/fn/spel/SpelFunctionApplicationTests.java b/function/spring-spel-function/src/test/java/org/springframework/cloud/fn/spel/SpelFunctionApplicationTests.java index e3e00851..7a26f91d 100644 --- a/function/spring-spel-function/src/test/java/org/springframework/cloud/fn/spel/SpelFunctionApplicationTests.java +++ b/function/spring-spel-function/src/test/java/org/springframework/cloud/fn/spel/SpelFunctionApplicationTests.java @@ -48,7 +48,8 @@ public void testTransform() { @Test public void testJson() { Message message = MessageBuilder.withPayload("{\"foo\":\"bar\"}") - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build(); + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) + .build(); final Message transformed = this.transformer.apply(message); assertThat(transformed.getPayload()).isEqualTo("{\"FOO\":\"BAR\"}"); } @@ -57,4 +58,5 @@ public void testJson() { static class SpelFunctionTestApplication { } + } diff --git a/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionConfiguration.java b/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionConfiguration.java index f8adff49..da1f82cf 100644 --- a/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionConfiguration.java +++ b/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionConfiguration.java @@ -60,8 +60,7 @@ public Function, List>> splitterFunction(AbstractMessageSp @ConditionalOnProperty(prefix = "splitter", name = "expression") public AbstractMessageSplitter expressionSplitter(SplitterFunctionProperties splitterFunctionProperties) { return new ExpressionEvaluatingSplitter( - new SpelExpressionParser() - .parseExpression(splitterFunctionProperties.getExpression())); + new SpelExpressionParser().parseExpression(splitterFunctionProperties.getExpression())); } @Bean @@ -96,10 +95,12 @@ static class FileSplitterCondition extends AnyNestedCondition { @ConditionalOnProperty(prefix = "splitter", name = "charset") static class Charset { + } @ConditionalOnProperty(prefix = "splitter", name = "fileMarkers") static class FileMarkers { + } } diff --git a/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionProperties.java b/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionProperties.java index eef233b0..088eac1b 100644 --- a/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionProperties.java +++ b/function/spring-splitter-function/src/main/java/org/springframework/cloud/fn/splitter/SplitterFunctionProperties.java @@ -37,33 +37,29 @@ public class SplitterFunctionProperties { private String expression; /** - * When expression is null, delimiters to use when tokenizing - * {@link String} payloads. + * When expression is null, delimiters to use when tokenizing {@link String} payloads. */ private String delimiters; /** - * Set to true or false to use a {@code FileSplitter} (to split - * text-based files by line) that includes - * (or not) beginning/end of file markers. + * Set to true or false to use a {@code FileSplitter} (to split text-based files by + * line) that includes (or not) beginning/end of file markers. */ private Boolean fileMarkers; /** - * When 'fileMarkers == true', specify if they should be produced - * as FileSplitter.FileMarker objects or JSON. + * When 'fileMarkers == true', specify if they should be produced as + * FileSplitter.FileMarker objects or JSON. */ private boolean markersJson = true; /** - * The charset to use when converting bytes in text-based files - * to String. + * The charset to use when converting bytes in text-based files to String. */ private String charset; /** - * Add correlation/sequence information in headers to facilitate later - * aggregation. + * Add correlation/sequence information in headers to facilitate later aggregation. */ private boolean applySequence = true; @@ -122,7 +118,8 @@ public boolean isDelimitersAllowed() { @AssertTrue(message = "File properties are not allowed when an 'expression' or 'delimiters' property is provided") public boolean isFilePropsAllowed() { - return !(this.expression != null || this.delimiters != null) || this.fileMarkers == null && this.charset == null; + return !(this.expression != null || this.delimiters != null) + || this.fileMarkers == null && this.charset == null; } } diff --git a/function/spring-splitter-function/src/test/java/org/springframework/cloud/fn/splitter/SplitterFunctionApplicationTests.java b/function/spring-splitter-function/src/test/java/org/springframework/cloud/fn/splitter/SplitterFunctionApplicationTests.java index 5c3a1baf..e90878a4 100644 --- a/function/spring-splitter-function/src/test/java/org/springframework/cloud/fn/splitter/SplitterFunctionApplicationTests.java +++ b/function/spring-splitter-function/src/test/java/org/springframework/cloud/fn/splitter/SplitterFunctionApplicationTests.java @@ -45,5 +45,7 @@ public void testExpressionSplitter() { @SpringBootApplication static class SplitterFunctionTestApplication { + } + } diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/CommandLineArgumentsMessageMapper.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/CommandLineArgumentsMessageMapper.java index 8cac1b0f..743822e8 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/CommandLineArgumentsMessageMapper.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/CommandLineArgumentsMessageMapper.java @@ -21,4 +21,5 @@ import org.springframework.integration.handler.MessageProcessor; public interface CommandLineArgumentsMessageMapper extends MessageProcessor> { + } diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParser.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParser.java index 308d1c33..b7f37f0e 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParser.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParser.java @@ -23,7 +23,8 @@ import org.springframework.util.StringUtils; /** - * Parses a comma delimited list of key value pairs in which the values can contain commas as well. + * Parses a comma delimited list of key value pairs in which the values can contain commas + * as well. * * @author Chris Schaeffer * @author David Turanski @@ -63,4 +64,5 @@ private static void addKeyValuePair(String pair, Map properties) properties.put(pair.substring(0, firstEquals).trim(), pair.substring(firstEquals + 1).trim()); } } + } diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequest.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequest.java index 3644499b..eb226f6f 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequest.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequest.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class TaskLaunchRequest { + @JsonProperty("args") private List commandlineArguments = new ArrayList<>(); @@ -62,4 +63,5 @@ public TaskLaunchRequest addCommmandLineArguments(Collection args) { this.commandlineArguments.addAll(args); return this; } + } diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionConfiguration.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionConfiguration.java index 475c1402..4585aa18 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionConfiguration.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionConfiguration.java @@ -36,13 +36,17 @@ import org.springframework.util.StringUtils; /** - * Configuration for a {@link TaskLaunchRequestFunction}, provided as a common function that can be composed with other Suppliers or - * Functions to transform any {@link Message} to a {@link TaskLaunchRequest} which may be used as input to the {@code TaskLauncherFunction} to launch a task. + * Configuration for a {@link TaskLaunchRequestFunction}, provided as a common function + * that can be composed with other Suppliers or Functions to transform any {@link Message} + * to a {@link TaskLaunchRequest} which may be used as input to the + * {@code TaskLauncherFunction} to launch a task. * - * Command line arguments used by the task, as well as the task name itself may be statically configured or extracted from - * the message contents, using SpEL. See {@link TaskLaunchRequestFunctionProperties} for details. + * Command line arguments used by the task, as well as the task name itself may be + * statically configured or extracted from the message contents, using SpEL. See + * {@link TaskLaunchRequestFunctionProperties} for details. * - * It is also possible to provide your own implementations of {@link CommandLineArgumentsMessageMapper} and {@link TaskNameMessageMapper}. + * It is also possible to provide your own implementations of + * {@link CommandLineArgumentsMessageMapper} and {@link TaskNameMessageMapper}. * * @author David Turanski **/ @@ -58,9 +62,8 @@ public class TaskLaunchRequestFunctionConfiguration { /** * A {@link java.util.function.Function} to transform a {@link Message} payload to a * {@link TaskLaunchRequest}. - * - * @param taskLaunchRequestMessageProcessor a {@link TaskLaunchRequestMessageProcessor}. - * + * @param taskLaunchRequestMessageProcessor a + * {@link TaskLaunchRequestMessageProcessor}. * @return a {@code TaskLaunchRequest} Message. */ @Bean(name = TASK_LAUNCH_REQUEST_FUNCTION_NAME) @@ -78,10 +81,8 @@ public TaskLaunchRequestSupplier taskLaunchRequestInitializer( @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Bean public TaskLaunchRequestMessageProcessor taskLaunchRequestMessageProcessor( - TaskLaunchRequestSupplier taskLaunchRequestInitializer, - TaskLaunchRequestFunctionProperties properties, - EvaluationContext evaluationContext, - @Nullable TaskNameMessageMapper taskNameMessageMapper, + TaskLaunchRequestSupplier taskLaunchRequestInitializer, TaskLaunchRequestFunctionProperties properties, + EvaluationContext evaluationContext, @Nullable TaskNameMessageMapper taskNameMessageMapper, @Nullable CommandLineArgumentsMessageMapper commandLineArgumentsMessageMapper) { if (taskNameMessageMapper == null) { @@ -92,8 +93,7 @@ public TaskLaunchRequestMessageProcessor taskLaunchRequestMessageProcessor( commandLineArgumentsMessageMapper = commandLineArgumentsMessageMapper(properties, evaluationContext); } - return new TaskLaunchRequestMessageProcessor(taskLaunchRequestInitializer, - taskNameMessageMapper, + return new TaskLaunchRequestMessageProcessor(taskLaunchRequestInitializer, taskNameMessageMapper, commandLineArgumentsMessageMapper); } @@ -103,11 +103,11 @@ public EvaluationContext evaluationContext(BeanFactory beanFactory) { } private TaskNameMessageMapper taskNameMessageMapper(TaskLaunchRequestFunctionProperties taskLaunchRequestProperties, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { if (StringUtils.hasText(taskLaunchRequestProperties.getTaskNameExpression())) { SpelExpressionParser expressionParser = new SpelExpressionParser(); Expression taskNameExpression = expressionParser - .parseExpression(taskLaunchRequestProperties.getTaskNameExpression()); + .parseExpression(taskLaunchRequestProperties.getTaskNameExpression()); return new ExpressionEvaluatingTaskNameMessageMapper(taskNameExpression, evaluationContext); } @@ -122,23 +122,23 @@ private CommandLineArgumentsMessageMapper commandLineArgumentsMessageMapper( } private static class TaskLaunchRequestPropertiesInitializer extends TaskLaunchRequestSupplier { - TaskLaunchRequestPropertiesInitializer( - TaskLaunchRequestFunctionProperties taskLaunchRequestProperties) { - this.commandLineArgumentSupplier( - () -> new ArrayList<>(taskLaunchRequestProperties.getArgs())); + TaskLaunchRequestPropertiesInitializer(TaskLaunchRequestFunctionProperties taskLaunchRequestProperties) { + + this.commandLineArgumentSupplier(() -> new ArrayList<>(taskLaunchRequestProperties.getArgs())); - this.deploymentPropertiesSupplier( - () -> KeyValueListParser.parseCommaDelimitedKeyValuePairs( - taskLaunchRequestProperties.getDeploymentProperties())); + this.deploymentPropertiesSupplier(() -> KeyValueListParser + .parseCommaDelimitedKeyValuePairs(taskLaunchRequestProperties.getDeploymentProperties())); this.taskNameSupplier(() -> taskLaunchRequestProperties.getTaskName()); } + } private static class ExpressionEvaluatingTaskNameMessageMapper implements TaskNameMessageMapper { private final Expression expression; + private final EvaluationContext evaluationContext; ExpressionEvaluatingTaskNameMessageMapper(Expression expression, EvaluationContext evaluationContext) { @@ -150,9 +150,11 @@ private static class ExpressionEvaluatingTaskNameMessageMapper implements TaskNa public String processMessage(Message message) { return expression.getValue(evaluationContext, message).toString(); } + } private static class ExpressionEvaluatingCommandLineArgsMapper implements CommandLineArgumentsMessageMapper { + private final Map argExpressionsMap; private final EvaluationContext evaluationContext; @@ -163,8 +165,8 @@ private static class ExpressionEvaluatingCommandLineArgsMapper implements Comman if (StringUtils.hasText(argExpressions)) { SpelExpressionParser expressionParser = new SpelExpressionParser(); - KeyValueListParser.parseCommaDelimitedKeyValuePairs(argExpressions).forEach( - (k, v) -> argExpressionsMap.put(k, expressionParser.parseExpression(v))); + KeyValueListParser.parseCommaDelimitedKeyValuePairs(argExpressions) + .forEach((k, v) -> argExpressionsMap.put(k, expressionParser.parseExpression(v))); } } @@ -176,9 +178,10 @@ public Collection processMessage(Message message) { private Collection evaluateArgExpressions(Message message) { List results = new LinkedList<>(); this.argExpressionsMap.forEach((k, expression) -> results - .add(String.format("%s=%s", k, expression.getValue(this.evaluationContext, message)))); + .add(String.format("%s=%s", k, expression.getValue(this.evaluationContext, message)))); return results; } + } } diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionProperties.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionProperties.java index 8ac70a27..dd27c919 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionProperties.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionProperties.java @@ -57,9 +57,9 @@ public class TaskLaunchRequestFunctionProperties { */ private String taskName; - /** - * A SpEL expression to extract the task name from each Message, using the Message as the evaluation context. + * A SpEL expression to extract the task name from each Message, using the Message as + * the evaluation context. */ private String taskNameExpression; diff --git a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestMessageProcessor.java b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestMessageProcessor.java index 1bbea190..eb649b9f 100644 --- a/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestMessageProcessor.java +++ b/function/spring-task-launch-request-function/src/main/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestMessageProcessor.java @@ -57,7 +57,7 @@ public Message postProcessMessage(Message message) { taskLaunchRequest.addCommmandLineArguments(commandLineArgumentsMessageMapper.processMessage(message)); MessageBuilder builder = MessageBuilder.withPayload(taskLaunchRequest) - .copyHeaders(message.getHeaders()); + .copyHeaders(message.getHeaders()); return adjustHeaders(builder).build(); } @@ -65,4 +65,5 @@ private MessageBuilder adjustHeaders(MessageBuilder { + } diff --git a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParserTests.java b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParserTests.java index 28d35361..32be9b81 100644 --- a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParserTests.java +++ b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/KeyValueListParserTests.java @@ -31,8 +31,8 @@ public class KeyValueListParserTests { @Test public void testParseSimpleDeploymentProperty() { - Map deploymentProperties = KeyValueListParser.parseCommaDelimitedKeyValuePairs( - "app.sftp.param=value"); + Map deploymentProperties = KeyValueListParser + .parseCommaDelimitedKeyValuePairs("app.sftp.param=value"); assertTrue("Invalid number of deployment properties: " + deploymentProperties.size(), deploymentProperties.size() == 1); assertTrue("Expected deployment key not found", deploymentProperties.containsKey("app.sftp.param")); @@ -41,8 +41,8 @@ public void testParseSimpleDeploymentProperty() { @Test public void testParseSimpleDeploymentPropertyMultipleValues() { - Map deploymentProperties = KeyValueListParser.parseCommaDelimitedKeyValuePairs( - "app.sftp.param=value1,value2,value3"); + Map deploymentProperties = KeyValueListParser + .parseCommaDelimitedKeyValuePairs("app.sftp.param=value1,value2,value3"); assertTrue("Invalid number of deployment properties: " + deploymentProperties.size(), deploymentProperties.size() == 1); @@ -55,8 +55,7 @@ public void testParseSpelExpressionMultipleValues() { Map argExpressions = KeyValueListParser.parseCommaDelimitedKeyValuePairs( "arg1=payload.substr(0,2),arg2=headers['foo'],arg3=headers['bar']==false"); - assertTrue("Invalid number of deployment properties: " + argExpressions.size(), - argExpressions.size() == 3); + assertTrue("Invalid number of deployment properties: " + argExpressions.size(), argExpressions.size() == 3); assertTrue("Expected deployment key not found", argExpressions.containsKey("arg1")); assertEquals("Invalid deployment value", "payload.substr(0,2)", argExpressions.get("arg1")); @@ -69,8 +68,8 @@ public void testParseSpelExpressionMultipleValues() { @Test public void testParseMultipleDeploymentPropertiesSingleValue() { - Map deploymentProperties = KeyValueListParser.parseCommaDelimitedKeyValuePairs( - "app.sftp.param=value1,app.sftp.other.param=value2"); + Map deploymentProperties = KeyValueListParser + .parseCommaDelimitedKeyValuePairs("app.sftp.param=value1,app.sftp.other.param=value2"); assertTrue("Invalid number of deployment properties: " + deploymentProperties.size(), deploymentProperties.size() == 2); @@ -84,8 +83,8 @@ public void testParseMultipleDeploymentPropertiesSingleValue() { public void testParseMultipleDeploymentPropertiesMultipleValues() { TaskLaunchRequestFunctionProperties taskLaunchRequestProperties = new TaskLaunchRequestFunctionProperties(); - Map deploymentProperties = KeyValueListParser.parseCommaDelimitedKeyValuePairs( - "app.sftp.param=value1,value2,app.sftp.other.param=other1,other2"); + Map deploymentProperties = KeyValueListParser + .parseCommaDelimitedKeyValuePairs("app.sftp.param=value1,value2,app.sftp.other.param=other1,other2"); assertTrue("Invalid number of deployment properties: " + deploymentProperties.size(), deploymentProperties.size() == 2); @@ -94,4 +93,5 @@ public void testParseMultipleDeploymentPropertiesMultipleValues() { assertTrue("Expected deployment key not found", deploymentProperties.containsKey("app.sftp.other.param")); assertEquals("Invalid deployment value", "other1,other2", deploymentProperties.get("app.sftp.other.param")); } + } diff --git a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionApplicationTests.java b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionApplicationTests.java index f23399ae..d548216a 100644 --- a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionApplicationTests.java +++ b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionApplicationTests.java @@ -45,18 +45,17 @@ public class TaskLaunchRequestFunctionApplicationTests { @BeforeEach public void setUp() { springApplicationBuilder = new SpringApplicationBuilder(TaskLaunchRequestFunctionTestApplication.class) - .web(WebApplicationType.NONE); + .web(WebApplicationType.NONE); } @Test @DirtiesContext public void simpleDataflowTaskLaunchRequest() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", - "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name=foo") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name=foo") + .run(); TaskLaunchRequest taskLaunchRequest = verifyAndreceiveTaskLaunchRequest(context); @@ -69,16 +68,15 @@ public void simpleDataflowTaskLaunchRequest() throws IOException { @DirtiesContext public void dataflowTaskLaunchRequestWithArgsAndDeploymentProperties() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name=foo", "task.launch.request.args=foo=bar,baz=boo", - "task.launch.request.deploymentProperties=count=3") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name=foo", "task.launch.request.args=foo=bar,baz=boo", + "task.launch.request.deploymentProperties=count=3") + .run(); TaskLaunchRequest taskLaunchRequest = verifyAndreceiveTaskLaunchRequest(context); assertThat(taskLaunchRequest.getTaskName()).isEqualTo("foo"); - assertThat(taskLaunchRequest.getCommandlineArguments()).containsExactlyInAnyOrder("foo=bar", - "baz=boo"); + assertThat(taskLaunchRequest.getCommandlineArguments()).containsExactlyInAnyOrder("foo=bar", "baz=boo"); assertThat(taskLaunchRequest.getDeploymentProperties()).containsOnly(entry("count", "3")); } @@ -86,10 +84,10 @@ public void dataflowTaskLaunchRequestWithArgsAndDeploymentProperties() throws IO @DirtiesContext public void taskLaunchRequestWithCommandLineArgsMessageMapper() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name=foo", "enhanceTLRArgs=true") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name=foo", "enhanceTLRArgs=true") + .run(); TaskLaunchRequest taskLaunchRequest = verifyAndreceiveTaskLaunchRequest(context); @@ -102,12 +100,11 @@ public void taskLaunchRequestWithCommandLineArgsMessageMapper() throws IOExcepti @Test @DirtiesContext public void taskLaunchRequestWithArgExpressions() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", - "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name=foo", - "task.launch.request.arg-expressions=foo=payload.toUpperCase(),bar=payload.substring(0,2)") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name=foo", + "task.launch.request.arg-expressions=foo=payload.toUpperCase(),bar=payload.substring(0,2)") + .run(); Message message = MessageBuilder.withPayload("hello").build(); @@ -123,11 +120,10 @@ public void taskLaunchRequestWithArgExpressions() throws IOException { @Test @DirtiesContext public void taskLaunchRequestWithIntPayload() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name=foo", - "task.launch.request.arg-expressions=i=payload") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name=foo", "task.launch.request.arg-expressions=i=payload") + .run(); TaskLaunchRequestFunction taskLaunchRequestFunction = context.getBean(TaskLaunchRequestFunction.class); @@ -144,10 +140,10 @@ public void taskLaunchRequestWithIntPayload() throws IOException { @Test @DirtiesContext public void taskNameExpression() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", - "task.launch.request.task-name-expression=payload+'_task'") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "task.launch.request.task-name-expression=payload+'_task'") + .run(); TaskLaunchRequestFunction taskLaunchRequestFunction = context.getBean(TaskLaunchRequestFunction.class); @@ -163,10 +159,10 @@ public void taskNameExpression() throws IOException { @Test @DirtiesContext public void customTaskNameExtractor() throws IOException { - ApplicationContext context = springApplicationBuilder.properties( - "spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", - "customTaskNameExtractor=true") - .run(); + ApplicationContext context = springApplicationBuilder + .properties("spring.jmx.enabled=false", "spring.cloud.function.definition=taskLaunchRequestFunction", + "customTaskNameExtractor=true") + .run(); TaskLaunchRequestFunction taskLaunchRequestFunction = context.getBean(TaskLaunchRequestFunction.class); Message message = MessageBuilder.withPayload("foo").build(); @@ -184,11 +180,10 @@ public void customTaskNameExtractor() throws IOException { assertThat(request.getTaskName()).isEqualTo("defaultTask"); } - private TaskLaunchRequest verifyAndreceiveTaskLaunchRequest(ApplicationContext context) - throws IOException { + private TaskLaunchRequest verifyAndreceiveTaskLaunchRequest(ApplicationContext context) throws IOException { TaskLaunchRequestFunction taskLaunchRequestFunction = context.getBean(TaskLaunchRequestFunction.class); Message message = taskLaunchRequestFunction - .apply(MessageBuilder.withPayload(new byte[] {}).build()); + .apply(MessageBuilder.withPayload(new byte[] {}).build()); assertThat(message).isNotNull(); return message.getPayload(); } @@ -207,5 +202,7 @@ TaskNameMessageMapper taskNameExtractor() { CommandLineArgumentsMessageMapper commandLineArgumentsProvider() { return message -> Collections.singletonList("runtimeArg"); } + } + } diff --git a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionPropertiesTests.java b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionPropertiesTests.java index a452a0e9..19eceaf2 100644 --- a/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionPropertiesTests.java +++ b/function/spring-task-launch-request-function/src/test/java/org/springframework/cloud/fn/task/launch/request/TaskLaunchRequestFunctionPropertiesTests.java @@ -73,4 +73,5 @@ private TaskLaunchRequestFunctionProperties getBatchProperties(String... var) { static class Conf { } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java index e58443ce..7529aa6a 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionConfiguration.java @@ -36,7 +36,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -103,11 +102,10 @@ public Function> twitterReverseGeocodeFunction(Twitter twi } @Bean - public Function, Message> twitterGeoFunction( - Function, GeoQuery> toGeoQuery, - Function> places, - Function> managedJson) { + public Function, Message> twitterGeoFunction(Function, GeoQuery> toGeoQuery, + Function> places, Function> managedJson) { return toGeoQuery.andThen(places).andThen(managedJson)::apply; } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java index 9e308342..cf316d27 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionProperties.java @@ -24,7 +24,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -35,8 +34,10 @@ public class TwitterGeoFunctionProperties { private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload"); public enum GeoType { + /** Geo retrieval type. */ reverse, search + } /** @@ -56,22 +57,24 @@ public enum GeoType { private Location location = new Location(); /** - * Hints for the number of results to return. This does not guarantee that the number of results - * returned will equal max_results, but instead informs how many 'nearby' results to return. + * Hints for the number of results to return. This does not guarantee that the number + * of results returned will equal max_results, but instead informs how many 'nearby' + * results to return. */ private int maxResults = -1; /** - * Sets a hint on the 'region' in which to search. If a number, then this is a radius in meters, but it - * can also take a string that is suffixed with ft to specify feet. If this is not passed in, then it is - * assumed to be 0m. If coming from a device, in practice, this value is whatever accuracy the device - * has measuring its location (whether it be coming from a GPS, WiFi triangulation, etc.). + * Sets a hint on the 'region' in which to search. If a number, then this is a radius + * in meters, but it can also take a string that is suffixed with ft to specify feet. + * If this is not passed in, then it is assumed to be 0m. If coming from a device, in + * practice, this value is whatever accuracy the device has measuring its location + * (whether it be coming from a GPS, WiFi triangulation, etc.). */ private String accuracy = null; /** - * Minimal granularity of data to return. If this is not passed in, then neighborhood is assumed. - * City can also be passed. + * Minimal granularity of data to return. If this is not passed in, then neighborhood + * is assumed. City can also be passed. */ private String granularity = null; @@ -125,7 +128,8 @@ public void setGranularity(String granularity) { @AssertTrue(message = "Either the IP or the Location must be set") public boolean isAtLeastOne() { - return this.getSearch().getIp() == null ^ (this.getLocation().getLat() == null && this.getLocation().getLon() == null); + return this.getSearch().getIp() == null + ^ (this.getLocation().getLat() == null && this.getLocation().getLon() == null); } @AssertTrue(message = "The IP parameter is applicable only for 'Search' GeoType") @@ -137,9 +141,10 @@ public boolean isIpUsedWithSearchGeoType() { } public static class Search { + /** - * An IP address. Used when attempting to fix geolocation based off of the user's IP address. - * Applicable only for 'search' geo type. + * An IP address. Used when attempting to fix geolocation based off of the user's + * IP address. Applicable only for 'search' geo type. */ private Expression ip = null; @@ -163,6 +168,7 @@ public Expression getQuery() { public void setQuery(Expression query) { this.query = query; } + } public static class Location { @@ -177,7 +183,6 @@ public static class Location { */ private Expression lon; - public Expression getLat() { return lat; } @@ -193,5 +198,7 @@ public Expression getLon() { public void setLon(Expression lon) { this.lon = lon; } + } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java index c82f023c..236e85c6 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionConfiguration.java @@ -59,8 +59,8 @@ public Function, Trends> trend(TwitterTrendFunctionProperties propert } @Bean - public Function, List> closestOrAvailableTrends( - TwitterTrendFunctionProperties properties, Twitter twitter) { + public Function, List> closestOrAvailableTrends(TwitterTrendFunctionProperties properties, + Twitter twitter) { return message -> { try { if (properties.getClosest().getLat() != null && properties.getClosest().getLon() != null) { @@ -80,12 +80,12 @@ public Function, List> closestOrAvailableTrends( } @Bean - public Function, Message> twitterTrendFunction( - Function> managedJson, Function, Trends> trend, - TwitterTrendFunctionProperties properties, Function, - List> closestOrAvailableTrends) { + public Function, Message> twitterTrendFunction(Function> managedJson, + Function, Trends> trend, TwitterTrendFunctionProperties properties, + Function, List> closestOrAvailableTrends) { - return (properties.getTrendQueryType() == TwitterTrendFunctionProperties.TrendQueryType.trend) ? - trend.andThen(managedJson) : closestOrAvailableTrends.andThen(managedJson); + return (properties.getTrendQueryType() == TwitterTrendFunctionProperties.TrendQueryType.trend) + ? trend.andThen(managedJson) : closestOrAvailableTrends.andThen(managedJson); } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java index e3fe33ba..63cadcd0 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionProperties.java @@ -33,10 +33,12 @@ public class TwitterTrendFunctionProperties { private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload"); enum TrendQueryType { + /** Retrieve trending places. */ trend, /** Retrieve the Locations of trending places. */ trendLocation + } private TrendQueryType trendQueryType = TrendQueryType.trend; @@ -74,17 +76,18 @@ public Closest getClosest() { } public static class Closest { + /** - * If provided with a long parameter the available trend locations will be sorted by distance, nearest - * to furthest, to the co-ordinate pair. - * The valid ranges for longitude is -180.0 to +180.0 (West is negative, East is positive) inclusive. + * If provided with a long parameter the available trend locations will be sorted + * by distance, nearest to furthest, to the co-ordinate pair. The valid ranges for + * longitude is -180.0 to +180.0 (West is negative, East is positive) inclusive. */ private Expression lat; /** - * If provided with a lat parameter the available trend locations will be sorted by distance, nearest to - * furthest, to the co-ordinate pair. The valid ranges for longitude is -180.0 to +180.0 (West is negative, - * East is positive) inclusive. + * If provided with a lat parameter the available trend locations will be sorted + * by distance, nearest to furthest, to the co-ordinate pair. The valid ranges for + * longitude is -180.0 to +180.0 (West is negative, East is positive) inclusive. */ private Expression lon; @@ -103,5 +106,7 @@ public Expression getLon() { public void setLon(Expression lon) { this.lon = lon; } + } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java index 17dfafe3..7dd4ed09 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionConfiguration.java @@ -35,7 +35,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -88,11 +87,12 @@ else if (lookup.getUserId() != null) { @Bean /** - * queryUsers - depends on the `twitter.users.type` property is either userSearch or userLookup. - * managedJson - converts Users into JSON message payload. + * queryUsers - depends on the `twitter.users.type` property is either userSearch or + * userLookup. managedJson - converts Users into JSON message payload. */ public Function, Message> twitterUsersFunction(Function, List> queryUsers, Function> managedJson) { return queryUsers.andThen(managedJson); } + } diff --git a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java index 8f1d5359..75243026 100644 --- a/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java +++ b/function/spring-twitter-function/src/main/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionProperties.java @@ -34,8 +34,10 @@ public class TwitterUsersFunctionProperties { private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload"); public enum UserQueryType { + /** User retrieval types. */ search, lookup + } /** @@ -45,14 +47,14 @@ public enum UserQueryType { private UserQueryType type = UserQueryType.search; /** - * Returns fully-hydrated user objects for specified by comma-separated values passed to the user_id and/or - * screen_name parameters. + * Returns fully-hydrated user objects for specified by comma-separated values passed + * to the user_id and/or screen_name parameters. */ private final Lookup lookup = new Lookup(); /** - * relevance-based search interface for querying by topical interest, full name, company name, location, - * or other criteria. + * relevance-based search interface for querying by topical interest, full name, + * company name, location, or other criteria. */ private final Search search = new Search(); @@ -85,6 +87,7 @@ else if (this.getType() == UserQueryType.search) { } public static class Lookup { + /** * A comma separated list of user IDs, up to 100 are allowed in a single request. * You are strongly encouraged to use a POST for larger requests. @@ -92,8 +95,9 @@ public static class Lookup { private Expression userId; /** - * A comma separated list of screen names, up to 100 are allowed in a single request. - * You are strongly encouraged to use a POST for larger (up to 100 screen names) requests. + * A comma separated list of screen names, up to 100 are allowed in a single + * request. You are strongly encouraged to use a POST for larger (up to 100 screen + * names) requests. */ private Expression screenName; @@ -112,9 +116,11 @@ public Expression getScreenName() { public void setScreenName(Expression screenName) { this.screenName = screenName; } + } public static class Search { + /** * The search query to run against people search. */ @@ -140,5 +146,7 @@ public int getPage() { public void setPage(int page) { this.page = page; } + } + } diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java index e3b50e79..2bd6801a 100644 --- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java +++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java @@ -58,14 +58,10 @@ /** * @author Christian Tzolov */ -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "twitter.connection.consumerKey=consumerKey666", - "twitter.connection.consumerSecret=consumerSecret666", - "twitter.connection.accessToken=accessToken666", - "twitter.connection.accessTokenSecret=accessTokenSecret666" - }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { "twitter.connection.consumerKey=consumerKey666", + "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666", + "twitter.connection.accessTokenSecret=accessTokenSecret666" }) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class TwitterGeoFunctionTest { @@ -83,18 +79,12 @@ public abstract class TwitterGeoFunctionTest { public static void recordRequestExpectation(Map> parameters) { mockClient - .when( - request() - .withMethod("GET") - .withPath("/geo/search.json") - .withQueryStringParameters(parameters), - unlimited()) - .respond( - response() - .withStatusCode(200) - .withHeader("Content-Type", "application/json; charset=utf-8") - .withBody(TwitterTestUtils.asString("classpath:/response/search_places_amsterdam.json")) - .withDelay(TimeUnit.SECONDS, 1)); + .when(request().withMethod("GET").withPath("/geo/search.json").withQueryStringParameters(parameters), + unlimited()) + .respond(response().withStatusCode(200) + .withHeader("Content-Type", "application/json; charset=utf-8") + .withBody(TwitterTestUtils.asString("classpath:/response/search_places_amsterdam.json")) + .withDelay(TimeUnit.SECONDS, 1)); } @@ -109,10 +99,8 @@ public static void stopMockServer() { mockServer.stop(); } - @TestPropertySource(properties = { - "twitter.geo.search.ip='127.0.0.1'", - "twitter.geo.search.query=payload.toUpperCase()" - }) + @TestPropertySource( + properties = { "twitter.geo.search.ip='127.0.0.1'", "twitter.geo.search.query=payload.toUpperCase()" }) public static class TwitterGeoSearchByIPAndQueryTests extends TwitterGeoFunctionTest { @Test @@ -128,12 +116,10 @@ public void testOne() throws IOException { Message received = twitterUsersFunction.apply(MessageBuilder.withPayload(inPayload).build()); - mockClient.verify(request() - .withMethod("GET") - .withPath("/geo/search.json") - .withQueryStringParameter("ip", "127.0.0.1") - .withQueryStringParameter("query", "AMSTERDAM"), - once()); + mockClient.verify(request().withMethod("GET") + .withPath("/geo/search.json") + .withQueryStringParameter("ip", "127.0.0.1") + .withQueryStringParameter("query", "AMSTERDAM"), once()); String outPayload = new String((byte[]) received.getPayload()); @@ -142,13 +128,11 @@ public void testOne() throws IOException { List places = new ObjectMapper().readValue(outPayload, List.class); assertThat(places).hasSize(12); } + } - @TestPropertySource(properties = { - "twitter.geo.location.lat='52.378'", - "twitter.geo.location.lon='4.9'", - "twitter.geo.search.query=payload.toUpperCase()" - }) + @TestPropertySource(properties = { "twitter.geo.location.lat='52.378'", "twitter.geo.location.lon='4.9'", + "twitter.geo.search.query=payload.toUpperCase()" }) public static class TwitterGeoSearchByLocationTests extends TwitterGeoFunctionTest { @Test @@ -165,13 +149,11 @@ public void testOne() throws IOException { Message received = twitterUsersFunction.apply(MessageBuilder.withPayload(inPayload).build()); - mockClient.verify(request() - .withMethod("GET") - .withPath("/geo/search.json") - .withQueryStringParameter("lat", "52.378") - .withQueryStringParameter("long", "4.9") - .withQueryStringParameter("query", "Amsterdam"), - once()); + mockClient.verify(request().withMethod("GET") + .withPath("/geo/search.json") + .withQueryStringParameter("lat", "52.378") + .withQueryStringParameter("long", "4.9") + .withQueryStringParameter("query", "Amsterdam"), once()); String outPayload = new String((byte[]) received.getPayload()); @@ -180,13 +162,11 @@ public void testOne() throws IOException { List places = new ObjectMapper().readValue(outPayload, List.class); assertThat(places).hasSize(12); } + } - @TestPropertySource(properties = { - "twitter.geo.type=reverse", - "twitter.geo.location.lat='52.378'", - "twitter.geo.location.lon='4.9'" - }) + @TestPropertySource(properties = { "twitter.geo.type=reverse", "twitter.geo.location.lat='52.378'", + "twitter.geo.location.lon='4.9'" }) public static class TwitterGeoSearchByLocation2Tests extends TwitterGeoFunctionTest { @Test @@ -202,12 +182,10 @@ public void testOne() throws IOException { Message received = twitterUsersFunction.apply(MessageBuilder.withPayload(inPayload).build()); - mockClient.verify(request() - .withMethod("GET") - .withPath("/geo/search.json") - .withQueryStringParameter("lat", "52.378") - .withQueryStringParameter("long", "4.9"), - once()); + mockClient.verify(request().withMethod("GET") + .withPath("/geo/search.json") + .withQueryStringParameter("lat", "52.378") + .withQueryStringParameter("long", "4.9"), once()); String outPayload = new String((byte[]) received.getPayload()); @@ -216,13 +194,12 @@ public void testOne() throws IOException { List places = new ObjectMapper().readValue(outPayload, List.class); assertThat(places).hasSize(12); } + } - @TestPropertySource(properties = { - "twitter.geo.location.lat=#jsonPath(new String(payload),'$.location.lat')", + @TestPropertySource(properties = { "twitter.geo.location.lat=#jsonPath(new String(payload),'$.location.lat')", "twitter.geo.location.lon=#jsonPath(new String(payload),'$.location.lon')", - "twitter.geo.search.query=#jsonPath(new String(payload),'$.country')" - }) + "twitter.geo.search.query=#jsonPath(new String(payload),'$.country')" }) public static class TwitterGeoSearchJsonPathTests extends TwitterGeoFunctionTest { @Test @@ -237,18 +214,15 @@ public void testOne() throws IOException { String inPayload = "{ \"country\" : \"Netherlands\", \"location\" : { \"lat\" : 52.00 , \"lon\" : 5.0 } }"; - Message received = twitterUsersFunction.apply(MessageBuilder - .withPayload(inPayload) - .setHeader("contentType", MimeTypeUtils.APPLICATION_JSON_VALUE) - .build()); + Message received = twitterUsersFunction.apply(MessageBuilder.withPayload(inPayload) + .setHeader("contentType", MimeTypeUtils.APPLICATION_JSON_VALUE) + .build()); - mockClient.verify(request() - .withMethod("GET") - .withPath("/geo/search.json") - .withQueryStringParameter("lat", "52.0") - .withQueryStringParameter("long", "5.0") - .withQueryStringParameter("query", "Netherlands"), - once()); + mockClient.verify(request().withMethod("GET") + .withPath("/geo/search.json") + .withQueryStringParameter("lat", "52.0") + .withQueryStringParameter("long", "5.0") + .withQueryStringParameter("query", "Netherlands"), once()); String outPayload = new String((byte[]) received.getPayload()); @@ -257,23 +231,26 @@ public void testOne() throws IOException { List places = new ObjectMapper().readValue(outPayload, List.class); assertThat(places).hasSize(12); } + } @SpringBootConfiguration @EnableAutoConfiguration @Import(TwitterGeoFunctionConfiguration.class) public static class TwitterGeoFunctionTestApplication { + @Bean @Primary public twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties, Function toConfigurationBuilder) { - Function mockedConfiguration = - toConfigurationBuilder.andThen( - new TwitterTestUtils().mockTwitterUrls( - String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); + Function mockedConfiguration = toConfigurationBuilder + .andThen(new TwitterTestUtils() + .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); return mockedConfiguration.apply(properties).build(); } + } + } diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java index bcd49d9d..08f2e228 100644 --- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java +++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTrendFunctionTests.java @@ -52,14 +52,10 @@ /** * @author Christian Tzolov */ -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "twitter.connection.consumerKey=consumerKey666", - "twitter.connection.consumerSecret=consumerSecret666", - "twitter.connection.accessToken=accessToken666", - "twitter.connection.accessTokenSecret=accessTokenSecret666" - }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { "twitter.connection.consumerKey=consumerKey666", + "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666", + "twitter.connection.accessTokenSecret=accessTokenSecret666" }) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class TwitterTrendFunctionTests { @@ -70,6 +66,7 @@ public abstract class TwitterTrendFunctionTests { private static ClientAndServer mockServer; private static MockServerClient mockClient; + private static HttpRequest trendsRequest; @Autowired @@ -80,10 +77,8 @@ public static void startServer() { mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT); mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT); - trendsRequest = setExpectation(request() - .withMethod("GET") - .withPath("/trends/place.json") - .withQueryStringParameter("id", "2972")); + trendsRequest = setExpectation( + request().withMethod("GET").withPath("/trends/place.json").withQueryStringParameter("id", "2972")); } @AfterAll @@ -92,23 +87,16 @@ public static void stopServer() { } public static HttpRequest setExpectation(HttpRequest request) { - mockClient - .when(request, exactly(1)) - .respond(response() - .withStatusCode(200) - .withHeaders( - new Header("Content-Type", "application/json; charset=utf-8"), - new Header("Cache-Control", "public, max-age=86400")) - .withBody(TwitterTestUtils.asString("classpath:/response/trends.json")) - .withDelay(TimeUnit.SECONDS, 1) - ); + mockClient.when(request, exactly(1)) + .respond(response().withStatusCode(200) + .withHeaders(new Header("Content-Type", "application/json; charset=utf-8"), + new Header("Cache-Control", "public, max-age=86400")) + .withBody(TwitterTestUtils.asString("classpath:/response/trends.json")) + .withDelay(TimeUnit.SECONDS, 1)); return request; } - @TestPropertySource(properties = { - "twitter.trend.locationId='2972'", - "twitter.connection.rawJson=true" - }) + @TestPropertySource(properties = { "twitter.trend.locationId='2972'", "twitter.connection.rawJson=true" }) public static class TwitterTrendPayloadTests extends TwitterTrendFunctionTests { @Test @@ -117,24 +105,26 @@ public void testOne() { mockClient.verify(trendsRequest, once()); assertThat(received).isNotNull(); } + } @SpringBootConfiguration @EnableAutoConfiguration @Import(TwitterTrendFunctionConfiguration.class) public static class TwitterTrendFunctionTestApplication { + @Bean @Primary public twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties, Function toConfigurationBuilder) { - Function mockedConfiguration = - toConfigurationBuilder.andThen( - new TwitterTestUtils().mockTwitterUrls( - String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); + Function mockedConfiguration = toConfigurationBuilder + .andThen(new TwitterTestUtils() + .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); return mockedConfiguration.apply(properties).build(); } + } } diff --git a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java index 8417d8e4..fa334fbb 100644 --- a/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java +++ b/function/spring-twitter-function/src/test/java/org/springframework/cloud/fn/twitter/users/TwitterUsersFunctionTests.java @@ -55,14 +55,10 @@ /** * @author Christian Tzolov */ -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "twitter.connection.consumerKey=consumerKey666", - "twitter.connection.consumerSecret=consumerSecret666", - "twitter.connection.accessToken=accessToken666", - "twitter.connection.accessTokenSecret=accessTokenSecret666" - }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { "twitter.connection.consumerKey=consumerKey666", + "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666", + "twitter.connection.accessTokenSecret=accessTokenSecret666" }) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class TwitterUsersFunctionTests { @@ -73,8 +69,11 @@ public abstract class TwitterUsersFunctionTests { private static ClientAndServer mockServer; private static MockServerClient mockClient; + private static HttpRequest searchUsersRequest; + private static HttpRequest lookupUsersRequest; + private static HttpRequest lookupUsersRequest2; @Autowired @@ -84,16 +83,12 @@ public abstract class TwitterUsersFunctionTests { Function, Message> twitterUsersFunction; public static HttpRequest setExpectation(HttpRequest request, String responseUri) { - mockClient - .when(request, exactly(1)) - .respond(response() - .withStatusCode(200) - .withHeaders( - new Header("Content-Type", "application/json; charset=utf-8"), - new Header("Cache-Control", "public, max-age=86400")) - .withBody(TwitterTestUtils.asString(responseUri)) - .withDelay(TimeUnit.SECONDS, 1) - ); + mockClient.when(request, exactly(1)) + .respond(response().withStatusCode(200) + .withHeaders(new Header("Content-Type", "application/json; charset=utf-8"), + new Header("Cache-Control", "public, max-age=86400")) + .withBody(TwitterTestUtils.asString(responseUri)) + .withDelay(TimeUnit.SECONDS, 1)); return request; } @@ -102,25 +97,20 @@ public static void startServer() { mockServer = ClientAndServer.startClientAndServer(MOCK_SERVER_PORT); mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT); - searchUsersRequest = setExpectation(request() - .withMethod("GET") - .withPath("/users/search.json") - .withQueryStringParameter("q", "tzolov") - .withQueryStringParameter("page", "3"), - "classpath:/response/search_users.json"); - - lookupUsersRequest = setExpectation(request() - .withMethod("GET") - .withPath("/users/lookup.json") - .withQueryStringParameter("user_id", - "710705860343963648,326896547,267603736,781497571629989888,838754923"), + searchUsersRequest = setExpectation(request().withMethod("GET") + .withPath("/users/search.json") + .withQueryStringParameter("q", "tzolov") + .withQueryStringParameter("page", "3"), "classpath:/response/search_users.json"); + + lookupUsersRequest = setExpectation(request().withMethod("GET") + .withPath("/users/lookup.json") + .withQueryStringParameter("user_id", "710705860343963648,326896547,267603736,781497571629989888,838754923"), "classpath:/response/lookup_users_id.json"); - lookupUsersRequest2 = setExpectation(request() - .withMethod("GET") - .withPath("/users/lookup.json") - .withQueryStringParameter("screen_name", - "TzolovMarto,Rabotnik57,antzolov,peyo_tzolov,ivantzolov"), + lookupUsersRequest2 = setExpectation( + request().withMethod("GET") + .withPath("/users/lookup.json") + .withQueryStringParameter("screen_name", "TzolovMarto,Rabotnik57,antzolov,peyo_tzolov,ivantzolov"), "classpath:/response/lookup_users_id.json"); } @@ -129,10 +119,7 @@ public static void stopServer() { mockServer.stop(); } - @TestPropertySource(properties = { - "twitter.users.type=search", - "twitter.users.search.query=payload" - }) + @TestPropertySource(properties = { "twitter.users.type=search", "twitter.users.search.query=payload" }) public static class TwitterSearchUsersTests extends TwitterUsersFunctionTests { @Test @@ -143,12 +130,11 @@ public void testOne() throws IOException { List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class); assertThat(list).hasSize(20); } + } - @TestPropertySource(properties = { - "twitter.users.type=lookup", - "twitter.users.lookup.userId='710705860343963648,326896547,267603736,781497571629989888,838754923'" - }) + @TestPropertySource(properties = { "twitter.users.type=lookup", + "twitter.users.lookup.userId='710705860343963648,326896547,267603736,781497571629989888,838754923'" }) public static class TwitterLookupUserIdLiteralTests extends TwitterUsersFunctionTests { @Test @@ -161,12 +147,11 @@ public void testOne() throws IOException { List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class); assertThat(list).hasSize(5); } + } - @TestPropertySource(properties = { - "twitter.users.type=lookup", - "twitter.users.lookup.screenName=#jsonPath(payload,'$[*].code')" - }) + @TestPropertySource(properties = { "twitter.users.type=lookup", + "twitter.users.lookup.screenName=#jsonPath(payload,'$[*].code')" }) public static class TwitterLookupScreenNamePayloadTests extends TwitterUsersFunctionTests { @Test @@ -182,23 +167,26 @@ public void testOne() throws IOException { List list = mapper.readValue(new String((byte[]) received.getPayload()), List.class); assertThat(list).hasSize(5); } + } @SpringBootConfiguration @EnableAutoConfiguration @Import(TwitterUsersFunctionConfiguration.class) static class TwitterUsersFunctionTestApplication { + @Bean @Primary public twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties, Function toConfigurationBuilder) { - Function mockedConfiguration = - toConfigurationBuilder.andThen( - new TwitterTestUtils().mockTwitterUrls( - String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); + Function mockedConfiguration = toConfigurationBuilder + .andThen(new TwitterTestUtils() + .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); return mockedConfiguration.apply(properties).build(); } + } + } diff --git a/gradle.properties b/gradle.properties index 98ca984b..b11074cf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,3 @@ version=5.0.0-SNAPSHOT org.gradle.jvmargs=-Xmx1536M -Dfile.encoding=UTF-8 org.gradle.caching=true org.gradle.parallel=true - diff --git a/gradle/checkstyle-conventions.gradle b/gradle/checkstyle-conventions.gradle new file mode 100644 index 00000000..24e0701e --- /dev/null +++ b/gradle/checkstyle-conventions.gradle @@ -0,0 +1,19 @@ + +apply plugin: 'io.spring.javaformat' +apply plugin: 'checkstyle' + +checkstyle { + toolVersion = "10.3" + configDirectory = rootProject.file('etc/checkstyle') + ignoreFailures = true +} + +dependencies { + // NOTE: We explicitly specify checkstyle dep before javaformat checkstyle due to antlr class mismatch + checkstyle("com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}") + checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}") +} + +tasks.named("checkFormatMain") { + exclude "org/springframework/cloud/fn/object/detection/protos" +} diff --git a/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumReactiveConsumerConfiguration.java b/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumReactiveConsumerConfiguration.java index ed8ad039..677ff174 100644 --- a/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumReactiveConsumerConfiguration.java +++ b/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumReactiveConsumerConfiguration.java @@ -48,7 +48,6 @@ import org.springframework.util.MimeTypeUtils; /** - * * @author Christian Tzolov * @author Artem Bilan */ @@ -58,6 +57,7 @@ public class DebeziumReactiveConsumerConfiguration implements BeanClassLoaderAware { private static final Log logger = LogFactory.getLog(DebeziumReactiveConsumerConfiguration.class); + /** * ORG_SPRINGFRAMEWORK_KAFKA_SUPPORT_KAFKA_NULL. */ @@ -77,15 +77,16 @@ public void setBeanClassLoader(ClassLoader classLoader) { } /** - * Reactive Streams, single subscriber, sink used to push down the change event signals received from the Debezium - * Engine. + * Reactive Streams, single subscriber, sink used to push down the change event + * signals received from the Debezium Engine. */ private final Sinks.Many> eventSink = Sinks.many().unicast().onBackpressureError(); /** - * Debezium Engine is designed to be submitted to an {@link ExecutorService} for execution by a single thread, and a - * running connector can be stopped either by calling {@link #stop()} from another thread or by interrupting the - * running thread (e.g., as is the case with {@link ExecutorService#shutdownNow()}). + * Debezium Engine is designed to be submitted to an {@link ExecutorService} for + * execution by a single thread, and a running connector can be stopped either by + * calling {@link #stop()} from another thread or by interrupting the running thread + * (e.g., as is the case with {@link ExecutorService#shutdownNow()}). */ private final ExecutorService debeziumExecutor = Executors.newSingleThreadExecutor(); @@ -101,8 +102,8 @@ public DebeziumEngine> debeziumEngine( public Supplier>> debeziumSupplier(DebeziumEngine> debeziumEngine) { return () -> this.eventSink.asFlux() - .doOnRequest(r -> debeziumExecutor.execute(debeziumEngine)) - .doOnTerminate(debeziumExecutor::shutdownNow); + .doOnRequest(r -> debeziumExecutor.execute(debeziumEngine)) + .doOnTerminate(debeziumExecutor::shutdownNow); } @Bean @@ -111,8 +112,7 @@ public Consumer> changeEventConsumer(DebeziumPropert DebeziumSupplierProperties supplierProperties) { return new ChangeEventConsumer(engineProperties.getPayloadFormat().contentType(), - supplierProperties.isCopyHeaders(), - this.eventSink); + supplierProperties.isCopyHeaders(), this.eventSink); } /** @@ -121,7 +121,9 @@ public Consumer> changeEventConsumer(DebeziumPropert private final class ChangeEventConsumer implements Consumer> { private final String contentType; + private final boolean copyHeaders; + private final Sinks.Many> eventSink; private ChangeEventConsumer(String contentType, boolean copyHeaders, Sinks.Many> eventSink) { @@ -140,10 +142,14 @@ public void accept(ChangeEvent changeEvent) { Object payload = changeEvent.value(); String destination = changeEvent.destination(); - // When the tombstone event is enabled, Debezium serializes the payload to null (e.g. empty payload) - // while the metadata information is carried through the headers (debezium_key). - // Note: Event for none flattened responses, when the debezium.properties.tombstones.on.delete=true - // (default), tombstones are generate by Debezium and handled by the code below. + // When the tombstone event is enabled, Debezium serializes the payload to + // null (e.g. empty payload) + // while the metadata information is carried through the headers + // (debezium_key). + // Note: Event for none flattened responses, when the + // debezium.properties.tombstones.on.delete=true + // (default), tombstones are generate by Debezium and handled by the code + // below. if (payload == null) { payload = DebeziumReactiveConsumerConfiguration.this.kafkaNull; } @@ -154,14 +160,12 @@ public void accept(ChangeEvent changeEvent) { return; } - MessageBuilder messageBuilder = MessageBuilder - .withPayload(payload) - .setHeader("debezium_key", key) - .setHeader("debezium_destination", destination) - .setHeader(MessageHeaders.CONTENT_TYPE, - (payload.equals(DebeziumReactiveConsumerConfiguration.this.kafkaNull)) - ? MimeTypeUtils.TEXT_PLAIN_VALUE - : this.contentType); + MessageBuilder messageBuilder = MessageBuilder.withPayload(payload) + .setHeader("debezium_key", key) + .setHeader("debezium_destination", destination) + .setHeader(MessageHeaders.CONTENT_TYPE, + (payload.equals(DebeziumReactiveConsumerConfiguration.this.kafkaNull)) + ? MimeTypeUtils.TEXT_PLAIN_VALUE : this.contentType); if (this.copyHeaders) { List> headers = changeEvent.headers(); @@ -176,6 +180,7 @@ public void accept(ChangeEvent changeEvent) { this.eventSink.tryEmitNext(messageBuilder.build()); } + } } diff --git a/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumSupplierProperties.java b/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumSupplierProperties.java index 55ab2018..4cb07e0e 100644 --- a/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumSupplierProperties.java +++ b/supplier/spring-debezium-supplier/src/main/java/org/springframework/cloud/fn/supplier/debezium/DebeziumSupplierProperties.java @@ -36,4 +36,5 @@ public boolean isCopyHeaders() { public void setCopyHeaders(boolean copyHeaders) { this.copyHeaders = copyHeaders; } + } diff --git a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumReactiveConsumerConfigurationTests.java b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumReactiveConsumerConfigurationTests.java index 72f89a8f..07c7ef97 100644 --- a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumReactiveConsumerConfigurationTests.java +++ b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumReactiveConsumerConfigurationTests.java @@ -35,8 +35,8 @@ public class DebeziumReactiveConsumerConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(DebeziumEngineBuilderAutoConfiguration.class, - DebeziumReactiveConsumerConfiguration.class)); + .withConfiguration(AutoConfigurations.of(DebeziumEngineBuilderAutoConfiguration.class, + DebeziumReactiveConsumerConfiguration.class)); // We have the debezium connectors on the classpath by default. diff --git a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumSupplierIntegrationTest.java b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumSupplierIntegrationTest.java index f19dc99e..357811cc 100644 --- a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumSupplierIntegrationTest.java +++ b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/DebeziumSupplierIntegrationTest.java @@ -37,58 +37,56 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { - "spring.cloud.function.definition=debeziumSupplier", - - // https://debezium.io/documentation/reference/transformations/event-flattening.html - "debezium.properties.transforms=unwrap", - "debezium.properties.transforms.unwrap.type=io.debezium.transforms.ExtractNewRecordState", - "debezium.properties.transforms.unwrap.drop.tombstones=true", - "debezium.properties.transforms.unwrap.delete.handling.mode=rewrite", - "debezium.properties.transforms.unwrap.add.fields=name,db,op,table", - - "debezium.properties.schema.history.internal=io.debezium.relational.history.MemorySchemaHistory", - "debezium.properties.offset.storage=org.apache.kafka.connect.storage.MemoryOffsetBackingStore", - - // Drop schema from the message payload. - "debezium.properties.key.converter.schemas.enable=false", - "debezium.properties.value.converter.schemas.enable=false", - - "debezium.properties.topic.prefix=my-topic", - "debezium.properties.name=my-connector", - "debezium.properties.database.server.id=85744", - "debezium.properties.connector.class=io.debezium.connector.mysql.MySqlConnector", - "debezium.properties.database.user=debezium", - "debezium.properties.database.password=dbz", - "debezium.properties.database.hostname=localhost", - - "debezium.properties.table.include.list=inventory.customers, inventory.addresses", - - // JdbcTemplate config. - "app.datasource.username=root", - "app.datasource.password=debezium", - "app.datasource.driver-class-name=com.mysql.cj.jdbc.Driver", - "app.datasource.type=com.zaxxer.hikari.HikariDataSource" -}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { "spring.cloud.function.definition=debeziumSupplier", + + // https://debezium.io/documentation/reference/transformations/event-flattening.html + "debezium.properties.transforms=unwrap", + "debezium.properties.transforms.unwrap.type=io.debezium.transforms.ExtractNewRecordState", + "debezium.properties.transforms.unwrap.drop.tombstones=true", + "debezium.properties.transforms.unwrap.delete.handling.mode=rewrite", + "debezium.properties.transforms.unwrap.add.fields=name,db,op,table", + + "debezium.properties.schema.history.internal=io.debezium.relational.history.MemorySchemaHistory", + "debezium.properties.offset.storage=org.apache.kafka.connect.storage.MemoryOffsetBackingStore", + + // Drop schema from the message payload. + "debezium.properties.key.converter.schemas.enable=false", + "debezium.properties.value.converter.schemas.enable=false", + + "debezium.properties.topic.prefix=my-topic", "debezium.properties.name=my-connector", + "debezium.properties.database.server.id=85744", + "debezium.properties.connector.class=io.debezium.connector.mysql.MySqlConnector", + "debezium.properties.database.user=debezium", "debezium.properties.database.password=dbz", + "debezium.properties.database.hostname=localhost", + + "debezium.properties.table.include.list=inventory.customers, inventory.addresses", + + // JdbcTemplate config. + "app.datasource.username=root", "app.datasource.password=debezium", + "app.datasource.driver-class-name=com.mysql.cj.jdbc.Driver", + "app.datasource.type=com.zaxxer.hikari.HikariDataSource" }) @Testcontainers public class DebeziumSupplierIntegrationTest { public static final String IMAGE_TAG = "2.3.3.Final"; + public static final String DEBEZIUM_EXAMPLE_MYSQL_IMAGE = "debezium/example-mysql:" + IMAGE_TAG; @Container static GenericContainer debeziumMySQL = new GenericContainer<>(DEBEZIUM_EXAMPLE_MYSQL_IMAGE) - .withEnv("MYSQL_ROOT_PASSWORD", "debezium") - .withEnv("MYSQL_USER", "mysqluser") - .withEnv("MYSQL_PASSWORD", "mysqlpw") - .withExposedPorts(3306); + .withEnv("MYSQL_ROOT_PASSWORD", "debezium") + .withEnv("MYSQL_USER", "mysqluser") + .withEnv("MYSQL_PASSWORD", "mysqlpw") + .withExposedPorts(3306); @DynamicPropertySource static void mysqlDbProperties(DynamicPropertyRegistry registry) { registry.add("debezium.properties.database.port", () -> debeziumMySQL.getMappedPort(3306)); registry.add("app.datasource.url", () -> String.format("jdbc:mysql://localhost:%d/%s?enabledTLSProtocols=TLSv1.2", - debeziumMySQL.getMappedPort(3306), "inventory")); // JdbcTemplate config. + debeziumMySQL.getMappedPort(3306), "inventory")); // JdbcTemplate + // config. } @Autowired @@ -109,51 +107,39 @@ void testDebeziumSupplier() { // https://github.com/debezium/container-images/blob/main/examples/mysql/2.3/inventory.sql // filtered by Customers and Addresses table. StepVerifier.create(messageFlux) - .expectNextCount(16) // Skip the DDL transaction logs. - - // Customers table - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":1001,\"first_name\":\"Sally\",\"last_name\":\"Thomas\",\"email\":\"sally.thomas@acme.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":1002,\"first_name\":\"George\",\"last_name\":\"Bailey\",\"email\":\"gbailey@foobar.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":1003,\"first_name\":\"Edward\",\"last_name\":\"Walker\",\"email\":\"ed@walker.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":1004,\"first_name\":\"Anne\",\"last_name\":\"Kretchmar\",\"email\":\"annek@noanswer.org\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) - - // NEW Customer Insert - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":1005,\"first_name\":\"Test666\",\"last_name\":\"Test666\",\"email\":\"Test666@spring.org\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) - - // Addresses table - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":10,\"customer_id\":1001,\"street\":\"3183 Moore Avenue\",\"city\":\"Euless\",\"state\":\"Texas\",\"zip\":\"76036\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":11,\"customer_id\":1001,\"street\":\"2389 Hidden Valley Road\",\"city\":\"Harrisburg\",\"state\":\"Pennsylvania\",\"zip\":\"17116\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":12,\"customer_id\":1002,\"street\":\"281 Riverside Drive\",\"city\":\"Augusta\",\"state\":\"Georgia\",\"zip\":\"30901\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":13,\"customer_id\":1003,\"street\":\"3787 Brownton Road\",\"city\":\"Columbus\",\"state\":\"Mississippi\",\"zip\":\"39701\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":14,\"customer_id\":1003,\"street\":\"2458 Lost Creek Road\",\"city\":\"Bethlehem\",\"state\":\"Pennsylvania\",\"zip\":\"18018\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":15,\"customer_id\":1003,\"street\":\"4800 Simpson Square\",\"city\":\"Hillsdale\",\"state\":\"Oklahoma\",\"zip\":\"73743\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .assertNext((message) -> assertThat(payloadString(message)) - .isEqualTo( - "{\"id\":16,\"customer_id\":1004,\"street\":\"1289 University Hill Road\",\"city\":\"Canehill\",\"state\":\"Arkansas\",\"zip\":\"72717\",\"type\":\"LIVING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) - .thenCancel() - .verify(); + .expectNextCount(16) // Skip the DDL transaction logs. + + // Customers table + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":1001,\"first_name\":\"Sally\",\"last_name\":\"Thomas\",\"email\":\"sally.thomas@acme.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":1002,\"first_name\":\"George\",\"last_name\":\"Bailey\",\"email\":\"gbailey@foobar.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":1003,\"first_name\":\"Edward\",\"last_name\":\"Walker\",\"email\":\"ed@walker.com\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":1004,\"first_name\":\"Anne\",\"last_name\":\"Kretchmar\",\"email\":\"annek@noanswer.org\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) + + // NEW Customer Insert + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":1005,\"first_name\":\"Test666\",\"last_name\":\"Test666\",\"email\":\"Test666@spring.org\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"customers\",\"__deleted\":\"false\"}")) + + // Addresses table + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":10,\"customer_id\":1001,\"street\":\"3183 Moore Avenue\",\"city\":\"Euless\",\"state\":\"Texas\",\"zip\":\"76036\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":11,\"customer_id\":1001,\"street\":\"2389 Hidden Valley Road\",\"city\":\"Harrisburg\",\"state\":\"Pennsylvania\",\"zip\":\"17116\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":12,\"customer_id\":1002,\"street\":\"281 Riverside Drive\",\"city\":\"Augusta\",\"state\":\"Georgia\",\"zip\":\"30901\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":13,\"customer_id\":1003,\"street\":\"3787 Brownton Road\",\"city\":\"Columbus\",\"state\":\"Mississippi\",\"zip\":\"39701\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":14,\"customer_id\":1003,\"street\":\"2458 Lost Creek Road\",\"city\":\"Bethlehem\",\"state\":\"Pennsylvania\",\"zip\":\"18018\",\"type\":\"SHIPPING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":15,\"customer_id\":1003,\"street\":\"4800 Simpson Square\",\"city\":\"Hillsdale\",\"state\":\"Oklahoma\",\"zip\":\"73743\",\"type\":\"BILLING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .assertNext((message) -> assertThat(payloadString(message)).isEqualTo( + "{\"id\":16,\"customer_id\":1004,\"street\":\"1289 University Hill Road\",\"city\":\"Canehill\",\"state\":\"Arkansas\",\"zip\":\"72717\",\"type\":\"LIVING\",\"__name\":\"my-topic\",\"__db\":\"inventory\",\"__op\":\"r\",\"__table\":\"addresses\",\"__deleted\":\"false\"}")) + .thenCancel() + .verify(); } @@ -162,8 +148,9 @@ private String payloadString(Message message) { } @SpringBootApplication(exclude = { MongoAutoConfiguration.class }) - @Import({TestJdbcTemplateConfiguration.class}) + @Import({ TestJdbcTemplateConfiguration.class }) static class DebeziumSupplierTestApplication { + } } diff --git a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/TestJdbcTemplateConfiguration.java b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/TestJdbcTemplateConfiguration.java index 9e7918ae..9a2bfa7a 100644 --- a/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/TestJdbcTemplateConfiguration.java +++ b/supplier/spring-debezium-supplier/src/test/java/org/springframework/cloud/fn/supplier/debezium/it/supplier/TestJdbcTemplateConfiguration.java @@ -28,11 +28,11 @@ import org.springframework.jdbc.core.JdbcTemplate; /** - * * @author Christian Tzolov */ @Configuration public class TestJdbcTemplateConfiguration { + @Bean public JdbcTemplate myJdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); @@ -47,9 +47,7 @@ public DataSourceProperties dataSourceProperties() { @Bean public HikariDataSource dataSource(DataSourceProperties dataSourceProperties) { - return dataSourceProperties.initializeDataSourceBuilder() - .type(HikariDataSource.class) - .build(); + return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); } } diff --git a/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierConfiguration.java b/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierConfiguration.java index da8dfc4c..9f33f6ca 100644 --- a/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierConfiguration.java +++ b/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierConfiguration.java @@ -55,7 +55,7 @@ * @author Soby Chacko */ @Configuration -@EnableConfigurationProperties({FileSupplierProperties.class, FileConsumerProperties.class}) +@EnableConfigurationProperties({ FileSupplierProperties.class, FileConsumerProperties.class }) public class FileSupplierConfiguration { private static final String METADATA_STORE_PREFIX = "local-file-system-metadata-"; @@ -70,7 +70,7 @@ public class FileSupplierConfiguration { private FileReadingMessageSource fileMessageSource; public FileSupplierConfiguration(FileSupplierProperties fileSupplierProperties, - FileConsumerProperties fileConsumerProperties) { + FileConsumerProperties fileConsumerProperties) { this.fileSupplierProperties = fileSupplierProperties; this.fileConsumerProperties = fileConsumerProperties; @@ -87,7 +87,8 @@ else if (this.fileSupplierProperties.getFilenameRegex() != null) { } if (this.fileSupplierProperties.isPreventDuplicates()) { - chainFilter.addFilter(new FileSystemPersistentAcceptOnceFileListFilter(metadataStore, METADATA_STORE_PREFIX)); + chainFilter + .addFilter(new FileSystemPersistentAcceptOnceFileListFilter(metadataStore, METADATA_STORE_PREFIX)); } return chainFilter; @@ -97,9 +98,8 @@ else if (this.fileSupplierProperties.getFilenameRegex() != null) { public FileInboundChannelAdapterSpec fileMessageSource(FileListFilter fileListFilter, @Nullable ComponentCustomizer fileInboundChannelAdapterSpecCustomizer) { - FileInboundChannelAdapterSpec adapterSpec = - Files.inboundAdapter(this.fileSupplierProperties.getDirectory()) - .filter(fileListFilter); + FileInboundChannelAdapterSpec adapterSpec = Files.inboundAdapter(this.fileSupplierProperties.getDirectory()) + .filter(fileListFilter); if (fileInboundChannelAdapterSpecCustomizer != null) { fileInboundChannelAdapterSpecCustomizer.customize(adapterSpec); } @@ -108,21 +108,20 @@ public FileInboundChannelAdapterSpec fileMessageSource(FileListFilter file @Bean public Flux> fileMessageFlux() { - return Mono.>create(monoSink -> - monoSink.onRequest(value -> - monoSink.success(this.fileMessageSource.receive()))) - .subscribeOn(Schedulers.boundedElastic()) - .repeatWhenEmpty(it -> it.delayElements(this.fileSupplierProperties.getDelayWhenEmpty())) - .repeat() - .doOnRequest(r -> this.fileMessageSource.start()); + return Mono + .>create( + monoSink -> monoSink.onRequest(value -> monoSink.success(this.fileMessageSource.receive()))) + .subscribeOn(Schedulers.boundedElastic()) + .repeatWhenEmpty(it -> it.delayElements(this.fileSupplierProperties.getDelayWhenEmpty())) + .repeat() + .doOnRequest(r -> this.fileMessageSource.start()); } @Bean @ConditionalOnExpression("environment['file.consumer.mode'] != 'ref'") public Publisher> fileReadingFlow() { IntegrationFlowBuilder flowBuilder = IntegrationFlow.from(fileMessageFlux()); - return FileUtils.enhanceFlowForReadingMode(flowBuilder, this.fileConsumerProperties) - .toReactivePublisher(); + return FileUtils.enhanceFlowForReadingMode(flowBuilder, this.fileConsumerProperties).toReactivePublisher(); } @Bean diff --git a/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierProperties.java b/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierProperties.java index d0870b64..72a8fba5 100644 --- a/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierProperties.java +++ b/supplier/spring-file-supplier/src/main/java/org/springframework/cloud/fn/supplier/file/FileSupplierProperties.java @@ -34,8 +34,7 @@ @Validated public class FileSupplierProperties { - private static final String DEFAULT_DIR = System.getProperty("java.io.tmpdir") + - File.separator + "file-supplier"; + private static final String DEFAULT_DIR = System.getProperty("java.io.tmpdir") + File.separator + "file-supplier"; /** * The directory to poll for new files. @@ -94,7 +93,7 @@ public void setFilenameRegex(Pattern filenameRegex) { this.filenameRegex = filenameRegex; } - //@AssertTrue(message = "filenamePattern and filenameRegex are mutually exclusive") + // @AssertTrue(message = "filenamePattern and filenameRegex are mutually exclusive") public boolean isExclusivePatterns() { return !(this.filenamePattern != null && this.filenameRegex != null); @@ -108,5 +107,4 @@ public void setDelayWhenEmpty(Duration delayWhenEmpty) { this.delayWhenEmpty = delayWhenEmpty; } - } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/DefaultFileSupplierTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/DefaultFileSupplierTests.java index ad11e887..67647331 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/DefaultFileSupplierTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/DefaultFileSupplierTests.java @@ -63,34 +63,20 @@ public void testBasicFlow() throws IOException { final Flux> messageFlux = fileSupplier.get(); - //create file after subscription + // create file after subscription Path tempFile = tempDir.resolve("test.file"); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo("first.file".getBytes()); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.FILENAME, "first.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.RELATIVE_PATH, "first.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.ORIGINAL_FILE, firstFile.toFile()); - } - ) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo("testing".getBytes()); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.FILENAME, "test.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.RELATIVE_PATH, "test.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.ORIGINAL_FILE, tempFile.toFile()); - }) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo("first.file".getBytes()); + assertThat(message.getHeaders()).containsEntry(FileHeaders.FILENAME, "first.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.RELATIVE_PATH, "first.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.ORIGINAL_FILE, firstFile.toFile()); + }).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo("testing".getBytes()); + assertThat(message.getHeaders()).containsEntry(FileHeaders.FILENAME, "test.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.RELATIVE_PATH, "test.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.ORIGINAL_FILE, tempFile.toFile()); + }).thenCancel().verifyLater(); Files.write(tempFile, "testing".getBytes()); stepVerifier.verify(); @@ -98,21 +84,24 @@ public void testBasicFlow() throws IOException { assertThat(this.metadataStore).isInstanceOf(JdbcMetadataStore.class); - List metadataStoreContent = - jdbcTemplate.queryForList("SELECT metadata_key FROM int_metadata_store", String.class); + List metadataStoreContent = jdbcTemplate.queryForList("SELECT metadata_key FROM int_metadata_store", + String.class); assertThat(metadataStoreContent).hasSize(2); assertThat(metadataStoreContent.get(0)).startsWith("local-file-system-metadata-"); assertThat(metadataStoreContent.get(0)).endsWith("first.file"); assertThat(metadataStoreContent.get(1)).endsWith("test.file"); - /* See AbstractFileSupplierTests.FileSupplierTestApplication.fileInboundChannelAdapterSpecCustomizer() - - through the ComponentCustomizer and @CustomizationAware on the FileSupplierConfiguration.fileMessageSource() - the provided customization is populated down to the bean under testing. - */ + /* + * See AbstractFileSupplierTests.FileSupplierTestApplication. + * fileInboundChannelAdapterSpecCustomizer() - through the ComponentCustomizer + * and @CustomizationAware on the FileSupplierConfiguration.fileMessageSource() + * the provided customization is populated down to the bean under testing. + */ assertThat(TestUtils.getPropertyValue(this.fileMessageSource, "watchEvents", FileReadingMessageSource.WatchEventType[].class)) - .isEqualTo(new FileReadingMessageSource.WatchEventType[]{ FileReadingMessageSource.WatchEventType.DELETE }); + .isEqualTo( + new FileReadingMessageSource.WatchEventType[] { FileReadingMessageSource.WatchEventType.DELETE }); } } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FileModeRefTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FileModeRefTests.java index 493705fb..08d55c83 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FileModeRefTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FileModeRefTests.java @@ -46,19 +46,12 @@ public void testBasicFlow() throws IOException { final Flux> messageFlux = fileSupplier.get(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(firstFile.toAbsolutePath().toFile()); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.FILENAME, "first.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.RELATIVE_PATH, "first.file"); - assertThat(message.getHeaders()) - .containsEntry(FileHeaders.ORIGINAL_FILE, firstFile.toFile()); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(firstFile.toAbsolutePath().toFile()); + assertThat(message.getHeaders()).containsEntry(FileHeaders.FILENAME, "first.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.RELATIVE_PATH, "first.file"); + assertThat(message.getHeaders()).containsEntry(FileHeaders.ORIGINAL_FILE, firstFile.toFile()); + }).thenCancel().verify(); } + } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithPatternTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithPatternTests.java index 7a7e1e61..926cf8db 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithPatternTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithPatternTests.java @@ -36,7 +36,7 @@ * @author Artem Bilan * @author Soby Chacko */ -@TestPropertySource(properties = {"file.consumer.mode=ref", "file.supplier.filenamePattern = *.txt"}) +@TestPropertySource(properties = { "file.consumer.mode=ref", "file.supplier.filenamePattern = *.txt" }) public class FilePayloadWithPatternTests extends AbstractFileSupplierTests { @Test @@ -51,18 +51,11 @@ public void testPattern() throws IOException { final Flux> messageFlux = fileSupplier.get(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(txtFile1.toAbsolutePath().toFile()); - } - ) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(txtFile2.toAbsolutePath().toFile()); - }) - .expectNoEvent(Duration.ofSeconds(1)) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(txtFile1.toAbsolutePath().toFile()); + }).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(txtFile2.toAbsolutePath().toFile()); + }).expectNoEvent(Duration.ofSeconds(1)).thenCancel().verify(); } + } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithRegexTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithRegexTests.java index 136ebf76..de9cb06c 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithRegexTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/FilePayloadWithRegexTests.java @@ -36,7 +36,7 @@ * @author Artem Bilan * @author Soby Chacko */ -@TestPropertySource(properties = {"file.consumer.mode=ref", "file.supplier.filenameRegex = t.*.txt"}) +@TestPropertySource(properties = { "file.consumer.mode=ref", "file.supplier.filenameRegex = t.*.txt" }) public class FilePayloadWithRegexTests extends AbstractFileSupplierTests { @Test @@ -51,18 +51,11 @@ public void testRegexPattern() throws IOException { final Flux> messageFlux = fileSupplier.get(); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(txtFile1.toAbsolutePath().toFile()); - } - ) - .expectNoEvent(Duration.ofSeconds(1)) - .expectNoEvent(Duration.ofSeconds(1)) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(txtFile1.toAbsolutePath().toFile()); + }).expectNoEvent(Duration.ofSeconds(1)).expectNoEvent(Duration.ofSeconds(1)).thenCancel().verifyLater(); stepVerifier.verify(); } + } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesAndMarkersAsJsonPayloadTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesAndMarkersAsJsonPayloadTests.java index bc34cd4b..9481eb0d 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesAndMarkersAsJsonPayloadTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesAndMarkersAsJsonPayloadTests.java @@ -38,7 +38,7 @@ * @author Artem Bilan * @author Soby Chacko */ -@TestPropertySource(properties = {"file.consumer.mode=lines", "file.consumer.withMarkers = true"}) +@TestPropertySource(properties = { "file.consumer.mode=lines", "file.consumer.withMarkers = true" }) public class LinesAndMarkersAsJsonPayloadTests extends AbstractFileSupplierTests { @Test @@ -49,35 +49,33 @@ public void testLinesWithMarkers() throws Exception { final Flux> messageFlux = fileSupplier.get(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - try { - final Object evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); - assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.START.name()); - } - catch (IOException e) { - // passt through - } - } - ) - .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("first line")) - .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("second line")) - .assertNext((message) -> { - try { - final Object fileMarker = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); - assertThat(fileMarker).isEqualTo(FileSplitter.FileMarker.Mark.END.name()); - FileSplitter.FileMarker fileMarker1 = JsonObjectMapperProvider.newInstance() - .fromJson(fileMarker, FileSplitter.FileMarker.class); - assertThat(FileSplitter.FileMarker.Mark.END).isEqualTo(fileMarker1.getMark()); - assertThat(firstFile.toAbsolutePath()).isEqualTo(fileMarker1.getFilePath()); - assertThat(fileMarker1.getLineCount()).isEqualTo(2); - } - catch (IOException e) { - // passt through - } - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + try { + final Object evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); + assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.START.name()); + } + catch (IOException e) { + // passt through + } + }) + .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("first line")) + .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("second line")) + .assertNext((message) -> { + try { + final Object fileMarker = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); + assertThat(fileMarker).isEqualTo(FileSplitter.FileMarker.Mark.END.name()); + FileSplitter.FileMarker fileMarker1 = JsonObjectMapperProvider.newInstance() + .fromJson(fileMarker, FileSplitter.FileMarker.class); + assertThat(FileSplitter.FileMarker.Mark.END).isEqualTo(fileMarker1.getMark()); + assertThat(firstFile.toAbsolutePath()).isEqualTo(fileMarker1.getFilePath()); + assertThat(fileMarker1.getLineCount()).isEqualTo(2); + } + catch (IOException e) { + // passt through + } + }) + .thenCancel() + .verify(); } + } diff --git a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesPayloadTests.java b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesPayloadTests.java index dd222c16..91fe26c1 100644 --- a/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesPayloadTests.java +++ b/supplier/spring-file-supplier/src/test/java/org/springframework/cloud/fn/supplier/file/LinesPayloadTests.java @@ -47,10 +47,11 @@ public void testLines() throws IOException { final Flux> messageFlux = fileSupplier.get(); StepVerifier.create(messageFlux) - .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("first line")) - .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("second line")) - .thenCancel() - .verify(); + .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("first line")) + .assertNext((message) -> assertThat(message.getPayload()).isEqualTo("second line")) + .thenCancel() + .verify(); } + } diff --git a/supplier/spring-ftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierConfiguration.java b/supplier/spring-ftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierConfiguration.java index 58870a23..5c8e8b1b 100644 --- a/supplier/spring-ftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierConfiguration.java +++ b/supplier/spring-ftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierConfiguration.java @@ -80,8 +80,7 @@ public class FtpSupplierConfiguration { private FtpInboundFileSynchronizingMessageSource ftpMessageSource; public FtpSupplierConfiguration(FtpSupplierProperties ftpSupplierProperties, - FileConsumerProperties fileConsumerProperties, - ConcurrentMetadataStore metadataStore, + FileConsumerProperties fileConsumerProperties, ConcurrentMetadataStore metadataStore, SessionFactory ftpSessionFactory) { this.ftpSupplierProperties = ftpSupplierProperties; @@ -95,13 +94,13 @@ public FtpInboundChannelAdapterSpec ftpMessageSource( @Nullable ComponentCustomizer ftpInboundChannelAdapterSpecCustomizer) { FtpInboundChannelAdapterSpec messageSourceBuilder = Ftp.inboundAdapter(ftpSessionFactory) - .preserveTimestamp(this.ftpSupplierProperties.isPreserveTimestamp()) - .remoteDirectory(this.ftpSupplierProperties.getRemoteDir()) - .remoteFileSeparator(this.ftpSupplierProperties.getRemoteFileSeparator()) - .localDirectory(this.ftpSupplierProperties.getLocalDir()) - .autoCreateLocalDirectory(this.ftpSupplierProperties.isAutoCreateLocalDir()) - .temporaryFileSuffix(this.ftpSupplierProperties.getTmpFileSuffix()) - .deleteRemoteFiles(this.ftpSupplierProperties.isDeleteRemoteFiles()); + .preserveTimestamp(this.ftpSupplierProperties.isPreserveTimestamp()) + .remoteDirectory(this.ftpSupplierProperties.getRemoteDir()) + .remoteFileSeparator(this.ftpSupplierProperties.getRemoteFileSeparator()) + .localDirectory(this.ftpSupplierProperties.getLocalDir()) + .autoCreateLocalDirectory(this.ftpSupplierProperties.isAutoCreateLocalDir()) + .temporaryFileSuffix(this.ftpSupplierProperties.getTmpFileSuffix()) + .deleteRemoteFiles(this.ftpSupplierProperties.isDeleteRemoteFiles()); ChainFileListFilter chainFileListFilter = new ChainFileListFilter<>(); @@ -125,20 +124,22 @@ else if (filenameRegex != null) { @Bean public Flux> ftpMessageFlux() { - return Mono.>create(monoSink -> - monoSink.onRequest(value -> - monoSink.success(this.ftpMessageSource.receive()))) - .subscribeOn(Schedulers.boundedElastic()) - .repeatWhenEmpty(it -> it.delayElements(this.ftpSupplierProperties.getDelayWhenEmpty())) - .repeat(); + return Mono + .>create( + monoSink -> monoSink.onRequest(value -> monoSink.success(this.ftpMessageSource.receive()))) + .subscribeOn(Schedulers.boundedElastic()) + .repeatWhenEmpty(it -> it.delayElements(this.ftpSupplierProperties.getDelayWhenEmpty())) + .repeat(); } @Bean @ConditionalOnExpression("environment['file.consumer.mode'] != 'ref'") public Publisher> ftpReadingFlow(FtpInboundFileSynchronizingMessageSource ftpMessageSource) { - return FileUtils.enhanceFlowForReadingMode(IntegrationFlow - .from(IntegrationReactiveUtils.messageSourceToFlux(ftpMessageSource)), fileConsumerProperties) - .toReactivePublisher(); + return FileUtils + .enhanceFlowForReadingMode( + IntegrationFlow.from(IntegrationReactiveUtils.messageSourceToFlux(ftpMessageSource)), + fileConsumerProperties) + .toReactivePublisher(); } @Bean diff --git a/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierPropertiesTests.java b/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierPropertiesTests.java index efe08e72..7bdd63b7 100644 --- a/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierPropertiesTests.java +++ b/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierPropertiesTests.java @@ -37,8 +37,7 @@ public class FtpSupplierPropertiesTests { @Test public void localDirCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.localDir:local") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.localDir:local").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -49,8 +48,7 @@ public void localDirCanBeCustomized() { @Test public void remoteDirCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.remoteDir:/remote") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.remoteDir:/remote").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -61,8 +59,7 @@ public void remoteDirCanBeCustomized() { @Test public void deleteRemoteFilesCanBeEnabled() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.deleteRemoteFiles:true") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.deleteRemoteFiles:true").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -73,8 +70,7 @@ public void deleteRemoteFilesCanBeEnabled() { @Test public void autoCreateLocalDirCanBeDisabled() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.autoCreateLocalDir:false") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.autoCreateLocalDir:false").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -85,8 +81,7 @@ public void autoCreateLocalDirCanBeDisabled() { @Test public void tmpFileSuffixCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.tmpFileSuffix:.foo") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.tmpFileSuffix:.foo").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -97,8 +92,7 @@ public void tmpFileSuffixCanBeCustomized() { @Test public void filenamePatternCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.filenamePattern:*.foo") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.filenamePattern:*.foo").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -109,8 +103,7 @@ public void filenamePatternCanBeCustomized() { @Test public void remoteFileSeparatorCanBeCustomized() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.remoteFileSeparator:\\") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.remoteFileSeparator:\\").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -118,12 +111,10 @@ public void remoteFileSeparatorCanBeCustomized() { context.close(); } - @Test public void preserveTimestampDirCanBeDisabled() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("ftp.supplier.preserveTimestamp:false") - .applyTo(context); + TestPropertyValues.of("ftp.supplier.preserveTimestamp:false").applyTo(context); context.register(Conf.class); context.refresh(); FtpSupplierProperties properties = context.getBean(FtpSupplierProperties.class); @@ -136,4 +127,5 @@ public void preserveTimestampDirCanBeDisabled() { static class Conf { } + } diff --git a/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierTests.java b/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierTests.java index e74e8bf8..c165406e 100644 --- a/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierTests.java +++ b/supplier/spring-ftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/ftp/FtpSupplierTests.java @@ -39,12 +39,8 @@ import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "ftp.factory.username = foo", - "ftp.factory.password = foo", - "file.consumer.mode = ref", - "ftp.factory.cacheSessions = true" - }) + properties = { "ftp.factory.username = foo", "ftp.factory.password = foo", "file.consumer.mode = ref", + "ftp.factory.cacheSessions = true" }) @DirtiesContext public class FtpSupplierTests extends FtpTestSupport { @@ -64,27 +60,23 @@ public class FtpSupplierTests extends FtpTestSupport { public void testSourceFileAsRef() { final Flux> messageFlux = ftpSupplier.get(); assertThat(this.sessionFactory).isInstanceOf(CachingSessionFactory.class); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))).isEqualTo( - new File(this.config.getLocalDir(), "ftpSource1.txt")); - } - ) - .assertNext((message) -> { - assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))).isEqualTo( - new File(this.config.getLocalDir(), "ftpSource2.txt")); - }) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) + .isEqualTo(new File(this.config.getLocalDir(), "ftpSource1.txt")); + }).assertNext((message) -> { + assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) + .isEqualTo(new File(this.config.getLocalDir(), "ftpSource2.txt")); + }).thenCancel().verifyLater(); stepVerifier.verify(); } @SpringBootApplication static class FtpSupplierTestApplication { - // These properties can be moved into the SpringBootApplication annotation, but providing here - // as a way to demonstrate how we can provide ConfigurationProperties as a bean in the application itself + // These properties can be moved into the SpringBootApplication annotation, but + // providing here + // as a way to demonstrate how we can provide ConfigurationProperties as a bean in + // the application itself // This way, it is less error-prone from typos. @Bean @Primary @@ -94,5 +86,7 @@ public FtpSupplierProperties ftpSupplierProperties() { ftpSupplierProperties.setFilenamePattern("*"); return ftpSupplierProperties; } + } + } diff --git a/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierConfiguration.java b/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierConfiguration.java index 2cbef92a..d9c10051 100644 --- a/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierConfiguration.java +++ b/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierConfiguration.java @@ -57,39 +57,33 @@ public HeaderMapper httpHeaderMapper(HttpSupplierProperties httpSup @Bean public Publisher> httpSupplierFlow(HttpSupplierProperties httpSupplierProperties, - HeaderMapper httpHeaderMapper, - ServerCodecConfigurer serverCodecConfigurer) { + HeaderMapper httpHeaderMapper, ServerCodecConfigurer serverCodecConfigurer) { - return IntegrationFlow.from( - WebFlux.inboundChannelAdapter(httpSupplierProperties.getPathPattern()) - .requestPayloadType(byte[].class) - .statusCodeExpression(new ValueExpression<>(HttpStatus.ACCEPTED)) - .headerMapper(httpHeaderMapper) - .codecConfigurer(serverCodecConfigurer) - .crossOrigin(crossOrigin -> - crossOrigin.origin(httpSupplierProperties.getCors().getAllowedOrigins()) - .allowedHeaders(httpSupplierProperties.getCors().getAllowedHeaders()) - .allowCredentials(httpSupplierProperties.getCors().getAllowCredentials())) - .autoStartup(false)) - .enrichHeaders((headers) -> - headers.headerFunction(MessageHeaders.CONTENT_TYPE, - (message) -> - (MediaType.APPLICATION_FORM_URLENCODED.equals( - message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MediaType.class))) - ? MediaType.APPLICATION_JSON - : null, - true)) - .toReactivePublisher(); + return IntegrationFlow + .from(WebFlux.inboundChannelAdapter(httpSupplierProperties.getPathPattern()) + .requestPayloadType(byte[].class) + .statusCodeExpression(new ValueExpression<>(HttpStatus.ACCEPTED)) + .headerMapper(httpHeaderMapper) + .codecConfigurer(serverCodecConfigurer) + .crossOrigin(crossOrigin -> crossOrigin.origin(httpSupplierProperties.getCors().getAllowedOrigins()) + .allowedHeaders(httpSupplierProperties.getCors().getAllowedHeaders()) + .allowCredentials(httpSupplierProperties.getCors().getAllowCredentials())) + .autoStartup(false)) + .enrichHeaders((headers) -> headers.headerFunction(MessageHeaders.CONTENT_TYPE, + (message) -> (MediaType.APPLICATION_FORM_URLENCODED + .equals(message.getHeaders().get(MessageHeaders.CONTENT_TYPE, MediaType.class))) + ? MediaType.APPLICATION_JSON : null, + true)) + .toReactivePublisher(); } @Bean - public Supplier>> httpSupplier( - Publisher> httpRequestPublisher, + public Supplier>> httpSupplier(Publisher> httpRequestPublisher, WebFluxInboundEndpoint webFluxInboundEndpoint) { return () -> Flux.from(httpRequestPublisher) - .doOnSubscribe((subscription) -> webFluxInboundEndpoint.start()) - .doOnTerminate(webFluxInboundEndpoint::stop); + .doOnSubscribe((subscription) -> webFluxInboundEndpoint.start()) + .doOnTerminate(webFluxInboundEndpoint::stop); } } diff --git a/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierProperties.java b/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierProperties.java index 76f5a345..5414704d 100644 --- a/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierProperties.java +++ b/supplier/spring-http-supplier/src/main/java/org/springframework/cloud/fn/supplier/http/HttpSupplierProperties.java @@ -40,7 +40,7 @@ public class HttpSupplierProperties { /** * Headers that will be mapped. */ - private String[] mappedRequestHeaders = {DefaultHttpHeaderMapper.HTTP_REQUEST_HEADER_NAME_PATTERN}; + private String[] mappedRequestHeaders = { DefaultHttpHeaderMapper.HTTP_REQUEST_HEADER_NAME_PATTERN }; /** * CORS properties. @@ -77,15 +77,16 @@ public static class Cors { /** * List of allowed origins, e.g. https://domain1.com. */ - private String[] allowedOrigins = {CorsConfiguration.ALL}; + private String[] allowedOrigins = { CorsConfiguration.ALL }; /** * List of request headers that can be used during the actual request. */ - private String[] allowedHeaders = {CorsConfiguration.ALL}; + private String[] allowedHeaders = { CorsConfiguration.ALL }; /** - * Whether the browser should include any cookies associated with the domain of the request being annotated. + * Whether the browser should include any cookies associated with the domain of + * the request being annotated. */ private Boolean allowCredentials; diff --git a/supplier/spring-http-supplier/src/test/java/org/springframework/cloud/fn/supplier/http/HttpSupplierApplicationTests.java b/supplier/spring-http-supplier/src/test/java/org/springframework/cloud/fn/supplier/http/HttpSupplierApplicationTests.java index 968e9cde..b2279408 100644 --- a/supplier/spring-http-supplier/src/test/java/org/springframework/cloud/fn/supplier/http/HttpSupplierApplicationTests.java +++ b/supplier/spring-http-supplier/src/test/java/org/springframework/cloud/fn/supplier/http/HttpSupplierApplicationTests.java @@ -55,15 +55,10 @@ * * @author Artem Bilan */ -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { - "server.ssl.key-store=classpath:test.jks", - "server.ssl.key-password=password", - "server.ssl.trust-store=classpath:test.jks", - "server.ssl.client-auth=want", - "spring.codec.max-in-memory-size=10MB" - }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { "server.ssl.key-store=classpath:test.jks", "server.ssl.key-password=password", + "server.ssl.trust-store=classpath:test.jks", "server.ssl.client-auth=want", + "spring.codec.max-in-memory-size=10MB" }) @DirtiesContext public class HttpSupplierApplicationTests { @@ -78,95 +73,69 @@ public class HttpSupplierApplicationTests { @Test public void testHttpSupplier() throws SSLException { - ServerCodecConfigurer codecConfigurer = - TestUtils.getPropertyValue(this.webFluxInboundEndpoint, "codecConfigurer", ServerCodecConfigurer.class); + ServerCodecConfigurer codecConfigurer = TestUtils.getPropertyValue(this.webFluxInboundEndpoint, + "codecConfigurer", ServerCodecConfigurer.class); final ServerCodecConfigurer.ServerDefaultCodecs serverDefaultCodecs = codecConfigurer.defaultCodecs(); assertThat(TestUtils.getPropertyValue(serverDefaultCodecs, "maxInMemorySize", Integer.class)) - .isEqualTo(1024 * 1024 * 10); + .isEqualTo(1024 * 1024 * 10); - AbstractJackson2Decoder jackson2JsonDecoder = - TestUtils.getPropertyValue(serverDefaultCodecs, "jackson2JsonDecoder", AbstractJackson2Decoder.class); + AbstractJackson2Decoder jackson2JsonDecoder = TestUtils.getPropertyValue(serverDefaultCodecs, + "jackson2JsonDecoder", AbstractJackson2Decoder.class); - assertThat(jackson2JsonDecoder).isNotNull() - .extracting("maxInMemorySize") - .isEqualTo(1024 * 1024 * 10); + assertThat(jackson2JsonDecoder).isNotNull().extracting("maxInMemorySize").isEqualTo(1024 * 1024 * 10); Flux> messageFlux = this.httpSupplier.get(); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> - assertThat(message) - .satisfies((msg) -> assertThat(msg) - .extracting(Message::getPayload) - .isEqualTo("test1".getBytes())) - .satisfies((msg) -> assertThat(msg.getHeaders()) - .containsEntry(MessageHeaders.CONTENT_TYPE, - new MediaType("text", "plain", StandardCharsets.UTF_8)) - .extractingByKey(HttpHeaders.REQUEST_URL).asString() - .startsWith("https://")) - ) - .assertNext((message) -> - assertThat(message) - .extracting(Message::getPayload) - .isEqualTo("{\"name\":\"test2\"}".getBytes())) - .assertNext((message) -> - assertThat(message) - .extracting(Message::getPayload) - .isEqualTo("{\"name\":\"test3\"}".getBytes())) - .assertNext((message) -> - assertThat(message) - .satisfies((msg) -> assertThat(msg) - .extracting(Message::getPayload) - .asInstanceOf(InstanceOfAssertFactories.MAP) - .isEmpty()) - .satisfies((msg) -> assertThat(msg.getHeaders()) - .doesNotContainKey(MessageHeaders.CONTENT_TYPE))) - .thenCancel() - .verifyLater(); - - SslContext sslContext = - SslContextBuilder.forClient() - .sslProvider(SslProvider.JDK) - .trustManager(InsecureTrustManagerFactory.INSTANCE) - .build(); - - HttpClient httpClient = - HttpClient.create() - .secure(sslSpec -> sslSpec.sslContext(sslContext)); - - WebClient webClient = - WebClient.builder() - .clientConnector(new ReactorClientHttpConnector(httpClient)) - .baseUrl("https://localhost:" + port) - .build(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux) + .assertNext((message) -> assertThat(message) + .satisfies((msg) -> assertThat(msg).extracting(Message::getPayload).isEqualTo("test1".getBytes())) + .satisfies((msg) -> assertThat(msg.getHeaders()) + .containsEntry(MessageHeaders.CONTENT_TYPE, new MediaType("text", "plain", StandardCharsets.UTF_8)) + .extractingByKey(HttpHeaders.REQUEST_URL) + .asString() + .startsWith("https://"))) + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .isEqualTo("{\"name\":\"test2\"}".getBytes())) + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .isEqualTo("{\"name\":\"test3\"}".getBytes())) + .assertNext((message) -> assertThat(message) + .satisfies((msg) -> assertThat(msg).extracting(Message::getPayload) + .asInstanceOf(InstanceOfAssertFactories.MAP) + .isEmpty()) + .satisfies((msg) -> assertThat(msg.getHeaders()).doesNotContainKey(MessageHeaders.CONTENT_TYPE))) + .thenCancel() + .verifyLater(); + + SslContext sslContext = SslContextBuilder.forClient() + .sslProvider(SslProvider.JDK) + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + + HttpClient httpClient = HttpClient.create().secure(sslSpec -> sslSpec.sslContext(sslContext)); + + WebClient webClient = WebClient.builder() + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .baseUrl("https://localhost:" + port) + .build(); + + webClient.post().uri("/").bodyValue("test1").retrieve().toBodilessEntity().block(Duration.ofSeconds(10)); webClient.post() - .uri("/") - .bodyValue("test1") - .retrieve() - .toBodilessEntity() - .block(Duration.ofSeconds(10)); + .uri("/") + .bodyValue(new TestPojo("test2")) + .retrieve() + .toBodilessEntity() + .block(Duration.ofSeconds(10)); webClient.post() - .uri("/") - .bodyValue(new TestPojo("test2")) - .retrieve() - .toBodilessEntity() - .block(Duration.ofSeconds(10)); + .uri("/") + .bodyValue(new TestPojo("test3")) + .retrieve() + .toBodilessEntity() + .block(Duration.ofSeconds(10)); - webClient.post() - .uri("/") - .bodyValue(new TestPojo("test3")) - .retrieve() - .toBodilessEntity() - .block(Duration.ofSeconds(10)); - - webClient.post().uri("/") - .retrieve() - .toBodilessEntity() - .block(Duration.ofSeconds(10)); + webClient.post().uri("/").retrieve().toBodilessEntity().block(Duration.ofSeconds(10)); stepVerifier.verify(); } diff --git a/supplier/spring-jdbc-supplier/src/main/java/org/springframework/cloud/fn/supplier/jdbc/JdbcSupplierConfiguration.java b/supplier/spring-jdbc-supplier/src/main/java/org/springframework/cloud/fn/supplier/jdbc/JdbcSupplierConfiguration.java index a10013b1..d4b40631 100644 --- a/supplier/spring-jdbc-supplier/src/main/java/org/springframework/cloud/fn/supplier/jdbc/JdbcSupplierConfiguration.java +++ b/supplier/spring-jdbc-supplier/src/main/java/org/springframework/cloud/fn/supplier/jdbc/JdbcSupplierConfiguration.java @@ -59,8 +59,8 @@ public JdbcSupplierConfiguration(JdbcSupplierProperties properties, DataSource d public MessageSource jdbcMessageSource( @Nullable ComponentCustomizer jdbcPollingChannelAdapterCustomizer) { - JdbcPollingChannelAdapter jdbcPollingChannelAdapter = - new JdbcPollingChannelAdapter(this.dataSource, this.properties.getQuery()); + JdbcPollingChannelAdapter jdbcPollingChannelAdapter = new JdbcPollingChannelAdapter(this.dataSource, + this.properties.getQuery()); jdbcPollingChannelAdapter.setMaxRows(this.properties.getMaxRows()); jdbcPollingChannelAdapter.setUpdateSql(this.properties.getUpdate()); if (jdbcPollingChannelAdapterCustomizer != null) { @@ -77,7 +77,9 @@ public Supplier>> splittedSupplier(MessageSource jdbcMes return () -> { Message received = jdbcMessageSource.receive(); if (received != null) { - return Flux.fromIterable(splitterFunction.apply(received)); // multiple Message> + return Flux.fromIterable(splitterFunction.apply(received)); // multiple + // Message> } else { return Flux.empty(); diff --git a/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/DefaultJdbcSupplierTests.java b/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/DefaultJdbcSupplierTests.java index 030d2c58..d56c0ccc 100644 --- a/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/DefaultJdbcSupplierTests.java +++ b/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/DefaultJdbcSupplierTests.java @@ -46,57 +46,47 @@ public class DefaultJdbcSupplierTests { JdbcTemplate jdbcTemplate; @Test - @SuppressWarnings({ "unchecked", "rawtypes"}) + @SuppressWarnings({ "unchecked", "rawtypes" }) void testExtraction() { final Flux> messageFlux = jdbcSupplier.get(); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> - assertThat(message) - .satisfies((msg) -> assertThat(msg) - .extracting(Message::getPayload) - .matches(o -> { - Map map = (Map) o; - return map.get("ID").equals(1L) && map.get("NAME").equals("Bob"); - }) - )) - .assertNext((message) -> - assertThat(message) - .satisfies((msg) -> assertThat(msg) - .extracting(Message::getPayload) - .matches(o -> { - Map map = (Map) o; - return map.get("ID").equals(2L) && map.get("NAME").equals("Jane"); - }) - )) - .assertNext((message) -> - assertThat(message) - .satisfies((msg) -> assertThat(msg) - .extracting(Message::getPayload) - .matches(o -> { - Map map = (Map) o; - return map.get("ID").equals(3L) && map.get("NAME").equals("John"); - }) - )) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux) + .assertNext((message) -> assertThat(message) + .satisfies((msg) -> assertThat(msg).extracting(Message::getPayload).matches(o -> { + Map map = (Map) o; + return map.get("ID").equals(1L) && map.get("NAME").equals("Bob"); + }))) + .assertNext((message) -> assertThat(message) + .satisfies((msg) -> assertThat(msg).extracting(Message::getPayload).matches(o -> { + Map map = (Map) o; + return map.get("ID").equals(2L) && map.get("NAME").equals("Jane"); + }))) + .assertNext((message) -> assertThat(message) + .satisfies((msg) -> assertThat(msg).extracting(Message::getPayload).matches(o -> { + Map map = (Map) o; + return map.get("ID").equals(3L) && map.get("NAME").equals("John"); + }))) + .thenCancel() + .verifyLater(); stepVerifier.verify(); } /* - The test to verify that DB is not initialized with Spring Integration DDL - (spring.integration.jdbc.initialize-schema=NEVER) what happens by default via IntegrationAutoConfiguration.IntegrationJdbcConfiguration. - This is not a functionality of this JDBC Supplier. + * The test to verify that DB is not initialized with Spring Integration DDL + * (spring.integration.jdbc.initialize-schema=NEVER) what happens by default via + * IntegrationAutoConfiguration.IntegrationJdbcConfiguration. This is not a + * functionality of this JDBC Supplier. */ @Test void verifyNoIntMessageGroupTable() { assertThatExceptionOfType(BadSqlGrammarException.class) - .isThrownBy(() -> this.jdbcTemplate.queryForList("SELECT * FROM INT_MESSAGE_GROUP")) - .havingCause() - .withMessageContaining("Table \"INT_MESSAGE_GROUP\" not found;"); + .isThrownBy(() -> this.jdbcTemplate.queryForList("SELECT * FROM INT_MESSAGE_GROUP")) + .havingCause() + .withMessageContaining("Table \"INT_MESSAGE_GROUP\" not found;"); } @SpringBootApplication static class JdbcSupplierTestApplication { + } + } diff --git a/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/NonSplitJdbcSupplierTests.java b/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/NonSplitJdbcSupplierTests.java index a6413e7b..9ed42f97 100644 --- a/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/NonSplitJdbcSupplierTests.java +++ b/supplier/spring-jdbc-supplier/src/test/java/org/springframework/cloud/fn/supplier/jdbc/NonSplitJdbcSupplierTests.java @@ -35,7 +35,7 @@ * @author Artem Bilan */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = {"jdbc.supplier.query=select id, name from test order by id", "jdbc.supplier.split=false"}) + properties = { "jdbc.supplier.query=select id, name from test order by id", "jdbc.supplier.split=false" }) @DirtiesContext public class NonSplitJdbcSupplierTests { @@ -61,5 +61,7 @@ void testExtraction() { @SpringBootApplication static class JdbcSupplierTestApplication { + } + } diff --git a/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierConfiguration.java b/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierConfiguration.java index d4e040a0..5375b5be 100644 --- a/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierConfiguration.java +++ b/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierConfiguration.java @@ -56,10 +56,8 @@ public Supplier>> jmsSupplier(Publisher> jmsPublisher } @Bean - public Publisher> jmsPublisher( - AbstractMessageListenerContainer container, - @Nullable ComponentCustomizer> - jmsMessageDrivenChannelAdapterSpecCustomizer) { + public Publisher> jmsPublisher(AbstractMessageListenerContainer container, + @Nullable ComponentCustomizer> jmsMessageDrivenChannelAdapterSpecCustomizer) { JmsMessageDrivenChannelAdapterSpec messageProducerSpec = Jms.messageDrivenChannelAdapter(container); @@ -67,8 +65,7 @@ public Publisher> jmsPublisher( jmsMessageDrivenChannelAdapterSpecCustomizer.customize(messageProducerSpec); } - return IntegrationFlow.from(messageProducerSpec) - .toReactivePublisher(true); + return IntegrationFlow.from(messageProducerSpec).toReactivePublisher(true); } @Bean @@ -89,7 +86,7 @@ public AbstractMessageListenerContainer container() { else { SimpleMessageListenerContainer smlc = new SimpleMessageListenerContainer(); smlc.setSessionTransacted(false); - if (listenerProperties != null && listenerProperties.getConcurrency() != null) { + if (listenerProperties != null && listenerProperties.getConcurrency() != null) { smlc.setConcurrentConsumers(listenerProperties.getConcurrency()); } container = smlc; @@ -103,8 +100,7 @@ public AbstractMessageListenerContainer container() { container.setMessageSelector(this.properties.getMessageSelector()); } container.setPubSubDomain(this.jmsProperties.isPubSubDomain()); - if (this.properties.getMessageSelector() != null - && listenerProperties.getAcknowledgeMode() != null) { + if (this.properties.getMessageSelector() != null && listenerProperties.getAcknowledgeMode() != null) { container.setSessionAcknowledgeMode(listenerProperties.getAcknowledgeMode().getMode()); } if (this.properties.getSubscriptionDurable() != null) { diff --git a/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierProperties.java b/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierProperties.java index 245f9cb8..e215fd63 100644 --- a/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierProperties.java +++ b/supplier/spring-jms-supplier/src/main/java/org/springframework/cloud/fn/supplier/jms/JmsSupplierProperties.java @@ -123,4 +123,5 @@ public boolean isSessionTransacted() { public void setSessionTransacted(boolean sessionTransacted) { this.sessionTransacted = sessionTransacted; } + } diff --git a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/AbstractJmsSupplierTests.java b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/AbstractJmsSupplierTests.java index 81d8675d..0acdfe9a 100644 --- a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/AbstractJmsSupplierTests.java +++ b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/AbstractJmsSupplierTests.java @@ -33,4 +33,5 @@ public class AbstractJmsSupplierTests { public static class JmsSupplierTestApplication { } + } diff --git a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated1Tests.java b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated1Tests.java index 4b38d482..147510d2 100644 --- a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated1Tests.java +++ b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated1Tests.java @@ -26,17 +26,11 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "jms.supplier.sessionTransacted = false", - "jms.supplier.destination = topic", - "jms.supplier.messageSelector = JMSCorrelationId=foo", - "jms.supplier.subscriptionDurable = false", - "jms.supplier.subscriptionShared = false", - "spring.jms.listener.acknowledgeMode = DUPS_OK", - "spring.jms.listener.concurrency = 3", - "spring.jms.listener.maxConcurrency = 4", - "spring.jms.pubSubDomain = true" -}) +@TestPropertySource(properties = { "jms.supplier.sessionTransacted = false", "jms.supplier.destination = topic", + "jms.supplier.messageSelector = JMSCorrelationId=foo", "jms.supplier.subscriptionDurable = false", + "jms.supplier.subscriptionShared = false", "spring.jms.listener.acknowledgeMode = DUPS_OK", + "spring.jms.listener.concurrency = 3", "spring.jms.listener.maxConcurrency = 4", + "spring.jms.pubSubDomain = true" }) public class PropertiesPopulated1Tests extends AbstractJmsSupplierTests { @Test @@ -44,7 +38,8 @@ public void test() { AbstractMessageListenerContainer container = TestUtils.getPropertyValue(this.endpoint, "listenerContainer", AbstractMessageListenerContainer.class); assertThat(container).isInstanceOf(SimpleMessageListenerContainer.class); - assertThat(TestUtils.getPropertyValue(container, "sessionAcknowledgeMode")).isEqualTo(Session.DUPS_OK_ACKNOWLEDGE); + assertThat(TestUtils.getPropertyValue(container, "sessionAcknowledgeMode")) + .isEqualTo(Session.DUPS_OK_ACKNOWLEDGE); assertThat(TestUtils.getPropertyValue(container, "sessionTransacted", Boolean.class)).isFalse(); assertThat(TestUtils.getPropertyValue(container, "clientId")).isNull(); assertThat(TestUtils.getPropertyValue(container, "destination")).isEqualTo("topic"); @@ -54,4 +49,5 @@ public void test() { assertThat(TestUtils.getPropertyValue(container, "concurrentConsumers")).isEqualTo(3); assertThat(TestUtils.getPropertyValue(container, "pubSubDomain", Boolean.class)).isTrue(); } + } diff --git a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated2Tests.java b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated2Tests.java index c9b7e0cb..33e20107 100644 --- a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated2Tests.java +++ b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated2Tests.java @@ -26,13 +26,11 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "jms.supplier.sessionTransacted = true", "jms.supplier.clientId = client", "jms.supplier.destination = topic", - "jms.supplier.subscriptionName = subName", "jms.supplier.subscriptionDurable = true", - "jms.supplier.subscriptionShared = false", "spring.jms.listener.acknowledgeMode = AUTO", - "spring.jms.listener.concurrency = 3", - "spring.jms.listener.maxConcurrency = 4" -}) +@TestPropertySource(properties = { "jms.supplier.sessionTransacted = true", "jms.supplier.clientId = client", + "jms.supplier.destination = topic", "jms.supplier.subscriptionName = subName", + "jms.supplier.subscriptionDurable = true", "jms.supplier.subscriptionShared = false", + "spring.jms.listener.acknowledgeMode = AUTO", "spring.jms.listener.concurrency = 3", + "spring.jms.listener.maxConcurrency = 4" }) public class PropertiesPopulated2Tests extends AbstractJmsSupplierTests { @Test @@ -53,4 +51,5 @@ public void test() { assertThat(TestUtils.getPropertyValue(container, "maxConcurrentConsumers")).isEqualTo(4); assertThat(TestUtils.getPropertyValue(container, "pubSubDomain", Boolean.class)).isTrue(); } + } diff --git a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated3Tests.java b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated3Tests.java index d1b826e9..e62605ce 100644 --- a/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated3Tests.java +++ b/supplier/spring-jms-supplier/src/test/java/org/springframework/cloud/fn/supplier/jms/PropertiesPopulated3Tests.java @@ -33,14 +33,11 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "jms.supplier.sessionTransacted = true", "jms.supplier.destination = jmssource.test.queue", - "jms.supplier.messageSelector = JMSCorrelationId=foo", +@TestPropertySource(properties = { "jms.supplier.sessionTransacted = true", + "jms.supplier.destination = jmssource.test.queue", "jms.supplier.messageSelector = JMSCorrelationId=foo", "jms.supplier.subscriptionDurable = false", "jms.supplier.subscriptionShared = false", - "spring.jms.listener.acknowledgeMode = AUTO", - "spring.jms.listener.concurrency = 3", - "spring.jms.listener.maxConcurrency = 4", - "spring.jms.pubSubDomain = false" }) + "spring.jms.listener.acknowledgeMode = AUTO", "spring.jms.listener.concurrency = 3", + "spring.jms.listener.maxConcurrency = 4", "spring.jms.pubSubDomain = false" }) public class PropertiesPopulated3Tests extends AbstractJmsSupplierTests { @Autowired @@ -66,17 +63,13 @@ public void test() throws Exception { final Flux> messageFlux = jmsSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo("Hello, world!"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo("Hello, world!"); + }).thenCancel().verifyLater(); template.convertAndSend("jmssource.test.queue", "Hello, world!"); stepVerifier.verify(); } + } diff --git a/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierConfiguration.java b/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierConfiguration.java index e55aceeb..10804af7 100644 --- a/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierConfiguration.java +++ b/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierConfiguration.java @@ -47,11 +47,10 @@ import org.springframework.messaging.Message; /** - * An auto-configuration for Kafka Supplier. - * Uses a {@link KafkaMessageDrivenChannelAdapterSpec} to consumer records from Kafka topic. + * An auto-configuration for Kafka Supplier. Uses a + * {@link KafkaMessageDrivenChannelAdapterSpec} to consumer records from Kafka topic. * * @author Artem Bilan - * * @since 4.0 */ @AutoConfiguration(after = KafkaAutoConfiguration.class) @@ -67,8 +66,7 @@ public Supplier>> kafkaSupplier(Publisher> kafkaSuppl public Publisher> kafkaSupplierPublisher( KafkaMessageDrivenChannelAdapterSpec kafkaMessageDrivenChannelAdapterSpec) { - return IntegrationFlow.from(kafkaMessageDrivenChannelAdapterSpec) - .toReactivePublisher(true); + return IntegrationFlow.from(kafkaMessageDrivenChannelAdapterSpec).toReactivePublisher(true); } @Bean @@ -90,22 +88,20 @@ public Publisher> kafkaSupplierPublisher( container = kafkaListenerContainerFactory.createContainer(kafkaSupplierProperties.getTopics()); } - KafkaMessageDrivenChannelAdapter.ListenerMode listenerMode = - Boolean.TRUE.equals(kafkaListenerContainerFactory.isBatchListener()) - ? KafkaMessageDrivenChannelAdapter.ListenerMode.batch + KafkaMessageDrivenChannelAdapter.ListenerMode listenerMode = Boolean.TRUE.equals( + kafkaListenerContainerFactory.isBatchListener()) ? KafkaMessageDrivenChannelAdapter.ListenerMode.batch : KafkaMessageDrivenChannelAdapter.ListenerMode.record; - KafkaMessageDrivenChannelAdapterSpec kafkaMessageDrivenChannelAdapterSpec = - Kafka.messageDrivenChannelAdapter(container, listenerMode) - .ackDiscarded(kafkaSupplierProperties.isAckDiscarded()) - .autoStartup(false); + KafkaMessageDrivenChannelAdapterSpec kafkaMessageDrivenChannelAdapterSpec = Kafka + .messageDrivenChannelAdapter(container, listenerMode) + .ackDiscarded(kafkaSupplierProperties.isAckDiscarded()) + .autoStartup(false); RecordMessageConverter recordMessageConverter = recordMessageConverterProvider.getIfUnique(); if (KafkaMessageDrivenChannelAdapter.ListenerMode.batch.equals(listenerMode)) { - BatchMessageConverter batchMessageConverter = - batchMessageConverterProvider.getIfUnique( - () -> new BatchMessagingMessageConverter(recordMessageConverter)); + BatchMessageConverter batchMessageConverter = batchMessageConverterProvider + .getIfUnique(() -> new BatchMessagingMessageConverter(recordMessageConverter)); kafkaMessageDrivenChannelAdapterSpec.batchMessageConverter(batchMessageConverter); } @@ -130,10 +126,8 @@ RecordFilterStrategy recordFilterStrategy(KafkaSupplierPropertie StandardEvaluationContext evaluationContext = IntegrationContextUtils.getEvaluationContext(beanFactory); - return consumerRecord -> - Boolean.TRUE.equals( - kafkaSupplierProperties.getRecordFilter() - .getValue(evaluationContext, consumerRecord, Boolean.class)); + return consumerRecord -> Boolean.TRUE.equals( + kafkaSupplierProperties.getRecordFilter().getValue(evaluationContext, consumerRecord, Boolean.class)); } } diff --git a/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierProperties.java b/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierProperties.java index 6a509ac6..c5ce1a26 100644 --- a/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierProperties.java +++ b/supplier/spring-kafka-supplier/src/main/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierProperties.java @@ -25,7 +25,6 @@ * Auto-configuration properties for the Kafka Supplier. * * @author Artem Bilan - * * @since 4.0 */ @ConfigurationProperties("kafka.supplier") @@ -47,7 +46,8 @@ public class KafkaSupplierProperties { private boolean ackDiscarded; /** - * SpEL expression for 'RecordFilterStrategy' with a 'ConsumerRecord' as a root object. + * SpEL expression for 'RecordFilterStrategy' with a 'ConsumerRecord' as a root + * object. */ Expression recordFilter; diff --git a/supplier/spring-kafka-supplier/src/test/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierTests.java b/supplier/spring-kafka-supplier/src/test/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierTests.java index 68c3585c..49d1c1fe 100644 --- a/supplier/spring-kafka-supplier/src/test/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierTests.java +++ b/supplier/spring-kafka-supplier/src/test/java/org/springframework/cloud/fn/supplier/kafka/KafkaSupplierTests.java @@ -36,75 +36,61 @@ /** * @author Artem Bilan - * * @since 4.0 */ @EmbeddedKafka(partitions = 1, controlledShutdown = true) public class KafkaSupplierTests { final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - IntegrationAutoConfiguration.class, - KafkaAutoConfiguration.class, - KafkaSupplierConfiguration.class, - SpelExpressionConverterConfiguration.class)); + .withConfiguration(AutoConfigurations.of(IntegrationAutoConfiguration.class, KafkaAutoConfiguration.class, + KafkaSupplierConfiguration.class, SpelExpressionConverterConfiguration.class)); @Test void recordModeAndTopicPattern() { - this.contextRunner.withPropertyValues( - "spring.kafka.template.defaultTopic=defaultTopic", - "spring.kafka.consumer.group-id=test-group1", - "spring.kafka.consumer.auto-offset-reset=earliest", - "kafka.supplier.topicPattern=default.+") - .run((context) -> { - String testPayload1 = "test data #1"; - String testPayload2 = "test data #2"; - - KafkaTemplate kafkaTemplate = getKafkaTemplate(context); - kafkaTemplate.sendDefault(testPayload1); - kafkaTemplate.sendDefault(testPayload2); - kafkaTemplate.flush(); - - Supplier>> kafkaSupplier = getKafkaSupplier(context); - StepVerifier.create( - kafkaSupplier.get() - .map(Message::getPayload) - .cast(String.class)) - .expectNext(testPayload1, testPayload2) - .thenCancel() - .verify(Duration.ofSeconds(30)); - }); + this.contextRunner + .withPropertyValues("spring.kafka.template.defaultTopic=defaultTopic", + "spring.kafka.consumer.group-id=test-group1", "spring.kafka.consumer.auto-offset-reset=earliest", + "kafka.supplier.topicPattern=default.+") + .run((context) -> { + String testPayload1 = "test data #1"; + String testPayload2 = "test data #2"; + + KafkaTemplate kafkaTemplate = getKafkaTemplate(context); + kafkaTemplate.sendDefault(testPayload1); + kafkaTemplate.sendDefault(testPayload2); + kafkaTemplate.flush(); + + Supplier>> kafkaSupplier = getKafkaSupplier(context); + StepVerifier.create(kafkaSupplier.get().map(Message::getPayload).cast(String.class)) + .expectNext(testPayload1, testPayload2) + .thenCancel() + .verify(Duration.ofSeconds(30)); + }); } @Test void batchMode() { - this.contextRunner.withPropertyValues( - "spring.kafka.consumer.group-id=test-group2", - "spring.kafka.consumer.auto-offset-reset=earliest", - "spring.kafka.listener.type=BATCH", - "kafka.supplier.topics=testTopic1,testTopic2", - "kafka.supplier.recordFilter=value() == 'test data #2'") - .run((context) -> { - String testPayload1 = "test data #1"; - String testPayload2 = "test data #2"; - - Supplier>> kafkaSupplier = getKafkaSupplier(context); - StepVerifier stepVerifier = StepVerifier.create( - kafkaSupplier.get() - .map(Message::getPayload) - .cast(List.class)) - .expectNext(List.of(testPayload1)) - .thenCancel() - .verifyLater(); - - - KafkaTemplate kafkaTemplate = getKafkaTemplate(context); - kafkaTemplate.send("testTopic1", testPayload1); - kafkaTemplate.send("testTopic2", testPayload2); - kafkaTemplate.flush(); - - stepVerifier.verify(Duration.ofSeconds(30)); - }); + this.contextRunner.withPropertyValues("spring.kafka.consumer.group-id=test-group2", + "spring.kafka.consumer.auto-offset-reset=earliest", "spring.kafka.listener.type=BATCH", + "kafka.supplier.topics=testTopic1,testTopic2", "kafka.supplier.recordFilter=value() == 'test data #2'") + .run((context) -> { + String testPayload1 = "test data #1"; + String testPayload2 = "test data #2"; + + Supplier>> kafkaSupplier = getKafkaSupplier(context); + StepVerifier stepVerifier = StepVerifier + .create(kafkaSupplier.get().map(Message::getPayload).cast(List.class)) + .expectNext(List.of(testPayload1)) + .thenCancel() + .verifyLater(); + + KafkaTemplate kafkaTemplate = getKafkaTemplate(context); + kafkaTemplate.send("testTopic1", testPayload1); + kafkaTemplate.send("testTopic2", testPayload2); + kafkaTemplate.flush(); + + stepVerifier.verify(Duration.ofSeconds(30)); + }); } @SuppressWarnings("unchecked") diff --git a/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java b/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java index 35ba4e82..6bbaa5ea 100644 --- a/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java +++ b/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java @@ -58,7 +58,6 @@ @EnableConfigurationProperties(MailSupplierProperties.class) public class MailSupplierConfiguration { - final private MailSupplierProperties properties; public MailSupplierConfiguration(MailSupplierProperties properties) { @@ -69,13 +68,12 @@ public MailSupplierConfiguration(MailSupplierProperties properties) { public Publisher> mailInboundFlow(MessageProducerSupport messageProducer) { return IntegrationFlow.from(messageProducer) - .transform(Mail.toStringTransformer(this.properties.getCharset())) - .enrichHeaders(h -> h - .defaultOverwrite(true) - .header(MailHeaders.TO, arrayToListProcessor(MailHeaders.TO)) - .header(MailHeaders.CC, arrayToListProcessor(MailHeaders.CC)) - .header(MailHeaders.BCC, arrayToListProcessor(MailHeaders.BCC))) - .toReactivePublisher(true); + .transform(Mail.toStringTransformer(this.properties.getCharset())) + .enrichHeaders(h -> h.defaultOverwrite(true) + .header(MailHeaders.TO, arrayToListProcessor(MailHeaders.TO)) + .header(MailHeaders.CC, arrayToListProcessor(MailHeaders.CC)) + .header(MailHeaders.BCC, arrayToListProcessor(MailHeaders.BCC))) + .toReactivePublisher(true); } @Bean @@ -101,11 +99,11 @@ public List processMessage(Message message) { URLName urlName = this.properties.getUrl(); ImapIdleChannelAdapterSpec imapIdleChannelAdapterSpec = Mail.imapIdleAdapter(urlName.toString()) - .shouldDeleteMessages(this.properties.isDelete()) - .userFlag(this.properties.getUserFlag()) - .javaMailProperties(getJavaMailProperties(urlName)) - .selectorExpression(this.properties.getExpression()) - .shouldMarkMessagesAsRead(this.properties.isMarkAsRead()); + .shouldDeleteMessages(this.properties.isDelete()) + .userFlag(this.properties.getUserFlag()) + .javaMailProperties(getJavaMailProperties(urlName)) + .selectorExpression(this.properties.getExpression()) + .shouldMarkMessagesAsRead(this.properties.isMarkAsRead()); if (imapIdleChannelAdapterSpecCustomizer != null) { imapIdleChannelAdapterSpecCustomizer.customize(imapIdleChannelAdapterSpec); @@ -116,8 +114,7 @@ public List processMessage(Message message) { @Bean @ConditionalOnProperty(value = "mail.supplier.idle-imap", matchIfMissing = true, havingValue = "false") MessageSourceSpec mailMessageSource( - @Nullable ComponentCustomizer> - mailInboundChannelAdapterSpecCustomizer) { + @Nullable ComponentCustomizer> mailInboundChannelAdapterSpecCustomizer) { MailInboundChannelAdapterSpec adapterSpec; URLName urlName = this.properties.getUrl(); @@ -131,13 +128,12 @@ public List processMessage(Message message) { adapterSpec = getPop3ChannelAdapterSpec(urlName); break; default: - throw new IllegalArgumentException( - "Unsupported mail protocol: " + urlName.getProtocol()); + throw new IllegalArgumentException("Unsupported mail protocol: " + urlName.getProtocol()); } adapterSpec.javaMailProperties(getJavaMailProperties(urlName)) - .userFlag(this.properties.getUserFlag()) - .selectorExpression(this.properties.getExpression()) - .shouldDeleteMessages(this.properties.isDelete()); + .userFlag(this.properties.getUserFlag()) + .selectorExpression(this.properties.getExpression()) + .shouldDeleteMessages(this.properties.isDelete()); if (mailInboundChannelAdapterSpecCustomizer != null) { mailInboundChannelAdapterSpecCustomizer.customize(adapterSpec); @@ -169,8 +165,7 @@ private MailInboundChannelAdapterSpec getPop3ChannelAdapterSpec(URLName urlName) */ @SuppressWarnings("rawtypes") private MailInboundChannelAdapterSpec getImapChannelAdapterSpec(URLName urlName) { - return Mail.imapInboundAdapter(urlName.toString()) - .shouldMarkMessagesAsRead(this.properties.isMarkAsRead()); + return Mail.imapInboundAdapter(urlName.toString()).shouldMarkMessagesAsRead(this.properties.isMarkAsRead()); } private Properties getJavaMailProperties(URLName urlName) { diff --git a/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierProperties.java b/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierProperties.java index 05ccde23..a6972644 100644 --- a/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierProperties.java +++ b/supplier/spring-mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierProperties.java @@ -182,4 +182,5 @@ public String getUserFlag() { public void setUserFlag(String userFlag) { this.userFlag = userFlag; } + } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java index af5362cd..264faa0b 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java @@ -35,11 +35,9 @@ import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { - "mail.supplier.mark-as-read=true", - "mail.supplier.delete=false", - "mail.supplier.user-flag=testSIUserFlag", - "mail.supplier.java-mail-properties=mail.imap.socketFactory.fallback=true\\n mail.store.protocol=imap\\n mail.debug=true"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { "mail.supplier.mark-as-read=true", + "mail.supplier.delete=false", "mail.supplier.user-flag=testSIUserFlag", + "mail.supplier.java-mail-properties=mail.imap.socketFactory.fallback=true\\n mail.store.protocol=imap\\n mail.debug=true" }) @DirtiesContext public abstract class AbstractMailSupplierTests { @@ -54,7 +52,8 @@ public abstract class AbstractMailSupplierTests { protected StandardIntegrationFlow integrationFlow; protected void sendMessage(String subject, String body) { - mailUser.deliver(GreenMailUtil.createTextEmail("bar@bax", "test@test", subject, body, mailServer.getSmtp().getServerSetup())); + mailUser.deliver(GreenMailUtil.createTextEmail("bar@bax", "test@test", subject, body, + mailServer.getSmtp().getServerSetup())); } @BeforeAll @@ -66,7 +65,7 @@ public static void setup() { ServerSetup smtp = ServerSetupTest.SMTP.dynamicPort(); smtp.setServerStartupTimeout(10000); - mailServer = new GreenMail(new ServerSetup[] {imap, pop3, smtp}); + mailServer = new GreenMail(new ServerSetup[] { imap, pop3, smtp }); mailUser = mailServer.setUser("user", "pw"); mailServer.start(); } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java index 63b89f1a..05615d96 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java @@ -28,15 +28,13 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX", - "mail.supplier.charset=cp1251"}) +@TestPropertySource(properties = { "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX", + "mail.supplier.charset=cp1251" }) public class ImapFailTests extends AbstractMailSupplierTests { @Autowired protected MailToStringTransformer mailToStringTransformer; - @Test public void testSimpleTest() { // given @@ -45,12 +43,9 @@ public void testSimpleTest() { final Flux> messageFlux = mailSupplier.get(); // then assertThat(TestUtils.getPropertyValue(mailToStringTransformer, "charset").equals("cp1251")).isTrue(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); + }).thenCancel().verify(); } + } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java index 1ed7aec3..96ee190b 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java @@ -25,9 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "mail.supplier.idle-imap=true", - "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX"}) +@TestPropertySource(properties = { "mail.supplier.idle-imap=true", + "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX" }) public class ImapIdlePassTests extends AbstractMailSupplierTests { @Test @@ -37,13 +36,10 @@ public void testSimpleTest() { // when final Flux> messageFlux = mailSupplier.get(); // then - StepVerifier.create(messageFlux) - .assertNext((message) -> { - System.out.println("Message:" + message); - assertThat(((String) message.getPayload())).isEqualTo("foo"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + System.out.println("Message:" + message); + assertThat(((String) message.getPayload())).isEqualTo("foo"); + }).thenCancel().verify(); } + } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java index 97cc2a3f..289a5397 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java @@ -37,31 +37,31 @@ @TestPropertySource(properties = "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX") public class ImapPassTests extends AbstractMailSupplierTests { - @Test public void testSimpleTest() throws UnsupportedEncodingException, MessagingException { // given - MimeMessage mailMessage = GreenMailUtil.createTextEmail("bar@foo", "test@test", "test", "foo", mailServer.getSmtp().getServerSetup()); - mailMessage.addRecipients(jakarta.mail.Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("foo@bar", "Foo")}); - mailMessage.addRecipients(jakarta.mail.Message.RecipientType.CC, new InternetAddress[]{new InternetAddress("a@b"), new InternetAddress("c@d")}); - mailMessage.addRecipients(jakarta.mail.Message.RecipientType.BCC, new InternetAddress[]{new InternetAddress("e@f"), new InternetAddress("g@h")}); + MimeMessage mailMessage = GreenMailUtil.createTextEmail("bar@foo", "test@test", "test", "foo", + mailServer.getSmtp().getServerSetup()); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.TO, + new InternetAddress[] { new InternetAddress("foo@bar", "Foo") }); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.CC, + new InternetAddress[] { new InternetAddress("a@b"), new InternetAddress("c@d") }); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.BCC, + new InternetAddress[] { new InternetAddress("e@f"), new InternetAddress("g@h") }); mailUser.deliver(mailMessage); // when final Flux> messageFlux = mailSupplier.get(); // then - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload())).isEqualTo("foo"); - MessageHeaders headers = message.getHeaders(); - assertThat(headers.get(MailHeaders.TO)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.CC)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.BCC)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.TO).toString()).isEqualTo("[bar@foo, Foo ]"); - assertThat(headers.get(MailHeaders.CC).toString()).isEqualTo("[a@b, c@d]"); - assertThat(headers.get(MailHeaders.BCC).toString()).isEqualTo("[e@f, g@h]"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((String) message.getPayload())).isEqualTo("foo"); + MessageHeaders headers = message.getHeaders(); + assertThat(headers.get(MailHeaders.TO)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.CC)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.BCC)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.TO).toString()).isEqualTo("[bar@foo, Foo ]"); + assertThat(headers.get(MailHeaders.CC).toString()).isEqualTo("[a@b, c@d]"); + assertThat(headers.get(MailHeaders.BCC).toString()).isEqualTo("[e@f, g@h]"); + }).thenCancel().verify(); } + } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java index 52a17c88..aca6d806 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java @@ -28,7 +28,6 @@ @TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.pop3.port}/INBOX") public class Pop3FailTests extends AbstractMailSupplierTests { - @Test public void testSimpleTest() { // given @@ -36,13 +35,9 @@ public void testSimpleTest() { // when final Flux> messageFlux = mailSupplier.get(); // then - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); + }).thenCancel().verify(); } } diff --git a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java index fb1166d7..0e263122 100644 --- a/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java +++ b/supplier/spring-mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java @@ -28,20 +28,16 @@ @TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.pop3.port}/INBOX") public class Pop3PassTests extends AbstractMailSupplierTests { - @Test public void testSimpleTest() { // given sendMessage("test", "foo"); final Flux> messageFlux = mailSupplier.get(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload())).contains("foo"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((String) message.getPayload())).contains("foo"); + }).thenCancel().verify(); } + } diff --git a/supplier/spring-mongodb-supplier/src/main/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierConfiguration.java b/supplier/spring-mongodb-supplier/src/main/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierConfiguration.java index f63ae1b0..77bbadef 100644 --- a/supplier/spring-mongodb-supplier/src/main/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierConfiguration.java +++ b/supplier/spring-mongodb-supplier/src/main/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierConfiguration.java @@ -38,9 +38,9 @@ import org.springframework.messaging.Message; /** - * A configuration for MongoDB Source applications. Produces - * {@link MongoDbMessageSource} which polls collection with the query after startup - * according to the polling properties. + * A configuration for MongoDB Source applications. Produces {@link MongoDbMessageSource} + * which polls collection with the query after startup according to the polling + * properties. * * @author Adam Zwickey * @author Artem Bilan @@ -69,7 +69,9 @@ public Supplier>> splittedSupplier(MongoDbMessageSource mongoDbS return () -> { Message received = mongoDbSource.receive(); if (received != null) { - return Flux.fromIterable(splitterFunction.apply(received)); // multiple Message> + return Flux.fromIterable(splitterFunction.apply(received)); // multiple + // Message> } else { return Flux.empty(); @@ -88,8 +90,7 @@ public MongoDbMessageSource mongoDbSource( @Nullable ComponentCustomizer mongoDbMessageSourceCustomizer) { Expression queryExpression = (this.properties.getQueryExpression() != null - ? this.properties.getQueryExpression() - : new LiteralExpression(this.properties.getQuery())); + ? this.properties.getQueryExpression() : new LiteralExpression(this.properties.getQuery())); MongoDbMessageSource mongoDbMessageSource = new MongoDbMessageSource(this.mongoTemplate, queryExpression); mongoDbMessageSource.setCollectionNameExpression(new LiteralExpression(this.properties.getCollection())); mongoDbMessageSource.setEntityClass(String.class); diff --git a/supplier/spring-mongodb-supplier/src/test/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierApplicationTests.java b/supplier/spring-mongodb-supplier/src/test/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierApplicationTests.java index f22b6fc5..e66fd152 100644 --- a/supplier/spring-mongodb-supplier/src/test/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierApplicationTests.java +++ b/supplier/spring-mongodb-supplier/src/test/java/org/springframework/cloud/fn/supplier/mongo/MongodbSupplierApplicationTests.java @@ -40,11 +40,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; -@SpringBootTest(properties = { - "mongodb.supplier.collection=testing", - "mongodb.supplier.query={ name: { $exists: true }}", - "mongodb.supplier.update-expression='{ $unset: { name: 0 } }'" -}) +@SpringBootTest( + properties = { "mongodb.supplier.collection=testing", "mongodb.supplier.query={ name: { $exists: true }}", + "mongodb.supplier.update-expression='{ $unset: { name: 0 } }'" }) class MongodbSupplierApplicationTests implements MongoDbTestContainerSupport { @DynamicPropertySource @@ -66,12 +64,8 @@ public void setUp() { MongoDatabase database = this.mongo.getDatabase("test"); database.createCollection("testing"); MongoCollection collection = database.getCollection("testing"); - collection.insertOne( - new Document("greeting", "hello") - .append("name", "foo")); - collection.insertOne( - new Document("greeting", "hola") - .append("name", "bar")); + collection.insertOne(new Document("greeting", "hello").append("name", "foo")); + collection.insertOne(new Document("greeting", "hola").append("name", "bar")); } @Test @@ -80,17 +74,13 @@ void testMongodbSupplier() { Flux> messageFlux = this.mongodbSupplier.get(); // when StepVerifier.create(messageFlux) - // then - .assertNext((message) -> - assertThat(toMap(message)).contains( - entry("greeting", "hello"), - entry("name", "foo"))) - .assertNext((message) -> - assertThat(toMap(message)).contains( - entry("greeting", "hola"), - entry("name", "bar"))) - .thenCancel() - .verify(); + // then + .assertNext( + (message) -> assertThat(toMap(message)).contains(entry("greeting", "hello"), entry("name", "foo"))) + .assertNext( + (message) -> assertThat(toMap(message)).contains(entry("greeting", "hola"), entry("name", "bar"))) + .thenCancel() + .verify(); assertThat(this.mongodbSupplier.get().collectList().block()).isEmpty(); } @@ -109,5 +99,7 @@ private Map toMap(Message message) { @SpringBootApplication static class MongoDbSupplierTestApplication { + } + } diff --git a/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierConfiguration.java b/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierConfiguration.java index 82b1bc52..07b3e606 100644 --- a/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierConfiguration.java +++ b/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierConfiguration.java @@ -44,7 +44,7 @@ * @author Soby Chacko */ @Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties({MqttProperties.class, MqttSupplierProperties.class}) +@EnableConfigurationProperties({ MqttProperties.class, MqttSupplierProperties.class }) @Import(MqttConfiguration.class) public class MqttSupplierConfiguration { @@ -66,9 +66,8 @@ public Supplier>> mqttSupplier(Publisher> mqttPublish public MqttPahoMessageDrivenChannelAdapter mqttInbound( @Nullable ComponentCustomizer mqttMessageProducerCustomizer) { - MqttPahoMessageDrivenChannelAdapter adapter = - new MqttPahoMessageDrivenChannelAdapter(this.properties.getClientId(), this.mqttClientFactory, - this.properties.getTopics()); + MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( + this.properties.getClientId(), this.mqttClientFactory, this.properties.getTopics()); adapter.setQos(this.properties.getQos()); adapter.setConverter(pahoMessageConverter(this.beanFactory)); adapter.setAutoStartup(false); @@ -82,8 +81,7 @@ public MqttPahoMessageDrivenChannelAdapter mqttInbound( @Bean public Publisher> mqttPublisher(MqttPahoMessageDrivenChannelAdapter mqttInbound) { - return IntegrationFlow.from(mqttInbound) - .toReactivePublisher(true); + return IntegrationFlow.from(mqttInbound).toReactivePublisher(true); } private DefaultPahoMessageConverter pahoMessageConverter(BeanFactory beanFactory) { diff --git a/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierProperties.java b/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierProperties.java index 25f671e6..b8ca910b 100644 --- a/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierProperties.java +++ b/supplier/spring-mqtt-supplier/src/main/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierProperties.java @@ -44,7 +44,8 @@ public class MqttSupplierProperties { private String[] topics = new String[] { "stream.mqtt" }; /** - * the qos; a single value for all topics or a comma-delimited list to match the topics. + * the qos; a single value for all topics or a comma-delimited list to match the + * topics. */ private int[] qos = new int[] { 0 }; diff --git a/supplier/spring-mqtt-supplier/src/test/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierTests.java b/supplier/spring-mqtt-supplier/src/test/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierTests.java index 2ac19f94..a6e4e08f 100644 --- a/supplier/spring-mqtt-supplier/src/test/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierTests.java +++ b/supplier/spring-mqtt-supplier/src/test/java/org/springframework/cloud/fn/supplier/mqtt/MqttSupplierTests.java @@ -52,22 +52,18 @@ * @author Artem Bilan * */ -@SpringBootTest(properties = - { "mqtt.supplier.topics=test,fake", - "mqtt.supplier.qos=0,0", - "mqtt.ssl-properties.com.ibm.ssl.protocol=TLS", - "mqtt.ssl-properties.com.ibm.ssl.keyStoreType=TEST"}) +@SpringBootTest(properties = { "mqtt.supplier.topics=test,fake", "mqtt.supplier.qos=0,0", + "mqtt.ssl-properties.com.ibm.ssl.protocol=TLS", "mqtt.ssl-properties.com.ibm.ssl.keyStoreType=TEST" }) @DirtiesContext public class MqttSupplierTests { static { - GenericContainer mosquitto = - new GenericContainer<>("eclipse-mosquitto:2.0.13") - .withCommand("mosquitto -c /mosquitto-no-auth.conf") - .withReuse(true) - .withExposedPorts(1883) - .withStartupTimeout(Duration.ofSeconds(120)) - .withStartupAttempts(3); + GenericContainer mosquitto = new GenericContainer<>("eclipse-mosquitto:2.0.13") + .withCommand("mosquitto -c /mosquitto-no-auth.conf") + .withReuse(true) + .withExposedPorts(1883) + .withStartupTimeout(Duration.ofSeconds(120)) + .withStartupAttempts(3); mosquitto.start(); final Integer mappedPort = mosquitto.getMappedPort(1883); System.setProperty("mqtt.url", "tcp://localhost:" + mappedPort); @@ -89,20 +85,15 @@ public void testBasicFlow() { MqttConnectOptions connectionInfo = this.mqttOutbound.getConnectionInfo(); Properties sslProperties = connectionInfo.getSSLProperties(); assertThat(sslProperties) - .containsEntry(SSLSocketFactoryFactory.SSLPROTOCOL, SSLSocketFactoryFactory.DEFAULT_PROTOCOL) - .containsEntry(SSLSocketFactoryFactory.KEYSTORETYPE, "TEST"); + .containsEntry(SSLSocketFactoryFactory.SSLPROTOCOL, SSLSocketFactoryFactory.DEFAULT_PROTOCOL) + .containsEntry(SSLSocketFactoryFactory.KEYSTORETYPE, "TEST"); this.mqttOutbound.handleMessage(MessageBuilder.withPayload("hello").build()); final Flux> messageFlux = mqttSupplier.get(); - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo("hello"); - } - ) - .thenCancel() - .verify(); + StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo("hello"); + }).thenCancel().verify(); } @SpringBootApplication diff --git a/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierConfiguration.java b/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierConfiguration.java index c058e9af..e28234d0 100644 --- a/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierConfiguration.java +++ b/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierConfiguration.java @@ -68,19 +68,17 @@ @EnableConfigurationProperties(RabbitSupplierProperties.class) public class RabbitSupplierConfiguration implements DisposableBean { - private static final MessagePropertiesConverter inboundMessagePropertiesConverter = - new DefaultMessagePropertiesConverter() { + private static final MessagePropertiesConverter inboundMessagePropertiesConverter = new DefaultMessagePropertiesConverter() { - @Override - public MessageProperties toMessageProperties(AMQP.BasicProperties source, - Envelope envelope, String charset) { + @Override + public MessageProperties toMessageProperties(AMQP.BasicProperties source, Envelope envelope, String charset) { - MessageProperties properties = super.toMessageProperties(source, envelope, charset); - properties.setDeliveryMode(null); - return properties; - } + MessageProperties properties = super.toMessageProperties(source, envelope, charset); + properties.setDeliveryMode(null); + return properties; + } - }; + }; @Autowired private RabbitProperties rabbitProperties; @@ -107,8 +105,7 @@ public MessageProperties toMessageProperties(AMQP.BasicProperties source, @Bean public SimpleMessageListenerContainer container(RetryOperationsInterceptor rabbitSourceRetryInterceptor) { - ConnectionFactory connectionFactory = this.properties.isOwnConnection() - ? buildLocalConnectionFactory() + ConnectionFactory connectionFactory = this.properties.isOwnConnection() ? buildLocalConnectionFactory() : this.rabbitConnectionFactory; SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); container.setAutoStartup(false); @@ -151,16 +148,14 @@ public SimpleMessageListenerContainer container(RetryOperationsInterceptor rabbi public Publisher> rabbitPublisher(SimpleMessageListenerContainer container, @Nullable ComponentCustomizer amqpMessageProducerCustomizer) { - AmqpInboundChannelAdapterSMLCSpec messageProducerSpec = - Amqp.inboundAdapter(container) - .mappedRequestHeaders(properties.getMappedRequestHeaders()); + AmqpInboundChannelAdapterSMLCSpec messageProducerSpec = Amqp.inboundAdapter(container) + .mappedRequestHeaders(properties.getMappedRequestHeaders()); if (amqpMessageProducerCustomizer != null) { amqpMessageProducerCustomizer.customize(messageProducerSpec); } - return IntegrationFlow.from(messageProducerSpec) - .toReactivePublisher(true); + return IntegrationFlow.from(messageProducerSpec).toReactivePublisher(true); } @Bean @@ -171,11 +166,11 @@ public Supplier>> rabbitSupplier(Publisher> @Bean public RetryOperationsInterceptor rabbitSourceRetryInterceptor() { return RetryInterceptorBuilder.stateless() - .maxAttempts(this.properties.getMaxAttempts()) - .backOffOptions(this.properties.getInitialRetryInterval(), this.properties.getRetryMultiplier(), - this.properties.getMaxRetryInterval()) - .recoverer(new RejectAndDontRequeueRecoverer()) - .build(); + .maxAttempts(this.properties.getMaxAttempts()) + .backOffOptions(this.properties.getInitialRetryInterval(), this.properties.getRetryMultiplier(), + this.properties.getMaxRetryInterval()) + .recoverer(new RejectAndDontRequeueRecoverer()) + .build(); } @Override @@ -187,9 +182,8 @@ public void destroy() { private ConnectionFactory buildLocalConnectionFactory() { try { - this.ownConnectionFactory = rabbitConnectionFactory( - this.rabbitProperties, this.resourceLoader, this.credentialsProvider, this.credentialsRefreshService, - this.connectionFactoryCustomizers); + this.ownConnectionFactory = rabbitConnectionFactory(this.rabbitProperties, this.resourceLoader, + this.credentialsProvider, this.credentialsRefreshService, this.connectionFactoryCustomizers); } catch (Exception exception) { @@ -199,31 +193,33 @@ private ConnectionFactory buildLocalConnectionFactory() { return this.ownConnectionFactory; } - /* NOTE: This is based on RabbitAutoConfiguration.RabbitConnectionFactoryCreator - * https://github.com/spring-projects/spring-boot/blob/c820ad01a108d419d8548265b8a34ed7c5591f7c/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java#L95 - * [UPGRADE_CONSIDERATION] this should stay somewhat in sync w/ the functionality provided by its original source. + /* + * NOTE: This is based on RabbitAutoConfiguration.RabbitConnectionFactoryCreator + * https://github.com/spring-projects/spring-boot/blob/ + * c820ad01a108d419d8548265b8a34ed7c5591f7c/spring-boot-project/spring-boot- + * autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/ + * RabbitAutoConfiguration.java#L95 [UPGRADE_CONSIDERATION] this should stay somewhat + * in sync w/ the functionality provided by its original source. */ private static CachingConnectionFactory rabbitConnectionFactory(RabbitProperties properties, - ResourceLoader resourceLoader, - ObjectProvider credentialsProvider, + ResourceLoader resourceLoader, ObjectProvider credentialsProvider, ObjectProvider credentialsRefreshService, ObjectProvider connectionFactoryCustomizers) throws Exception { RabbitConnectionFactoryBean connectionFactoryBean = new RabbitConnectionFactoryBean(); - RabbitConnectionFactoryBeanConfigurer connectionFactoryBeanConfigurer = - new RabbitConnectionFactoryBeanConfigurer(resourceLoader, properties); + RabbitConnectionFactoryBeanConfigurer connectionFactoryBeanConfigurer = new RabbitConnectionFactoryBeanConfigurer( + resourceLoader, properties); connectionFactoryBeanConfigurer.setCredentialsProvider(credentialsProvider.getIfUnique()); connectionFactoryBeanConfigurer.setCredentialsRefreshService(credentialsRefreshService.getIfUnique()); connectionFactoryBeanConfigurer.configure(connectionFactoryBean); connectionFactoryBean.afterPropertiesSet(); com.rabbitmq.client.ConnectionFactory connectionFactory = connectionFactoryBean.getObject(); - connectionFactoryCustomizers.orderedStream() - .forEach((customizer) -> customizer.customize(connectionFactory)); + connectionFactoryCustomizers.orderedStream().forEach((customizer) -> customizer.customize(connectionFactory)); CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(connectionFactory); - CachingConnectionFactoryConfigurer cachingConnectionFactoryConfigurer = - new CachingConnectionFactoryConfigurer(properties); + CachingConnectionFactoryConfigurer cachingConnectionFactoryConfigurer = new CachingConnectionFactoryConfigurer( + properties); cachingConnectionFactoryConfigurer.setConnectionNameStrategy(cf -> "rabbit.supplier.own.connection"); cachingConnectionFactoryConfigurer.configure(cachingConnectionFactory); cachingConnectionFactory.afterPropertiesSet(); diff --git a/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierProperties.java b/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierProperties.java index 0cb390ca..3def1023 100644 --- a/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierProperties.java +++ b/supplier/spring-rabbit-supplier/src/main/java/org/springframework/cloud/fn/supplier/rabbit/RabbitSupplierProperties.java @@ -44,7 +44,7 @@ public class RabbitSupplierProperties { /** * Headers that will be mapped. */ - private String[] mappedRequestHeaders = {"STANDARD_REQUEST_HEADERS"}; + private String[] mappedRequestHeaders = { "STANDARD_REQUEST_HEADERS" }; /** * Initial retry interval when retry is enabled. @@ -158,4 +158,5 @@ public boolean isOwnConnection() { public void setOwnConnection(boolean ownConnection) { this.ownConnection = ownConnection; } + } diff --git a/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierConfiguration.java b/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierConfiguration.java index be44f4fd..fbba50e3 100644 --- a/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierConfiguration.java +++ b/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierConfiguration.java @@ -59,7 +59,7 @@ * @author David Turanski */ @Configuration(proxyBeanMethods = false) -@EnableConfigurationProperties({AwsS3SupplierProperties.class, FileConsumerProperties.class}) +@EnableConfigurationProperties({ AwsS3SupplierProperties.class, FileConsumerProperties.class }) public class AwsS3SupplierConfiguration { protected static final String METADATA_STORE_PREFIX = "s3-metadata-"; @@ -73,8 +73,7 @@ public class AwsS3SupplierConfiguration { protected final ConcurrentMetadataStore metadataStore; public AwsS3SupplierConfiguration(AwsS3SupplierProperties awsS3SupplierProperties, - FileConsumerProperties fileConsumerProperties, - S3SessionFactory s3SessionFactory, + FileConsumerProperties fileConsumerProperties, S3SessionFactory s3SessionFactory, ConcurrentMetadataStore metadataStore) { this.awsS3SupplierProperties = awsS3SupplierProperties; @@ -96,12 +95,12 @@ public Supplier>> s3Supplier(Publisher> s3SupplierFlo public ChainFileListFilter filter(ConcurrentMetadataStore metadataStore) { ChainFileListFilter chainFilter = new ChainFileListFilter<>(); if (StringUtils.hasText(this.awsS3SupplierProperties.getFilenamePattern())) { - chainFilter.addFilter( - new S3SimplePatternFileListFilter(this.awsS3SupplierProperties.getFilenamePattern())); + chainFilter + .addFilter(new S3SimplePatternFileListFilter(this.awsS3SupplierProperties.getFilenamePattern())); } else if (this.awsS3SupplierProperties.getFilenameRegex() != null) { chainFilter - .addFilter(new S3RegexPatternFileListFilter(this.awsS3SupplierProperties.getFilenameRegex())); + .addFilter(new S3RegexPatternFileListFilter(this.awsS3SupplierProperties.getFilenameRegex())); } chainFilter.addFilter(new S3PersistentAcceptOnceFileListFilter(metadataStore, METADATA_STORE_PREFIX)); @@ -109,8 +108,7 @@ else if (this.awsS3SupplierProperties.getFilenameRegex() != null) { } SynchronizingConfiguration(AwsS3SupplierProperties awsS3SupplierProperties, - FileConsumerProperties fileConsumerProperties, - S3SessionFactory s3SessionFactory, + FileConsumerProperties fileConsumerProperties, S3SessionFactory s3SessionFactory, ConcurrentMetadataStore concurrentMetadataStore) { super(awsS3SupplierProperties, fileConsumerProperties, s3SessionFactory, concurrentMetadataStore); @@ -118,12 +116,12 @@ else if (this.awsS3SupplierProperties.getFilenameRegex() != null) { @Bean public Publisher> s3SupplierFlow(S3InboundFileSynchronizingMessageSource s3MessageSource) { - return FileUtils.enhanceFlowForReadingMode( - IntegrationFlow.from( - IntegrationReactiveUtils.messageSourceToFlux(s3MessageSource) - .doOnSubscribe((s) -> s3MessageSource.start())), - fileConsumerProperties) - .toReactivePublisher(true); + return FileUtils + .enhanceFlowForReadingMode( + IntegrationFlow.from(IntegrationReactiveUtils.messageSourceToFlux(s3MessageSource) + .doOnSubscribe((s) -> s3MessageSource.start())), + fileConsumerProperties) + .toReactivePublisher(true); } @Bean @@ -165,8 +163,7 @@ public S3InboundFileSynchronizingMessageSource s3MessageSource( static class ListOnlyConfiguration extends AwsS3SupplierConfiguration { ListOnlyConfiguration(AwsS3SupplierProperties awsS3SupplierProperties, - FileConsumerProperties fileConsumerProperties, - S3SessionFactory s3SessionFactory, + FileConsumerProperties fileConsumerProperties, S3SessionFactory s3SessionFactory, ConcurrentMetadataStore metadataStore) { super(awsS3SupplierProperties, fileConsumerProperties, s3SessionFactory, metadataStore); @@ -191,7 +188,8 @@ Predicate listOnlyFilter(AwsS3SupplierProperties awsS3SupplierProperti } else if (this.awsS3SupplierProperties.getFilenameRegex() != null) { predicate = (S3Object summary) -> this.awsS3SupplierProperties.getFilenameRegex() - .matcher(summary.key()).matches(); + .matcher(summary.key()) + .matches(); } predicate = predicate.and((S3Object summary) -> { final String key = METADATA_STORE_PREFIX + awsS3SupplierProperties.getRemoteDir() + "-" + summary.key(); @@ -208,32 +206,27 @@ else if (this.awsS3SupplierProperties.getFilenameRegex() != null) { } @Bean - ReactiveMessageSourceProducer s3ListingMessageProducer( - S3Client amazonS3, - ObjectMapper objectMapper, - AwsS3SupplierProperties awsS3SupplierProperties, - Predicate filter - ) { - return new ReactiveMessageSourceProducer( - (MessageSource>) () -> { - List summaryList = - amazonS3.listObjects(ListObjectsRequest.builder() - .bucket(awsS3SupplierProperties.getRemoteDir()) - .build()) - .contents() - .stream() - .filter(filter) - .map(s3Object -> { - try { - return objectMapper.writeValueAsString(s3Object.toBuilder()); - } - catch (JsonProcessingException ex) { - throw new RuntimeException(ex); - } - }) - .collect(Collectors.toList()); - return summaryList.isEmpty() ? null : new GenericMessage<>(summaryList); - }); + ReactiveMessageSourceProducer s3ListingMessageProducer(S3Client amazonS3, ObjectMapper objectMapper, + AwsS3SupplierProperties awsS3SupplierProperties, Predicate filter) { + return new ReactiveMessageSourceProducer((MessageSource>) () -> { + List summaryList = amazonS3 + .listObjects(ListObjectsRequest.builder().bucket(awsS3SupplierProperties.getRemoteDir()).build()) + .contents() + .stream() + .filter(filter) + .map(s3Object -> { + try { + return objectMapper.writeValueAsString(s3Object.toBuilder()); + } + catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + }) + .collect(Collectors.toList()); + return summaryList.isEmpty() ? null : new GenericMessage<>(summaryList); + }); } + } + } diff --git a/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierProperties.java b/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierProperties.java index 86d3c098..16ec6e11 100644 --- a/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierProperties.java +++ b/supplier/spring-s3-supplier/src/main/java/org/springframework/cloud/fn/supplier/s3/AwsS3SupplierProperties.java @@ -172,4 +172,5 @@ public boolean isListOnly() { public void setListOnly(boolean listOnly) { this.listOnly = listOnly; } + } diff --git a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AbstractAwsS3SupplierMockTests.java b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AbstractAwsS3SupplierMockTests.java index 23b2ba4c..1fa67abb 100644 --- a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AbstractAwsS3SupplierMockTests.java +++ b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AbstractAwsS3SupplierMockTests.java @@ -55,13 +55,11 @@ import static org.mockito.Mockito.mock; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "spring.cloud.aws.credentials.accessKey=" + AbstractAwsS3SupplierMockTests.AWS_ACCESS_KEY, + properties = { "spring.cloud.aws.credentials.accessKey=" + AbstractAwsS3SupplierMockTests.AWS_ACCESS_KEY, "spring.cloud.aws.credentials.secretKey=" + AbstractAwsS3SupplierMockTests.AWS_SECRET_KEY, "spring.cloud.aws.region.static=" + AbstractAwsS3SupplierMockTests.AWS_REGION, "spring.cloud.aws.s3.endpoint=s3://foo", - "s3.supplier.remoteDir=" + AbstractAwsS3SupplierMockTests.S3_BUCKET - }) + "s3.supplier.remoteDir=" + AbstractAwsS3SupplierMockTests.S3_BUCKET }) @DirtiesContext @SpringIntegrationTest(noAutoStartup = "*") public abstract class AbstractAwsS3SupplierMockTests { @@ -105,11 +103,7 @@ public static void setup() throws IOException { Instant instant = Instant.now().plus(Period.ofDays(1)); for (File file : f.listFiles()) { - S3Object s3Object = - S3Object.builder() - .key("subdir/" + file.getName()) - .lastModified(instant) - .build(); + S3Object s3Object = S3Object.builder().key("subdir/" + file.getName()).lastModified(instant).build(); S3_OBJECTS.put(s3Object, new FileInputStream(file)); } @@ -123,15 +117,14 @@ public static void setup() throws IOException { @AfterAll public static void tearDown() { System.clearProperty("s3.supplier.localDir"); - S3_OBJECTS.values() - .forEach(stream -> { - try { - stream.close(); - } - catch (IOException e) { - // Ignore - } - }); + S3_OBJECTS.values().forEach(stream -> { + try { + stream.close(); + } + catch (IOException e) { + // Ignore + } + }); } @SpringBootApplication @@ -142,21 +135,18 @@ public static class S3SupplierTestApplication { public S3Client amazonS3Mock() { S3Client amazonS3 = mock(S3Client.class); - ListObjectsResponse listObjectsResponse = - ListObjectsResponse.builder().contents(S3_OBJECTS.keySet()).isTruncated(false).build(); + ListObjectsResponse listObjectsResponse = ListObjectsResponse.builder() + .contents(S3_OBJECTS.keySet()) + .isTruncated(false) + .build(); - willAnswer(invocation -> listObjectsResponse) - .given(amazonS3) - .listObjects(any(ListObjectsRequest.class)); + willAnswer(invocation -> listObjectsResponse).given(amazonS3).listObjects(any(ListObjectsRequest.class)); for (Map.Entry s3Object : S3_OBJECTS.entrySet()) { - willAnswer(invocation -> - new ResponseInputStream<>(GetObjectResponse.builder().build(), s3Object.getValue())) - .given(amazonS3) - .getObject(GetObjectRequest.builder() - .bucket(S3_BUCKET) - .key(s3Object.getKey().key()) - .build()); + willAnswer(invocation -> new ResponseInputStream<>(GetObjectResponse.builder().build(), + s3Object.getValue())) + .given(amazonS3) + .getObject(GetObjectRequest.builder().bucket(S3_BUCKET).key(s3Object.getKey().key()).build()); } return amazonS3; } diff --git a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3FilesTransferredTests.java b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3FilesTransferredTests.java index f5e4b197..a2ce28cc 100644 --- a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3FilesTransferredTests.java +++ b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3FilesTransferredTests.java @@ -28,26 +28,21 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = {"file.consumer.mode=ref", - "s3.supplier.filenameRegex=.*\\\\.test$"}) +@TestPropertySource(properties = { "file.consumer.mode=ref", "s3.supplier.filenameRegex=.*\\\\.test$" }) public class AmazonS3FilesTransferredTests extends AbstractAwsS3SupplierMockTests { @Test public void test() { final Flux> messageFlux = s3Supplier.get(); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) - .isEqualTo(new File(this.awsS3SupplierProperties.getLocalDir() + File.separator + "subdir" + File.separator + "1.test")); - } - ) - .assertNext((message) -> { - assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) - .isEqualTo(new File(this.awsS3SupplierProperties.getLocalDir() + File.separator + "subdir" + File.separator + "2.test")); - }) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) + .isEqualTo(new File(this.awsS3SupplierProperties.getLocalDir() + File.separator + "subdir" + + File.separator + "1.test")); + }).assertNext((message) -> { + assertThat(new File(message.getPayload().toString().replaceAll("\"", ""))) + .isEqualTo(new File(this.awsS3SupplierProperties.getLocalDir() + File.separator + "subdir" + + File.separator + "2.test")); + }).thenCancel().verifyLater(); standardIntegrationFlow.start(); stepVerifier.verify(Duration.ofSeconds(10)); } diff --git a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3LinesTransferredTests.java b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3LinesTransferredTests.java index 8f2713d3..96dfd598 100644 --- a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3LinesTransferredTests.java +++ b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3LinesTransferredTests.java @@ -29,32 +29,25 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "file.consumer.mode=lines", - "s3.supplier.filenamePattern=*/otherFile", - "file.consumer.with-markers=false"}) +@TestPropertySource(properties = { "file.consumer.mode=lines", "s3.supplier.filenamePattern=*/otherFile", + "file.consumer.with-markers=false" }) public class AmazonS3LinesTransferredTests extends AbstractAwsS3SupplierMockTests { @Test public void test() { final Flux> messageFlux = s3Supplier.get(); - StepVerifier stepVerifier = - StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()).isEqualTo("Other"); - assertThat(message.getHeaders()).containsKey(FileHeaders.ORIGINAL_FILE); - assertThat(message.getHeaders()).containsValue( - new File(this.awsS3SupplierProperties.getLocalDir(), "subdir/otherFile")); - } - ) - .assertNext((message) -> { - assertThat(message.getPayload().toString()).isEqualTo("Other2"); - }) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo("Other"); + assertThat(message.getHeaders()).containsKey(FileHeaders.ORIGINAL_FILE); + assertThat(message.getHeaders()) + .containsValue(new File(this.awsS3SupplierProperties.getLocalDir(), "subdir/otherFile")); + }).assertNext((message) -> { + assertThat(message.getPayload().toString()).isEqualTo("Other2"); + }).thenCancel().verifyLater(); standardIntegrationFlow.start(); stepVerifier.verify(Duration.ofSeconds(10)); assertThat(this.awsS3SupplierProperties.getLocalDir().list()).hasSize(1); } + } diff --git a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3ListOnlyTests.java b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3ListOnlyTests.java index bb8d324c..cd968293 100644 --- a/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3ListOnlyTests.java +++ b/supplier/spring-s3-supplier/src/test/java/org/springframework/cloud/fn/supplier/s3/AmazonS3ListOnlyTests.java @@ -31,9 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { - "s3.supplier.list-only=true" -}) +@TestPropertySource(properties = { "s3.supplier.list-only=true" }) public class AmazonS3ListOnlyTests extends AbstractAwsS3SupplierMockTests { @Test @@ -43,27 +41,22 @@ public void test() { keys.add("subdir/1.test"); keys.add("subdir/2.test"); keys.add("subdir/otherFile"); - StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext(message -> { - String s3Object = (String) message.getPayload(); - String key = jsonPathKey(s3Object); - assertThat(keys).contains(key); - keys.remove(key); - }) - .assertNext(message -> { - String s3Object = (String) message.getPayload(); - String key = jsonPathKey(s3Object); - assertThat(keys).contains(key); - keys.remove(key); - }) - .assertNext(message -> { - String s3Object = (String) message.getPayload(); - String key = jsonPathKey(s3Object); - assertThat(keys).contains(key); - keys.remove(key); - }) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext(message -> { + String s3Object = (String) message.getPayload(); + String key = jsonPathKey(s3Object); + assertThat(keys).contains(key); + keys.remove(key); + }).assertNext(message -> { + String s3Object = (String) message.getPayload(); + String key = jsonPathKey(s3Object); + assertThat(keys).contains(key); + keys.remove(key); + }).assertNext(message -> { + String s3Object = (String) message.getPayload(); + String key = jsonPathKey(s3Object); + assertThat(keys).contains(key); + keys.remove(key); + }).thenCancel().verifyLater(); standardIntegrationFlow.start(); stepVerifier.verify(Duration.ofSeconds(10)); } diff --git a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierConfiguration.java b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierConfiguration.java index fb90b276..a3bf615c 100644 --- a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierConfiguration.java +++ b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierConfiguration.java @@ -104,9 +104,8 @@ public MonoProcessor subscriptionBarrier() { @Bean public Supplier>> sftpSupplier(MessageSource sftpMessageSource, - @Nullable Publisher> sftpReadingFlow, - MonoProcessor subscriptionBarrier, - SftpSupplierProperties sftpSupplierProperties) { + @Nullable Publisher> sftpReadingFlow, MonoProcessor subscriptionBarrier, + SftpSupplierProperties sftpSupplierProperties) { Flux> flux = sftpReadingFlow == null ? sftpMessageFlux(sftpMessageSource, sftpSupplierProperties, subscriptionBarrier) @@ -117,9 +116,7 @@ public Supplier>> sftpSupplier(MessageSource sftpMe @Bean @Primary - public MessageSource sftpMessageSource( - MessageSource messageSource, - BeanFactory beanFactory, + public MessageSource sftpMessageSource(MessageSource messageSource, BeanFactory beanFactory, @Nullable List receiveMessageAdvice) { if (CollectionUtils.isEmpty(receiveMessageAdvice)) { @@ -142,10 +139,8 @@ public MessageSource sftpMessageSource( * Configure the standard filters for SFTP inbound adapters. */ @Bean - public FileListFilter chainFilter( - SftpSupplierProperties sftpSupplierProperties, - ConcurrentMetadataStore metadataStore - ) { + public FileListFilter chainFilter(SftpSupplierProperties sftpSupplierProperties, + ConcurrentMetadataStore metadataStore) { ChainFileListFilter chainFilter = new ChainFileListFilter<>(); @@ -167,9 +162,9 @@ private Flux> sftpMessageFlux(MessageSource sftpMessageS SftpSupplierProperties sftpSupplierProperties, MonoProcessor subscriptionBarrier) { return IntegrationReactiveUtils.messageSourceToFlux(sftpMessageSource) - .delaySubscription(subscriptionBarrier) - .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, - sftpSupplierProperties.getDelayWhenEmpty())); + .delaySubscription(subscriptionBarrier) + .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, + sftpSupplierProperties.getDelayWhenEmpty())); } @@ -189,36 +184,34 @@ public SftpRemoteFileTemplate sftpTemplate(SftpSupplierFactoryConfiguration.Dele } /** - * Streaming {@link MessageSource} that provides an InputStream for each remote file. It - * does not synchronize files to a local directory. + * Streaming {@link MessageSource} that provides an InputStream for each remote + * file. It does not synchronize files to a local directory. * @return a {@link MessageSource}. */ @Bean public SftpStreamingInboundChannelAdapterSpec targetMessageSource(SftpRemoteFileTemplate sftpTemplate, - SftpSupplierProperties sftpSupplierProperties, - FileListFilter fileListFilter) { + SftpSupplierProperties sftpSupplierProperties, FileListFilter fileListFilter) { return Sftp.inboundStreamingAdapter(sftpTemplate) - .remoteDirectory(remoteDirectory(sftpSupplierProperties)) - .remoteFileSeparator(sftpSupplierProperties.getRemoteFileSeparator()) - .filter(fileListFilter) - .maxFetchSize(sftpSupplierProperties.getMaxFetch()); + .remoteDirectory(remoteDirectory(sftpSupplierProperties)) + .remoteFileSeparator(sftpSupplierProperties.getRemoteFileSeparator()) + .filter(fileListFilter) + .maxFetchSize(sftpSupplierProperties.getMaxFetch()); } @Bean - public Publisher> sftpReadingFlow( - MessageSource sftpMessageSource, - MonoProcessor subscriptionBarrier, - SftpSupplierProperties sftpSupplierProperties, + public Publisher> sftpReadingFlow(MessageSource sftpMessageSource, + MonoProcessor subscriptionBarrier, SftpSupplierProperties sftpSupplierProperties, FileConsumerProperties fileConsumerProperties) { - return FileUtils.enhanceStreamFlowForReadingMode(IntegrationFlow - .from(IntegrationReactiveUtils.messageSourceToFlux(sftpMessageSource) - .delaySubscription(subscriptionBarrier) - .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, - sftpSupplierProperties.getDelayWhenEmpty()))), - fileConsumerProperties) - .toReactivePublisher(); + return FileUtils + .enhanceStreamFlowForReadingMode( + IntegrationFlow.from(IntegrationReactiveUtils.messageSourceToFlux(sftpMessageSource) + .delaySubscription(subscriptionBarrier) + .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, + sftpSupplierProperties.getDelayWhenEmpty()))), + fileConsumerProperties) + .toReactivePublisher(); } @Bean @@ -232,11 +225,12 @@ public RemoteFileDeletingAdvice remoteFileDeletingAdvice(SftpRemoteFileTemplate @Bean @ConditionalOnProperty(prefix = "sftp.supplier", value = "rename-remote-files-to") public RemoteFileRenamingAdvice remoteFileRenamingAdvice(SftpRemoteFileTemplate sftpTemplate, - SftpSupplierProperties sftpSupplierProperties) { + SftpSupplierProperties sftpSupplierProperties) { return new RemoteFileRenamingAdvice(sftpTemplate, sftpSupplierProperties.getRemoteFileSeparator(), sftpSupplierProperties.getRenameRemoteFilesTo()); } + } @Configuration @@ -252,24 +246,21 @@ static class NonStreamingConfiguration { */ @Bean @ConditionalOnExpression("environment['file.consumer.mode']!='ref' && environment['sftp.supplier.list-only']!='true'") - public Publisher> sftpReadingFlow( - MessageSource sftpMessageSource, - MonoProcessor subscriptionBarrier, - SftpSupplierProperties sftpSupplierProperties, + public Publisher> sftpReadingFlow(MessageSource sftpMessageSource, + MonoProcessor subscriptionBarrier, SftpSupplierProperties sftpSupplierProperties, FileConsumerProperties fileConsumerProperties, @Nullable @Qualifier("renameRemoteFileHandler") MessageHandler renameRemoteFileHandler) { - IntegrationFlowBuilder flowBuilder = FileUtils.enhanceFlowForReadingMode(IntegrationFlow - .from(IntegrationReactiveUtils.messageSourceToFlux(sftpMessageSource) - .delaySubscription(subscriptionBarrier) - .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, - sftpSupplierProperties.getDelayWhenEmpty()))), + IntegrationFlowBuilder flowBuilder = FileUtils.enhanceFlowForReadingMode( + IntegrationFlow.from(IntegrationReactiveUtils.messageSourceToFlux(sftpMessageSource) + .delaySubscription(subscriptionBarrier) + .contextWrite(Context.of(IntegrationReactiveUtils.DELAY_WHEN_EMPTY_KEY, + sftpSupplierProperties.getDelayWhenEmpty()))), fileConsumerProperties); if (renameRemoteFileHandler != null) { - flowBuilder.publishSubscribeChannel(pubsub -> - pubsub.subscribe(subFlow -> subFlow.handle(renameRemoteFileHandler).nullChannel()) - ); + flowBuilder.publishSubscribeChannel( + pubsub -> pubsub.subscribe(subFlow -> subFlow.handle(renameRemoteFileHandler).nullChannel())); } return flowBuilder.toReactivePublisher(); @@ -285,18 +276,17 @@ public SftpInboundChannelAdapterSpec targetMessageSource(SftpSupplierProperties SftpSupplierFactoryConfiguration.DelegatingFactoryWrapper delegatingFactoryWrapper, FileListFilter fileListFilter) { - return Sftp - .inboundAdapter(delegatingFactoryWrapper.getFactory()) - .preserveTimestamp(sftpSupplierProperties.isPreserveTimestamp()) - .autoCreateLocalDirectory(sftpSupplierProperties.isAutoCreateLocalDir()) - .deleteRemoteFiles(sftpSupplierProperties.isDeleteRemoteFiles()) - .localDirectory(sftpSupplierProperties.getLocalDir()) - .remoteDirectory(remoteDirectory(sftpSupplierProperties)) - .remoteFileSeparator(sftpSupplierProperties.getRemoteFileSeparator()) - .temporaryFileSuffix(sftpSupplierProperties.getTmpFileSuffix()) - .metadataStorePrefix(METADATA_STORE_PREFIX) - .maxFetchSize(sftpSupplierProperties.getMaxFetch()) - .filter(fileListFilter); + return Sftp.inboundAdapter(delegatingFactoryWrapper.getFactory()) + .preserveTimestamp(sftpSupplierProperties.isPreserveTimestamp()) + .autoCreateLocalDirectory(sftpSupplierProperties.isAutoCreateLocalDir()) + .deleteRemoteFiles(sftpSupplierProperties.isDeleteRemoteFiles()) + .localDirectory(sftpSupplierProperties.getLocalDir()) + .remoteDirectory(remoteDirectory(sftpSupplierProperties)) + .remoteFileSeparator(sftpSupplierProperties.getRemoteFileSeparator()) + .temporaryFileSuffix(sftpSupplierProperties.getTmpFileSuffix()) + .metadataStorePrefix(METADATA_STORE_PREFIX) + .maxFetchSize(sftpSupplierProperties.getMaxFetch()) + .filter(fileListFilter); } @Bean @@ -305,14 +295,14 @@ public SftpOutboundGatewaySpec renameRemoteFileHandler( SftpSupplierFactoryConfiguration.DelegatingFactoryWrapper delegatingFactoryWrapper, SftpSupplierProperties sftpSupplierProperties) { - return Sftp.outboundGateway(delegatingFactoryWrapper.getFactory(), - AbstractRemoteFileOutboundGateway.Command.MV.getCommand(), - String.format("headers.get('%s') + '%s' + headers.get('%s')", - FileHeaders.REMOTE_DIRECTORY, - sftpSupplierProperties.getRemoteFileSeparator(), - FileHeaders.REMOTE_FILE)) - .renameExpression(sftpSupplierProperties.getRenameRemoteFilesTo()); + return Sftp + .outboundGateway(delegatingFactoryWrapper.getFactory(), + AbstractRemoteFileOutboundGateway.Command.MV.getCommand(), + String.format("headers.get('%s') + '%s' + headers.get('%s')", FileHeaders.REMOTE_DIRECTORY, + sftpSupplierProperties.getRemoteFileSeparator(), FileHeaders.REMOTE_FILE)) + .renameExpression(sftpSupplierProperties.getRenameRemoteFilesTo()); } + } /* @@ -343,10 +333,8 @@ public SftpListingMessageProducer sftpListingMessageProducer(SftpSupplierPropert SftpSupplierFactoryConfiguration.DelegatingFactoryWrapper delegatingFactoryWrapper) { return new SftpListingMessageProducer(delegatingFactoryWrapper.getFactory(), - remoteDirectory(sftpSupplierProperties), - sftpSupplierProperties.getRemoteFileSeparator(), - sftpSupplierProperties.getSortBy() - ); + remoteDirectory(sftpSupplierProperties), sftpSupplierProperties.getRemoteFileSeparator(), + sftpSupplierProperties.getSortBy()); } @Bean @@ -363,18 +351,17 @@ else if (sftpSupplierProperties.getFilenameRegex() != null) { } @Bean - public IntegrationFlow listingFlow(MessageProducerSupport listingMessageProducer, - MessageChannel listingChannel, MessageProcessor lsEntryToStringTransformer, - GenericSelector> duplicateFilter, + public IntegrationFlow listingFlow(MessageProducerSupport listingMessageProducer, MessageChannel listingChannel, + MessageProcessor lsEntryToStringTransformer, GenericSelector> duplicateFilter, GenericSelector listOnlyFilter) { return IntegrationFlow.from(listingMessageProducer) - .split() - .transform(lsEntryToStringTransformer) - .filter(duplicateFilter) - .filter(listOnlyFilter) - .channel(listingChannel) - .get(); + .split() + .transform(lsEntryToStringTransformer) + .filter(duplicateFilter) + .filter(listOnlyFilter) + .channel(listingChannel) + .get(); } @Bean @@ -386,10 +373,10 @@ public MessageProcessor> lsEntryToStringTransformer() { String fileName = message.getHeaders().get(FileHeaders.REMOTE_DIRECTORY) + dirEntry.getFilename(); return MessageBuilder.withPayload(fileName) - .copyHeaders(message.getHeaders()) - .setHeader(FILE_MODIFIED_TIME_HEADER, String.valueOf(dirEntry.getAttributes().getModifyTime())) - .setHeader(MessageHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) - .build(); + .copyHeaders(message.getHeaders()) + .setHeader(FILE_MODIFIED_TIME_HEADER, String.valueOf(dirEntry.getAttributes().getModifyTime())) + .setHeader(MessageHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) + .build(); }; } @@ -406,8 +393,7 @@ public boolean accept(Message message) { boolean result = !lastModifiedTime.equals(storedLastModifiedTime); if (result) { - metadataStore.put( - METADATA_STORE_PREFIX + message.getPayload(), + metadataStore.put(METADATA_STORE_PREFIX + message.getPayload(), message.getHeaders().get(FILE_MODIFIED_TIME_HEADER).toString()); } return result; @@ -438,7 +424,7 @@ public void listNames() { Stream stream; try { stream = Stream.of(this.sessionFactory.getSession().list(this.remoteDirectory)) - .filter(x -> !(x.getAttributes().isDirectory() || x.getAttributes().isSymbolicLink())); + .filter(x -> !(x.getAttributes().isDirectory() || x.getAttributes().isSymbolicLink())); if (sort != null) { stream = stream.sorted(sort.comparator()); @@ -448,8 +434,8 @@ public void listNames() { throw new MessagingException(e.getMessage(), e); } sendMessage(MessageBuilder.withPayload(stream) - .setHeader(FileHeaders.REMOTE_DIRECTORY, this.remoteDirectory + this.remoteFileSeparator) - .build()); + .setHeader(FileHeaders.REMOTE_DIRECTORY, this.remoteDirectory + this.remoteFileSeparator) + .build()); } } diff --git a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierFactoryConfiguration.java b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierFactoryConfiguration.java index 012bee25..e50be7f9 100644 --- a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierFactoryConfiguration.java +++ b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierFactoryConfiguration.java @@ -63,18 +63,14 @@ public DelegatingFactoryWrapper delegatingFactoryWrapper(SftpSupplierProperties @Bean StandardRotationPolicy rotationPolicy(SftpSupplierProperties properties, DelegatingFactoryWrapper factory) { - return properties.isMultiSource() - ? new StandardRotationPolicy(factory.getFactory(), - SftpSupplierProperties.keyDirectories(properties), properties.isFair()) - : null; + return properties.isMultiSource() ? new StandardRotationPolicy(factory.getFactory(), + SftpSupplierProperties.keyDirectories(properties), properties.isFair()) : null; } @Bean public SftpSupplierRotator rotatingAdvice(SftpSupplierProperties properties, @Nullable StandardRotationPolicy rotationPolicy) { - return properties.isMultiSource() - ? new SftpSupplierRotator(properties, rotationPolicy) - : null; + return properties.isMultiSource() ? new SftpSupplierRotator(properties, rotationPolicy) : null; } static SessionFactory buildFactory(ApplicationContext applicationContext, @@ -90,7 +86,7 @@ static SessionFactory buildFactory(ApplicationContext appli sftpSessionFactory.setAllowUnknownKeys(factory.isAllowUnknownKeys()); if (factory.getKnownHostsExpression() != null) { String knownHostsLocation = factory.getKnownHostsExpression() - .getValue(IntegrationContextUtils.getEvaluationContext(applicationContext), String.class); + .getValue(IntegrationContextUtils.getEvaluationContext(applicationContext), String.class); Resource knownHostsResource = applicationContext.getResource(knownHostsLocation); sftpSessionFactory.setKnownHostsResource(knownHostsResource); } @@ -107,8 +103,9 @@ public final static class DelegatingFactoryWrapper implements DisposableBean { DelegatingFactoryWrapper(SftpSupplierProperties properties, SessionFactory defaultFactory, ApplicationContext applicationContext) { - properties.getFactories().forEach((key, factory) -> - this.factories.put(key, SftpSupplierFactoryConfiguration.buildFactory(applicationContext, factory))); + properties.getFactories() + .forEach((key, factory) -> this.factories.put(key, + SftpSupplierFactoryConfiguration.buildFactory(applicationContext, factory))); this.delegatingSessionFactory = new DelegatingSessionFactory<>(this.factories, defaultFactory); } diff --git a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierProperties.java b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierProperties.java index f81f4904..9fde6a4b 100644 --- a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierProperties.java +++ b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierProperties.java @@ -49,6 +49,7 @@ @ConfigurationProperties("sftp.supplier") @Validated public class SftpSupplierProperties { + /** * Session factory properties. */ @@ -75,7 +76,8 @@ public class SftpSupplierProperties { private boolean deleteRemoteFiles = false; /** - * A SpEL expression resolving to the new name remote files must be renamed to after successful transfer. + * A SpEL expression resolving to the new name remote files must be renamed to after + * successful transfer. */ private Expression renameRemoteFilesTo = null; @@ -120,15 +122,15 @@ public class SftpSupplierProperties { private Duration delayWhenEmpty = Duration.ofSeconds(1); /** - * The maximum number of remote files to fetch per poll; default unlimited. Does not apply - * when listing files or building task launch requests. + * The maximum number of remote files to fetch per poll; default unlimited. Does not + * apply when listing files or building task launch requests. */ private int maxFetch = Integer.MIN_VALUE; /** - * True for fair rotation of multiple servers/directories. This is false by default so if - * a source has more than one entry, these will be received before the other sources are - * visited. + * True for fair rotation of multiple servers/directories. This is false by default so + * if a source has more than one entry, these will be received before the other + * sources are visited. */ private boolean fair; @@ -143,8 +145,9 @@ public class SftpSupplierProperties { private String[] directories; /** - * Sorting specification for remote files listings. If null, order of entries is undefined. - * Otherwise, entries are sorted by the specified field and direction, according to the type canonical ordering. + * Sorting specification for remote files listings. If null, order of entries is + * undefined. Otherwise, entries are sorted by the specified field and direction, + * according to the type canonical ordering. */ private SortSpec sortBy; @@ -439,8 +442,10 @@ public void setKnownHostsExpression(Expression knownHosts) { } public static class SortSpec { + /** - * Attribute of the file listing entry to sort by (FILENAME, ATIME: last access time, MTIME: last modified time). + * Attribute of the file listing entry to sort by (FILENAME, ATIME: last access + * time, MTIME: last modified time). */ private Attribute attribute; @@ -468,6 +473,7 @@ public void setDir(Dir dir) { } public enum Attribute { + /** * Filename attribute. */ @@ -482,9 +488,11 @@ public enum Attribute { * Last modified time attribute. */ MTIME + } public enum Dir { + /** * Ascending sort direction. */ @@ -494,6 +502,7 @@ public enum Dir { * Descending sort direction. */ DESC + } private Comparator getAttributeComparator() { @@ -513,5 +522,7 @@ public Comparator comparator() { Comparator comparator = getAttributeComparator(); return dir == Dir.ASC ? comparator : comparator.reversed(); } + } + } diff --git a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierRotator.java b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierRotator.java index 4f3e827a..56743445 100644 --- a/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierRotator.java +++ b/supplier/spring-sftp-supplier/src/main/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierRotator.java @@ -55,9 +55,11 @@ public String getCurrentDirectory() { public Message afterReceive(Message result, MessageSource source) { if (result != null) { result = MessageBuilder.fromMessage(result) - .setHeader(SFTP_SELECTED_SERVER_PROPERTY_KEY, this.getCurrentKey()).build(); + .setHeader(SFTP_SELECTED_SERVER_PROPERTY_KEY, this.getCurrentKey()) + .build(); } this.rotationPolicy.afterReceive(result != null, source); return result; } + } diff --git a/supplier/spring-sftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierApplicationTests.java b/supplier/spring-sftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierApplicationTests.java index c41d09e0..e5f3fac6 100644 --- a/supplier/spring-sftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierApplicationTests.java +++ b/supplier/spring-sftp-supplier/src/test/java/org/springframework/cloud/fn/supplier/sftp/SftpSupplierApplicationTests.java @@ -58,211 +58,172 @@ public class SftpSupplierApplicationTests extends SftpTestSupport { @BeforeEach void setUpDefaultProperties() { defaultApplicationContextRunner = new ApplicationContextRunner() - .withUserConfiguration(SftpSupplierTestApplication.class) - .withPropertyValues( - "sftp.supplier.factory.host=localhost", - "sftp.supplier.factory.port=${sftp.factory.port}", - "sftp.supplier.factory.username=user", - "sftp.supplier.factory.password=pass", - "sftp.supplier.factory.cache-sessions=true", - "sftp.supplier.factory.allowUnknownKeys=true", - "sftp.supplier.localDir=" + this.targetLocalDirectory.getAbsolutePath(), - "sftp.supplier.remoteDir=sftpSource"); + .withUserConfiguration(SftpSupplierTestApplication.class) + .withPropertyValues("sftp.supplier.factory.host=localhost", + "sftp.supplier.factory.port=${sftp.factory.port}", "sftp.supplier.factory.username=user", + "sftp.supplier.factory.password=pass", "sftp.supplier.factory.cache-sessions=true", + "sftp.supplier.factory.allowUnknownKeys=true", + "sftp.supplier.localDir=" + this.targetLocalDirectory.getAbsolutePath(), + "sftp.supplier.remoteDir=sftpSource"); } @Test @SuppressWarnings("unchecked") void supplierForListOnly() { - defaultApplicationContextRunner - .withPropertyValues("sftp.supplier.listOnly=true") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", - Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - HashSet fileNames = new HashSet<>(); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource1.txt")); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource2.txt")); - final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - assertThat(expectedFileNames.get()).contains(message.getPayload()); - expectedFileNames.get().remove(message.getPayload()); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .assertNext(message -> { - assertThat(expectedFileNames.get()).contains(message.getPayload()); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .thenCancel() - .verify(Duration.ofSeconds(30)); - - }); + defaultApplicationContextRunner.withPropertyValues("sftp.supplier.listOnly=true").run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + HashSet fileNames = new HashSet<>(); + fileNames + .add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource1.txt")); + fileNames + .add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource2.txt")); + final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + assertThat(expectedFileNames.get()).contains(message.getPayload()); + expectedFileNames.get().remove(message.getPayload()); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).assertNext(message -> { + assertThat(expectedFileNames.get()).contains(message.getPayload()); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).thenCancel().verify(Duration.ofSeconds(30)); + + }); } @Test @SuppressWarnings("unchecked") void supplierForListOnlyWithPatternFilter() { defaultApplicationContextRunner - .withPropertyValues("sftp.supplier.listOnly=true", - "sftp.supplier.file-name-pattern=.*1.txt") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", - Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + .withPropertyValues("sftp.supplier.listOnly=true", "sftp.supplier.file-name-pattern=.*1.txt") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> assertThat(message.getPayload()).contains("sftpSource1.txt")) - .thenCancel() - .verify(Duration.ofSeconds(30)); + StepVerifier.create(sftpSupplier.get()) + .assertNext(message -> assertThat(message.getPayload()).contains("sftpSource1.txt")) + .thenCancel() + .verify(Duration.ofSeconds(30)); - }); + }); } @Test @SuppressWarnings("unchecked") void supplierForListSortedByFilenameAsc() { defaultApplicationContextRunner - .withPropertyValues("sftp.supplier.listOnly=true", - "sftp.supplier.sortBy.attribute=filename", - "sftp.supplier.sortBy.dir=asc") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", - Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - List fileNames = new ArrayList<>(); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource1.txt")); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource2.txt")); - final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(0)); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .assertNext(message -> { - assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(1)); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .thenCancel() - .verify(Duration.ofSeconds(30)); - - }); + .withPropertyValues("sftp.supplier.listOnly=true", "sftp.supplier.sortBy.attribute=filename", + "sftp.supplier.sortBy.dir=asc") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + List fileNames = new ArrayList<>(); + fileNames.add( + String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource1.txt")); + fileNames.add( + String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource2.txt")); + final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(0)); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).assertNext(message -> { + assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(1)); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).thenCancel().verify(Duration.ofSeconds(30)); + + }); } @Test @SuppressWarnings("unchecked") void supplierForListSortedByFilenameDesc() { defaultApplicationContextRunner - .withPropertyValues("sftp.supplier.listOnly=true", - "sftp.supplier.sortBy.attribute=filename", - "sftp.supplier.sortBy.dir=desc") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", - Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - List fileNames = new ArrayList<>(); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource2.txt")); - fileNames.add(String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), - "sftpSource1.txt")); - final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(0)); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .assertNext(message -> { - assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(1)); - assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)) - .isEqualTo(MediaType.TEXT_PLAIN); - }) - .thenCancel() - .verify(Duration.ofSeconds(30)); - - }); + .withPropertyValues("sftp.supplier.listOnly=true", "sftp.supplier.sortBy.attribute=filename", + "sftp.supplier.sortBy.dir=desc") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + List fileNames = new ArrayList<>(); + fileNames.add( + String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource2.txt")); + fileNames.add( + String.join(properties.getRemoteFileSeparator(), properties.getRemoteDir(), "sftpSource1.txt")); + final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(0)); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).assertNext(message -> { + assertThat(message.getPayload()).isEqualTo(expectedFileNames.get().get(1)); + assertThat(message.getHeaders().get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MediaType.TEXT_PLAIN); + }).thenCancel().verify(Duration.ofSeconds(30)); + + }); } @Test @SuppressWarnings("unchecked") void supplierForFileRef() { defaultApplicationContextRunner - .withPropertyValues( - "sftp.supplier.localDir=" + getTargetLocalDirectory().getAbsolutePath(), - "file.consumer.mode=ref") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - MetadataStore metadataStore = context.getBean(MetadataStore.class); - HashSet fileNames = new HashSet<>(); - fileNames.add(properties.getLocalDir() + File.separator + "sftpSource1.txt"); - fileNames.add(properties.getLocalDir() + File.separator + "sftpSource2.txt"); - final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - File file = message.getPayload(); - assertThat(expectedFileNames.get()).contains(file.getAbsolutePath()); - expectedFileNames.get().remove(file.getAbsolutePath()); - }) - .expectNextMatches( - message -> expectedFileNames.get().contains(message.getPayload().getAbsolutePath())) - .thenCancel() - .verify(Duration.ofSeconds(30)); - - assertThat(metadataStore.get("sftpSource/sftpSource1.txt")).isNotNull(); - assertThat(metadataStore.get("sftpSource/sftpSource2.txt")).isNotNull(); - assertThat(Files.exists(Paths.get(getTargetLocalDirectory().getAbsolutePath(), "sftpSource1.txt"))) - .isTrue(); - assertThat(Files.exists(Paths.get(getTargetLocalDirectory().getAbsolutePath(), "sftpSource2.txt"))) - .isTrue(); - }); + .withPropertyValues("sftp.supplier.localDir=" + getTargetLocalDirectory().getAbsolutePath(), + "file.consumer.mode=ref") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + MetadataStore metadataStore = context.getBean(MetadataStore.class); + HashSet fileNames = new HashSet<>(); + fileNames.add(properties.getLocalDir() + File.separator + "sftpSource1.txt"); + fileNames.add(properties.getLocalDir() + File.separator + "sftpSource2.txt"); + final AtomicReference> expectedFileNames = new AtomicReference<>(fileNames); + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + File file = message.getPayload(); + assertThat(expectedFileNames.get()).contains(file.getAbsolutePath()); + expectedFileNames.get().remove(file.getAbsolutePath()); + }) + .expectNextMatches( + message -> expectedFileNames.get().contains(message.getPayload().getAbsolutePath())) + .thenCancel() + .verify(Duration.ofSeconds(30)); + + assertThat(metadataStore.get("sftpSource/sftpSource1.txt")).isNotNull(); + assertThat(metadataStore.get("sftpSource/sftpSource2.txt")).isNotNull(); + assertThat(Files.exists(Paths.get(getTargetLocalDirectory().getAbsolutePath(), "sftpSource1.txt"))) + .isTrue(); + assertThat(Files.exists(Paths.get(getTargetLocalDirectory().getAbsolutePath(), "sftpSource2.txt"))) + .isTrue(); + }); } @Test @SuppressWarnings("unchecked") void deleteRemoteFiles() { defaultApplicationContextRunner - .withPropertyValues( - "sftp.supplier.stream=true", - "sftp.supplier.delete-remote-files=true") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); - StepVerifier.create(sftpSupplier.get()) - .expectNextMatches(message -> message.getPayload().length > 0) - .expectNextMatches(message -> message.getPayload().length > 0) - .thenCancel() - .verify(Duration.ofSeconds(30)); - await().atMost(Duration.ofSeconds(30)) - .until(() -> getSourceRemoteDirectory().list().length == 0); - }); + .withPropertyValues("sftp.supplier.stream=true", "sftp.supplier.delete-remote-files=true") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + StepVerifier.create(sftpSupplier.get()) + .expectNextMatches(message -> message.getPayload().length > 0) + .expectNextMatches(message -> message.getPayload().length > 0) + .thenCancel() + .verify(Duration.ofSeconds(30)); + await().atMost(Duration.ofSeconds(30)).until(() -> getSourceRemoteDirectory().list().length == 0); + }); } @Test void renameRemoteFilesStream() { defaultApplicationContextRunner - .withPropertyValues( - "sftp.supplier.stream=true", - "sftp.supplier.delete-remote-files=false", - "sftp.supplier.rename-remote-files-to='/sftpTarget/' + headers.file_remoteFile") - .run(this::doTestRenameRemoteFiles); + .withPropertyValues("sftp.supplier.stream=true", "sftp.supplier.delete-remote-files=false", + "sftp.supplier.rename-remote-files-to='/sftpTarget/' + headers.file_remoteFile") + .run(this::doTestRenameRemoteFiles); } @Test void renameRemoteFiles() { defaultApplicationContextRunner - .withPropertyValues( - "sftp.supplier.stream=false", - "sftp.supplier.delete-remote-files=false", - "sftp.supplier.rename-remote-files-to='/sftpTarget/' + headers.file_remoteFile") - .run(this::doTestRenameRemoteFiles); + .withPropertyValues("sftp.supplier.stream=false", "sftp.supplier.delete-remote-files=false", + "sftp.supplier.rename-remote-files-to='/sftpTarget/' + headers.file_remoteFile") + .run(this::doTestRenameRemoteFiles); } @SuppressWarnings("unchecked") @@ -270,109 +231,92 @@ private void doTestRenameRemoteFiles(AssertableApplicationContext context) { Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); final Set expectedTargetFiles = Arrays.stream(getSourceRemoteDirectory().list()) - .collect(Collectors.toSet()); + .collect(Collectors.toSet()); StepVerifier.create(sftpSupplier.get()) - .expectNextMatches(message -> message.getPayload().length > 0) - .expectNextMatches(message -> message.getPayload().length > 0) - .thenCancel() - .verify(Duration.ofSeconds(30)); + .expectNextMatches(message -> message.getPayload().length > 0) + .expectNextMatches(message -> message.getPayload().length > 0) + .thenCancel() + .verify(Duration.ofSeconds(30)); await().atMost(Duration.ofSeconds(30)) - .until(() -> - expectedTargetFiles.equals( - Arrays.stream(getTargetRemoteDirectory().list()) - .collect(Collectors.toSet())) - ); + .until(() -> expectedTargetFiles + .equals(Arrays.stream(getTargetRemoteDirectory().list()).collect(Collectors.toSet()))); } @Test @SuppressWarnings("unchecked") public void streamSourceFilesInLineMode() { defaultApplicationContextRunner - .withPropertyValues( - "sftp.supplier.stream=true", - "sftp.supplier.factory.private-key = classpath:id_rsa_pp", - "sftp.supplier.factory.passphrase = secret", - "sftp.supplier.factory.password = badPassword", // ensure public key was used - "sftp.supplier.delete-remote-files=true", - "file.consumer.mode=lines", - "file.consumer.with-markers=true", - "file.consumer.markers-json=true") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - final Object evaluate; - try { - evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); - assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.START.name()); - } - catch (IOException e) { - fail(e.getMessage()); - } - }) - .expectNextMatches(message -> message.getPayload().startsWith("source")) - .assertNext(message -> { - final Object evaluate; - try { - evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); - assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.END.name()); - } - catch (IOException e) { - fail(e.getMessage()); - } - }) - .thenCancel() - .verify(Duration.ofSeconds(30)); - }); + .withPropertyValues("sftp.supplier.stream=true", "sftp.supplier.factory.private-key = classpath:id_rsa_pp", + "sftp.supplier.factory.passphrase = secret", "sftp.supplier.factory.password = badPassword", // ensure + // public + // key + // was + // used + "sftp.supplier.delete-remote-files=true", "file.consumer.mode=lines", + "file.consumer.with-markers=true", "file.consumer.markers-json=true") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + final Object evaluate; + try { + evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); + assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.START.name()); + } + catch (IOException e) { + fail(e.getMessage()); + } + }).expectNextMatches(message -> message.getPayload().startsWith("source")).assertNext(message -> { + final Object evaluate; + try { + evaluate = JsonPathUtils.evaluate(message.getPayload(), "$.mark"); + assertThat(evaluate).isEqualTo(FileSplitter.FileMarker.Mark.END.name()); + } + catch (IOException e) { + fail(e.getMessage()); + } + }).thenCancel().verify(Duration.ofSeconds(30)); + }); } @Test @SuppressWarnings("unchecked") void supplierWithMultiSourceAndStreamContentsSource3ComesSecond() throws Exception { Path newSource = createNewRemoteSource( - Paths.get(remoteTemporaryFolder.toString(), "sftpSecondSource", "doesNotMatter.txt"), - "source3"); + Paths.get(remoteTemporaryFolder.toString(), "sftpSecondSource", "doesNotMatter.txt"), "source3"); try { - new ApplicationContextRunner() - .withUserConfiguration(SftpSupplierTestApplication.class) - .withPropertyValues( - "sftp.supplier.stream=true", - "sftp.supplier.factories.one.host=localhost", - "sftp.supplier.factories.one.port=${sftp.factory.port}", - "sftp.supplier.factories.one.username=user", - "sftp.supplier.factories.one.password=pass", - "sftp.supplier.factories.one.cache-sessions=true", - "sftp.supplier.factories.one.allowUnknownKeys=true", - "sftp.supplier.factories.two.host=localhost", - "sftp.supplier.factories.two.port=${sftp.factory.port}", - "sftp.supplier.factories.two.username = user", - "sftp.supplier.factories.two.password = pass", - "sftp.supplier.factories.two.cache-sessions = true", - "sftp.supplier.factories.two.allowUnknownKeys = true", - "sftp.supplier.directories=one.sftpSource,two.sftpSecondSource", - "sftp.supplier.max-fetch=1", - "sftp.supplier.fair=true") - .run(context -> { - - Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); - HashSet contents = new HashSet<>(); - contents.add("source1"); - contents.add("source2"); - final AtomicReference> expectedContentsOfAllFiles = new AtomicReference<>(contents); - - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - String payload = new String(message.getPayload()); - assertThat(expectedContentsOfAllFiles.get()).contains(payload); - expectedContentsOfAllFiles.get().remove(payload); - }) - .expectNextMatches(message -> new String(message.getPayload()).equals("source3")) - .expectNextMatches(message -> expectedContentsOfAllFiles.get() - .contains(new String(message.getPayload()))) - .thenCancel() - .verify(Duration.ofSeconds(30)); - }); + new ApplicationContextRunner().withUserConfiguration(SftpSupplierTestApplication.class) + .withPropertyValues("sftp.supplier.stream=true", "sftp.supplier.factories.one.host=localhost", + "sftp.supplier.factories.one.port=${sftp.factory.port}", + "sftp.supplier.factories.one.username=user", "sftp.supplier.factories.one.password=pass", + "sftp.supplier.factories.one.cache-sessions=true", + "sftp.supplier.factories.one.allowUnknownKeys=true", + "sftp.supplier.factories.two.host=localhost", + "sftp.supplier.factories.two.port=${sftp.factory.port}", + "sftp.supplier.factories.two.username = user", "sftp.supplier.factories.two.password = pass", + "sftp.supplier.factories.two.cache-sessions = true", + "sftp.supplier.factories.two.allowUnknownKeys = true", + "sftp.supplier.directories=one.sftpSource,two.sftpSecondSource", "sftp.supplier.max-fetch=1", + "sftp.supplier.fair=true") + .run(context -> { + + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + HashSet contents = new HashSet<>(); + contents.add("source1"); + contents.add("source2"); + final AtomicReference> expectedContentsOfAllFiles = new AtomicReference<>(contents); + + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + String payload = new String(message.getPayload()); + assertThat(expectedContentsOfAllFiles.get()).contains(payload); + expectedContentsOfAllFiles.get().remove(payload); + }) + .expectNextMatches(message -> new String(message.getPayload()).equals("source3")) + .expectNextMatches( + message -> expectedContentsOfAllFiles.get().contains(new String(message.getPayload()))) + .thenCancel() + .verify(Duration.ofSeconds(30)); + }); } finally { deleteNewSource(newSource); @@ -383,56 +327,49 @@ void supplierWithMultiSourceAndStreamContentsSource3ComesSecond() throws Excepti @SuppressWarnings("unchecked") void supplierMultiSourceRefTestsFor200Alex() throws Exception { Path newSource = createNewRemoteSource( - Paths.get(remoteTemporaryFolder.toString(), "sftpSecondSource", "sftpSource3.txt"), - "doesNotMatter"); + Paths.get(remoteTemporaryFolder.toString(), "sftpSecondSource", "sftpSource3.txt"), "doesNotMatter"); try { - new ApplicationContextRunner() - .withUserConfiguration(SftpSupplierTestApplication.class) - .withPropertyValues( - "file.consumer.mode = ref", - "sftp.supplier.localDir=" + this.targetLocalDirectory.getAbsolutePath(), - "sftp.supplier.factories.one.host=localhost", - "sftp.supplier.factories.one.port=${sftp.factory.port}", - "sftp.supplier.factories.one.username = user", - "sftp.supplier.factories.one.password = pass", - "sftp.supplier.factories.one.cache-sessions = true", - "sftp.supplier.factories.one.allowUnknownKeys = true", - "sftp.supplier.factories.two.host=localhost", - "sftp.supplier.factories.two.port=${sftp.factory.port}", - "sftp.supplier.factories.two.username = user", - "sftp.supplier.factories.two.password = pass", - "sftp.supplier.factories.two.cache-sessions = true", - "sftp.supplier.factories.two.allowUnknownKeys = true", - "sftp.supplier.factories.empty.host=localhost", - "sftp.supplier.factories.empty.port=${sftp.factory.port}", - "sftp.supplier.factories.empty.username=user", - "sftp.supplier.factories.empty.password=pass", - "sftp.supplier.factories.empty.allowUnknownKeys = true", - "sftp.supplier.directories=one.sftpSource,two.sftpSecondSource,empty.sftpSource", - "sftp.supplier.max-fetch=1", - "sftp.supplier.fair=true") - .run(context -> { - Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); - SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); - String localDir = properties.getLocalDir().getPath(); - HashSet firstSourceFiles = new HashSet<>(); - firstSourceFiles.add(Paths.get(localDir, "sftpSource1.txt").toString()); - firstSourceFiles.add(Paths.get(localDir, "sftpSource2.txt").toString()); - final AtomicReference> expectedFirstSourcePaths = new AtomicReference<>( - firstSourceFiles); - - StepVerifier.create(sftpSupplier.get()) - .assertNext(message -> { - assertThat(expectedFirstSourcePaths.get()).contains(message.getPayload().getPath()); - expectedFirstSourcePaths.get().remove(message.getPayload().getPath()); - }) - .expectNextMatches(message -> message.getPayload().getPath().equals( - Paths.get(localDir, "sftpSource3.txt").toString())) - .expectNextMatches(message -> expectedFirstSourcePaths.get() - .contains(message.getPayload().getPath())) - .thenCancel() - .verify(Duration.ofSeconds(10)); - }); + new ApplicationContextRunner().withUserConfiguration(SftpSupplierTestApplication.class) + .withPropertyValues("file.consumer.mode = ref", + "sftp.supplier.localDir=" + this.targetLocalDirectory.getAbsolutePath(), + "sftp.supplier.factories.one.host=localhost", + "sftp.supplier.factories.one.port=${sftp.factory.port}", + "sftp.supplier.factories.one.username = user", "sftp.supplier.factories.one.password = pass", + "sftp.supplier.factories.one.cache-sessions = true", + "sftp.supplier.factories.one.allowUnknownKeys = true", + "sftp.supplier.factories.two.host=localhost", + "sftp.supplier.factories.two.port=${sftp.factory.port}", + "sftp.supplier.factories.two.username = user", "sftp.supplier.factories.two.password = pass", + "sftp.supplier.factories.two.cache-sessions = true", + "sftp.supplier.factories.two.allowUnknownKeys = true", + "sftp.supplier.factories.empty.host=localhost", + "sftp.supplier.factories.empty.port=${sftp.factory.port}", + "sftp.supplier.factories.empty.username=user", "sftp.supplier.factories.empty.password=pass", + "sftp.supplier.factories.empty.allowUnknownKeys = true", + "sftp.supplier.directories=one.sftpSource,two.sftpSecondSource,empty.sftpSource", + "sftp.supplier.max-fetch=1", "sftp.supplier.fair=true") + .run(context -> { + Supplier>> sftpSupplier = context.getBean("sftpSupplier", Supplier.class); + SftpSupplierProperties properties = context.getBean(SftpSupplierProperties.class); + String localDir = properties.getLocalDir().getPath(); + HashSet firstSourceFiles = new HashSet<>(); + firstSourceFiles.add(Paths.get(localDir, "sftpSource1.txt").toString()); + firstSourceFiles.add(Paths.get(localDir, "sftpSource2.txt").toString()); + final AtomicReference> expectedFirstSourcePaths = new AtomicReference<>( + firstSourceFiles); + + StepVerifier.create(sftpSupplier.get()).assertNext(message -> { + assertThat(expectedFirstSourcePaths.get()).contains(message.getPayload().getPath()); + expectedFirstSourcePaths.get().remove(message.getPayload().getPath()); + }) + .expectNextMatches(message -> message.getPayload() + .getPath() + .equals(Paths.get(localDir, "sftpSource3.txt").toString())) + .expectNextMatches( + message -> expectedFirstSourcePaths.get().contains(message.getPayload().getPath())) + .thenCancel() + .verify(Duration.ofSeconds(10)); + }); } finally { deleteNewSource(newSource); diff --git a/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierConfiguration.java b/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierConfiguration.java index dbd9a093..f78bf3f4 100644 --- a/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierConfiguration.java +++ b/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierConfiguration.java @@ -60,19 +60,19 @@ public FluxMessageChannel syslogInputChannel() { } @Bean - public Supplier>> syslogSupplier(ObjectProvider udpAdapterProvider, - ObjectProvider tcpAdapterProvider) { - return () -> Flux.from(syslogInputChannel()) - .doOnSubscribe(subscription -> { - final UdpSyslogReceivingChannelAdapter udpAdapter = udpAdapterProvider.getIfAvailable(); - final TcpSyslogReceivingChannelAdapter tcpAdapter = tcpAdapterProvider.getIfAvailable(); - if (udpAdapter != null) { - udpAdapter.start(); - } - if (tcpAdapter != null) { - tcpAdapter.start(); - } - }); + public Supplier>> syslogSupplier( + ObjectProvider udpAdapterProvider, + ObjectProvider tcpAdapterProvider) { + return () -> Flux.from(syslogInputChannel()).doOnSubscribe(subscription -> { + final UdpSyslogReceivingChannelAdapter udpAdapter = udpAdapterProvider.getIfAvailable(); + final TcpSyslogReceivingChannelAdapter tcpAdapter = tcpAdapterProvider.getIfAvailable(); + if (udpAdapter != null) { + udpAdapter.start(); + } + if (tcpAdapter != null) { + tcpAdapter.start(); + } + }); } @Bean @@ -131,7 +131,6 @@ private void setAdapterProperties(SyslogReceivingChannelAdapterSupport adapter) adapter.setAutoStartup(false); } - @Configuration @ConditionalOnProperty(name = "syslog.supplier.protocol", havingValue = "tcp", matchIfMissing = true) protected static class TcpBits { @@ -166,6 +165,7 @@ public Deserializer syslogSupplierDecoder() { return decoder; } } + } @Configuration diff --git a/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierProperties.java b/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierProperties.java index 8240290e..bb2b1526 100644 --- a/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierProperties.java +++ b/supplier/spring-syslog-supplier/src/main/java/org/springframework/cloud/fn/supplier/syslog/SyslogSupplierProperties.java @@ -57,7 +57,8 @@ public class SyslogSupplierProperties { private int socketTimeout; /** - * '5424' or '3164' - the syslog format according to the RFC; 3164 is aka 'BSD' format. + * '5424' or '3164' - the syslog format according to the RFC; 3164 is aka 'BSD' + * format. */ private String rfc = "3164"; @@ -124,6 +125,7 @@ public boolean isSupportedRfc() { } public enum Protocol { + /** * TCP protocol. */ @@ -138,5 +140,7 @@ public enum Protocol { * Represents both TCP and UDP. */ both; + } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/AbstractSyslogSupplierTests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/AbstractSyslogSupplierTests.java index 599f1581..ef163d36 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/AbstractSyslogSupplierTests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/AbstractSyslogSupplierTests.java @@ -38,18 +38,16 @@ import static org.assertj.core.api.Assertions.assertThat; - @SpringBootTest(properties = "syslog.supplier.port = 0") @DirtiesContext public class AbstractSyslogSupplierTests { protected static final String RFC3164_PACKET = "<157>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE"; - protected static final String RFC5424_PACKET = - "<14>1 2014-06-20T09:14:07+00:00 loggregator d0602076-b14a-4c55-852a-981e7afeed38 DEA - " - + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"]" - + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"] " - + "Removing instance"; + protected static final String RFC5424_PACKET = "<14>1 2014-06-20T09:14:07+00:00 loggregator d0602076-b14a-4c55-852a-981e7afeed38 DEA - " + + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"]" + + "[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"] " + + "Removing instance"; @Autowired Supplier>> syslogSupplier; diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/NotNioTests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/NotNioTests.java index fd485d96..3aab6dd2 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/NotNioTests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/NotNioTests.java @@ -32,4 +32,5 @@ public void test() throws Exception { assertThat(TestUtils.getPropertyValue(this.connectionFactory, "soTimeout")).isEqualTo(0); assertThat(TestUtils.getPropertyValue(this.connectionFactory, "deserializer.maxMessageSize")).isEqualTo(2048); } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/PropertiesPopulatedTests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/PropertiesPopulatedTests.java index 5e2c7dbb..a3d7ae08 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/PropertiesPopulatedTests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/PropertiesPopulatedTests.java @@ -24,8 +24,9 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestPropertySource(properties = { "syslog.supplier.port = 0", "syslog.supplier.nio = true", "syslog.supplier.reverseLookup = true", - "syslog.supplier.socketTimeout = 123", "syslog.supplier.bufferSize = 5" }) +@TestPropertySource( + properties = { "syslog.supplier.port = 0", "syslog.supplier.nio = true", "syslog.supplier.reverseLookup = true", + "syslog.supplier.socketTimeout = 123", "syslog.supplier.bufferSize = 5" }) public class PropertiesPopulatedTests extends AbstractSyslogSupplierTests { @Test @@ -35,4 +36,5 @@ public void test() throws Exception { assertThat(TestUtils.getPropertyValue(this.connectionFactory, "soTimeout")).isEqualTo(123); assertThat(TestUtils.getPropertyValue(this.connectionFactory, "deserializer.maxMessageSize")).isEqualTo(5); } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp3164Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp3164Tests.java index 648a4130..bb1a774f 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp3164Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp3164Tests.java @@ -32,16 +32,13 @@ public class Tcp3164Tests extends AbstractSyslogSupplierTests { public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); + }).thenCancel().verifyLater(); sendTcp(AbstractSyslogSupplierTests.RFC3164_PACKET + "\n"); stepVerifier.verify(); } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp5424Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp5424Tests.java index a0934956..2b372d57 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp5424Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Tcp5424Tests.java @@ -34,16 +34,13 @@ public class Tcp5424Tests extends AbstractSyslogSupplierTests { public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); + }).thenCancel().verifyLater(); sendTcp("253 " + RFC5424_PACKET); stepVerifier.verify(); } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp3164Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp3164Tests.java index da19ce97..9c4db156 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp3164Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp3164Tests.java @@ -33,20 +33,15 @@ public class TcpAndUdp3164Tests extends AbstractSyslogSupplierTests { @Test public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); - } - ) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); + }).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); + }).thenCancel().verifyLater(); sendTcp(RFC3164_PACKET + "\n"); sendUdp(RFC3164_PACKET); stepVerifier.verify(); } + } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp5424Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp5424Tests.java index 394ce58c..00e6ddce 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp5424Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/TcpAndUdp5424Tests.java @@ -33,17 +33,11 @@ public class TcpAndUdp5424Tests extends AbstractSyslogSupplierTests { @Test public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); - } - ) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); + }).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); + }).thenCancel().verifyLater(); sendTcp("253 " + RFC5424_PACKET); sendUdp(RFC5424_PACKET); diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp3164Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp3164Tests.java index ab1ccf6a..e8578924 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp3164Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp3164Tests.java @@ -34,19 +34,14 @@ public class Udp3164Tests extends AbstractSyslogSupplierTests { public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("HOST")).isEqualTo("WEBERN"); + }).thenCancel().verifyLater(); sendUdp(RFC3164_PACKET); stepVerifier.verify(); - } } diff --git a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp5424Tests.java b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp5424Tests.java index c64cf307..94d41c40 100644 --- a/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp5424Tests.java +++ b/supplier/spring-syslog-supplier/src/test/java/org/springframework/cloud/fn/supplier/syslog/Udp5424Tests.java @@ -33,15 +33,12 @@ public class Udp5424Tests extends AbstractSyslogSupplierTests { @Test public void test() throws Exception { final Flux> messageFlux = syslogSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); - } - ) - .thenCancel() - .verifyLater(); + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(((Map) message.getPayload()).get("syslog_HOST")).isEqualTo("loggregator"); + }).thenCancel().verifyLater(); sendUdp(RFC5424_PACKET); stepVerifier.verify(); } + } diff --git a/supplier/spring-tcp-supplier/src/main/java/org/springframework/cloud/fn/supplier/tcp/TcpSupplierConfiguration.java b/supplier/spring-tcp-supplier/src/main/java/org/springframework/cloud/fn/supplier/tcp/TcpSupplierConfiguration.java index d5370ab0..b3f4a256 100644 --- a/supplier/spring-tcp-supplier/src/main/java/org/springframework/cloud/fn/supplier/tcp/TcpSupplierConfiguration.java +++ b/supplier/spring-tcp-supplier/src/main/java/org/springframework/cloud/fn/supplier/tcp/TcpSupplierConfiguration.java @@ -82,18 +82,14 @@ public TcpReceivingChannelAdapter adapter( @Bean public Publisher> tcpSupplierFlow(TcpReceivingChannelAdapter adapter) { - return IntegrationFlow.from(adapter) - .headerFilter(IpHeaders.LOCAL_ADDRESS) - .toReactivePublisher(); + return IntegrationFlow.from(adapter).headerFilter(IpHeaders.LOCAL_ADDRESS).toReactivePublisher(); } @Bean - public Supplier>> tcpSupplier( - Publisher> tcpSupplierFlow, + public Supplier>> tcpSupplier(Publisher> tcpSupplierFlow, TcpReceivingChannelAdapter tcpReceivingChannelAdapter) { - return () -> Flux.from(tcpSupplierFlow) - .doOnSubscribe(subscription -> tcpReceivingChannelAdapter.start()); + return () -> Flux.from(tcpSupplierFlow).doOnSubscribe(subscription -> tcpReceivingChannelAdapter.start()); } } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/AbstractTcpSupplierTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/AbstractTcpSupplierTests.java index d3ab0995..627b5425 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/AbstractTcpSupplierTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/AbstractTcpSupplierTests.java @@ -54,27 +54,18 @@ public class AbstractTcpSupplierTests { protected TcpSupplierProperties properties; /* - * Sends two messages with and asserts the - * payload is received on the other side. + * Sends two messages with and asserts the payload is + * received on the other side. */ protected void doTest(String prefix, String payload, String suffix) throws Exception { final Flux> messageFlux = tcpSupplier.get(); - final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(payload.getBytes()); - } - ) - .assertNext((message) -> { - assertThat(message.getPayload()) - .isEqualTo(payload.getBytes()); - } - ) - .thenCancel() - .verifyLater(); - + final StepVerifier stepVerifier = StepVerifier.create(messageFlux).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(payload.getBytes()); + }).assertNext((message) -> { + assertThat(message.getPayload()).isEqualTo(payload.getBytes()); + }).thenCancel().verifyLater(); int port = getPort(); Socket socket = SocketFactory.getDefault().createSocket("localhost", port); @@ -108,4 +99,5 @@ private int getPort() throws Exception { public static class TcpSupplierTestApplication { } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/CRLFTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/CRLFTests.java index a19543cb..70f808ba 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/CRLFTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/CRLFTests.java @@ -27,4 +27,5 @@ public class CRLFTests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("", "foo", "\r\n"); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L1Tests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L1Tests.java index 7aec2c43..d326a356 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L1Tests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L1Tests.java @@ -30,4 +30,5 @@ public class L1Tests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("\u0003", "foo", ""); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L2Tests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L2Tests.java index f2d7144c..3bb5ea6e 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L2Tests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L2Tests.java @@ -30,4 +30,5 @@ public class L2Tests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("\u0000\u0003", "foo", ""); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L4Tests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L4Tests.java index 1d0210a1..cf54ac0f 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L4Tests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/L4Tests.java @@ -30,4 +30,5 @@ public class L4Tests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("\u0000\u0000\u0000\u0003", "foo", ""); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/LFTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/LFTests.java index cbb89888..47467bff 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/LFTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/LFTests.java @@ -30,4 +30,5 @@ public class LFTests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("", "foo", "\n"); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NULLTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NULLTests.java index 9aac7d4a..1e1f1715 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NULLTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NULLTests.java @@ -30,4 +30,5 @@ public class NULLTests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("", "foo", "\u0000"); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NotNioTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NotNioTests.java index 2d7e039d..5932b173 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NotNioTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/NotNioTests.java @@ -35,4 +35,5 @@ public void test() { assertThat(TestUtils.getPropertyValue(this.connectionFactory, "soTimeout")).isEqualTo(120000); assertThat(TestUtils.getPropertyValue(this.connectionFactory, "deserializer.maxMessageSize")).isEqualTo(2048); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/PropertiesPopulatedTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/PropertiesPopulatedTests.java index d3aff90a..8d6426f7 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/PropertiesPopulatedTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/PropertiesPopulatedTests.java @@ -27,8 +27,8 @@ /** * @author Gary Russell */ -@TestPropertySource(properties = {"tcp.nio = true", "tcp.reverseLookup = true", - "tcp.useDirectBuffers = true", "tcp.socketTimeout = 123", "tcp.supplier.bufferSize = 5"}) +@TestPropertySource(properties = { "tcp.nio = true", "tcp.reverseLookup = true", "tcp.useDirectBuffers = true", + "tcp.socketTimeout = 123", "tcp.supplier.bufferSize = 5" }) public class PropertiesPopulatedTests extends AbstractTcpSupplierTests { @Test diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/RAWTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/RAWTests.java index 6ab80d62..469ecce2 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/RAWTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/RAWTests.java @@ -30,4 +30,5 @@ public class RAWTests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("", "foo", ""); } + } diff --git a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/STXETXTests.java b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/STXETXTests.java index 1f3111a3..097ca1ee 100644 --- a/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/STXETXTests.java +++ b/supplier/spring-tcp-supplier/src/test/java/org/springframework/cloud/fn/supplier/tcp/STXETXTests.java @@ -30,4 +30,5 @@ public class STXETXTests extends AbstractTcpSupplierTests { public void test() throws Exception { doTest("\u0002", "foo", "\u0003"); } + } diff --git a/supplier/spring-time-supplier/src/main/java/org/springframework/cloud/fn/supplier/time/DateFormat.java b/supplier/spring-time-supplier/src/main/java/org/springframework/cloud/fn/supplier/time/DateFormat.java index 7e94ef58..5c224f7e 100644 --- a/supplier/spring-time-supplier/src/main/java/org/springframework/cloud/fn/supplier/time/DateFormat.java +++ b/supplier/spring-time-supplier/src/main/java/org/springframework/cloud/fn/supplier/time/DateFormat.java @@ -34,11 +34,11 @@ * @author Eric Bottard * @author Soby Chacko */ -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, - ElementType.PARAMETER}) +@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, + ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @Documented -@Constraint(validatedBy = {DateFormat.DateFormatValidator.class}) +@Constraint(validatedBy = { DateFormat.DateFormatValidator.class }) public @interface DateFormat { /** diff --git a/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/TimeSupplierApplicationTests.java b/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/TimeSupplierApplicationTests.java index 2812f492..63341054 100644 --- a/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/TimeSupplierApplicationTests.java +++ b/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/TimeSupplierApplicationTests.java @@ -39,5 +39,7 @@ public abstract class TimeSupplierApplicationTests { @SpringBootApplication static class TimeSupplierTestApplication { + } + } diff --git a/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/VariationToSimpleTests.java b/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/VariationToSimpleTests.java index c33edb35..65edf54c 100644 --- a/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/VariationToSimpleTests.java +++ b/supplier/spring-time-supplier/src/test/java/org/springframework/cloud/fn/supplier/time/VariationToSimpleTests.java @@ -31,7 +31,7 @@ * @author Soby Chacko * @author Artem Bilan */ -@SpringBootTest({"time.dateFormat=MMddyyyy HH:mm:ss"}) +@SpringBootTest({ "time.dateFormat=MMddyyyy HH:mm:ss" }) public class VariationToSimpleTests extends TimeSupplierApplicationTests { @Test @@ -48,7 +48,8 @@ public void testTimeSupplier() { public void testInvalidDateFormat() { TimeSupplierProperties timeSupplierProperties = new TimeSupplierProperties(); timeSupplierProperties.setDateFormat("AA/dd/yyyy HH:mm:ss"); - assertThatIllegalArgumentException().isThrownBy(() -> new SimpleDateFormat(timeSupplierProperties.getDateFormat())); + assertThatIllegalArgumentException() + .isThrownBy(() -> new SimpleDateFormat(timeSupplierProperties.getDateFormat())); } } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierConfiguration.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierConfiguration.java index 58587056..ed64bba3 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierConfiguration.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierConfiguration.java @@ -41,7 +41,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @Configuration @@ -63,11 +62,10 @@ public Cursor cursor() { return new Cursor(); } - @Bean @ConditionalOnProperty(name = "twitter.friendships.source.type", havingValue = "followers") - public Supplier> followersSupplier(TwitterFriendshipsSupplierProperties properties, - Twitter twitter, Cursor cursorState) { + public Supplier> followersSupplier(TwitterFriendshipsSupplierProperties properties, Twitter twitter, + Cursor cursorState) { return () -> { try { PagableResponseList users; @@ -85,7 +83,8 @@ public Supplier> followersSupplier(TwitterFriendshipsSupplierProperti return users; } - logger.error(String.format("NULL users response for properties: %s and cursor: %s!", properties, cursorState)); + logger.error(String.format("NULL users response for properties: %s and cursor: %s!", properties, + cursorState)); cursorState.updateCursor(-1); } catch (TwitterException e) { @@ -98,8 +97,8 @@ public Supplier> followersSupplier(TwitterFriendshipsSupplierProperti @Bean @ConditionalOnProperty(name = "twitter.friendships.source.type", havingValue = "friends") - public Supplier> friendsSupplier(TwitterFriendshipsSupplierProperties properties, - Twitter twitter, Cursor cursorState) { + public Supplier> friendsSupplier(TwitterFriendshipsSupplierProperties properties, Twitter twitter, + Cursor cursorState) { return () -> { try { PagableResponseList users; @@ -117,7 +116,8 @@ public Supplier> friendsSupplier(TwitterFriendshipsSupplierProperties return users; } - logger.error(String.format("NULL users response for properties: %s and cursor: %s!", properties, cursorState)); + logger.error(String.format("NULL users response for properties: %s and cursor: %s!", properties, + cursorState)); cursorState.updateCursor(-1); } catch (TwitterException e) { @@ -147,4 +147,5 @@ public Supplier> deduplicatedFriendsJsonSupplier(Function> userRetriever, Function> managedJson) { return () -> userDeduplication.andThen(managedJson).apply(userRetriever.get()); } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierProperties.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierProperties.java index 4031e5c3..9fac4a83 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierProperties.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/friendships/TwitterFriendshipsSupplierProperties.java @@ -24,7 +24,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -33,8 +32,10 @@ public class TwitterFriendshipsSupplierProperties { public enum FriendshipsRequestType { + /** Friendship query types. */ followers, friends + } /** @@ -71,7 +72,8 @@ public enum FriendshipsRequestType { private boolean includeUserEntities = true; /** - * API request poll interval in milliseconds. Must be aligned with used APIs rate limits (~ 1 req/ 2 min). + * API request poll interval in milliseconds. Must be aligned with used APIs rate + * limits (~ 1 req/ 2 min). */ private int pollInterval = 121000; @@ -138,14 +140,9 @@ public boolean isUserProvided() { @Override public String toString() { - return "TwitterFriendshipsSourceProperties{" + - "type=" + type + - ", screenName='" + screenName + '\'' + - ", userId=" + userId + - ", count=" + count + - ", skipStatus=" + skipStatus + - ", includeUserEntities=" + includeUserEntities + - ", pollInterval=" + pollInterval + - '}'; + return "TwitterFriendshipsSourceProperties{" + "type=" + type + ", screenName='" + screenName + '\'' + + ", userId=" + userId + ", count=" + count + ", skipStatus=" + skipStatus + ", includeUserEntities=" + + includeUserEntities + ", pollInterval=" + pollInterval + '}'; } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierConfiguration.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierConfiguration.java index cc921f00..62a4d464 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierConfiguration.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierConfiguration.java @@ -38,7 +38,6 @@ import org.springframework.messaging.Message; /** - * * @author Christian Tzolov */ @EnableConfigurationProperties({ TwitterMessageSupplierProperties.class }) @@ -65,16 +64,17 @@ public Supplier> directMessagesSupplier(TwitterMessageSuppli return () -> { try { String cs = cursorState.getCursor(); - DirectMessageList messages = (cursorState.getCursor() == null) ? - twitter.getDirectMessages(properties.getCount()) : - twitter.getDirectMessages(properties.getCount(), cursorState.getCursor()); + DirectMessageList messages = (cursorState.getCursor() == null) + ? twitter.getDirectMessages(properties.getCount()) + : twitter.getDirectMessages(properties.getCount(), cursorState.getCursor()); if (messages != null) { cursorState.updateCursor(messages.getNextCursor()); return messages; } - logger.error(String.format("NULL messages response for properties: %s and cursor: %s!", properties, cursorState)); + logger.error(String.format("NULL messages response for properties: %s and cursor: %s!", properties, + cursorState)); cursorState.updateCursor(null); } catch (TwitterException e) { @@ -100,12 +100,14 @@ public Function, List> messageDeduplicate(Met } @Bean - public Supplier> twitterMessageSupplier(Function, List> messageDeduplicate, + public Supplier> twitterMessageSupplier( + Function, List> messageDeduplicate, Function> managedJson, Supplier> directMessagesSupplier) { return () -> messageDeduplicate.andThen(managedJson).apply(directMessagesSupplier.get()); } public static class MessageCursor { + private String cursor = null; public String getCursor() { @@ -118,9 +120,9 @@ public void updateCursor(String newCursor) { @Override public String toString() { - return "Cursor{" + - "cursor=" + cursor + - '}'; + return "Cursor{" + "cursor=" + cursor + '}'; } + } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierProperties.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierProperties.java index dedee2fd..50e7ab09 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierProperties.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/message/TwitterMessageSupplierProperties.java @@ -21,7 +21,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; - /** * @author Christian Tzolov */ @@ -42,4 +41,5 @@ public int getCount() { public void setCount(int count) { this.count = count; } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPagination.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPagination.java index c13a15a2..a5b68079 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPagination.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPagination.java @@ -23,23 +23,28 @@ import org.springframework.util.Assert; /** - * Searched tweets are ordered from top to bottom by their IDs. The higher the ID, more recent the tweet is. + * Searched tweets are ordered from top to bottom by their IDs. The higher the ID, more + * recent the tweet is. * - * The search goes backwards - from most recent to the oldest tweets and it uses the sinceId and the maxId to retrieve - * only tweets with IDs in the [sinceId, maxId) range. The -1 stands for unbounded sinceId or maxId. + * The search goes backwards - from most recent to the oldest tweets and it uses the + * sinceId and the maxId to retrieve only tweets with IDs in the [sinceId, maxId) range. + * The -1 stands for unbounded sinceId or maxId. * - * The first `pageCount` number requests are performed backwards, leaving the bottom boundary (sinceId) unbounded and - * adjusting the upper boundary (maxId) to the lowest tweet ID received. This ensures that no already processed - * tweets are returned. + * The first `pageCount` number requests are performed backwards, leaving the bottom + * boundary (sinceId) unbounded and adjusting the upper boundary (maxId) to the lowest + * tweet ID received. This ensures that no already processed tweets are returned. * - * The pageCounter is used the to count the number of pages retrieved in the pageCount range. Is starts from pageCount - * and goes backward until 0. On 0 the pageCounter is reset back to pageCount. + * The pageCounter is used the to count the number of pages retrieved in the pageCount + * range. Is starts from pageCount and goes backward until 0. On 0 the pageCounter is + * reset back to pageCount. * - * After performing pageCount number requests (e.g. pageCounter = 0), we start new iteration of searches from the top, - * most recent tweets but now the bottom boundary (sinceId) is adjusted to the max ID received so far. That means that - * only the newly added tweets will be processed + * After performing pageCount number requests (e.g. pageCounter = 0), we start new + * iteration of searches from the top, most recent tweets but now the bottom boundary + * (sinceId) is adjusted to the max ID received so far. That means that only the newly + * added tweets will be processed * - * Search pagination with max_id and since_id: https://developer.twitter.com/en/docs/tweets/timelines/guides/working-with-timelines.html + * Search pagination with max_id and since_id: + * https://developer.twitter.com/en/docs/tweets/timelines/guides/working-with-timelines.html * * @author Christian Tzolov */ @@ -53,8 +58,8 @@ public class SearchPagination { /** * Number of pages to search in history before start form the top again. * - * Note that the search goes backwards - from most recent to the oldest tweets. - * (eg. maxId == To max ID , sinceId == From min ID) + * Note that the search goes backwards - from most recent to the oldest tweets. (eg. + * maxId == To max ID , sinceId == From min ID) */ private final int pageCount; @@ -113,18 +118,15 @@ public int getPageCounter() { public void update(List tweets) { - tweets.stream().mapToLong(t -> t.getId()).min() - .ifPresent(tweetsMinId -> { - this.maxId = tweetsMinId - 1; - }); + tweets.stream().mapToLong(t -> t.getId()).min().ifPresent(tweetsMinId -> { + this.maxId = tweetsMinId - 1; + }); - tweets.stream().mapToLong(t -> t.getId()).max() - .ifPresent(tweetsMaxId -> { - Assert.isTrue(this.sinceId <= tweetsMaxId, - String.format("MAX_ID (%s) must be bigger then current SINCE_ID(%s)", - tweetsMaxId, this.sinceId)); - this.pageMaxId = Math.max(this.pageMaxId, tweetsMaxId); - }); + tweets.stream().mapToLong(t -> t.getId()).max().ifPresent(tweetsMaxId -> { + Assert.isTrue(this.sinceId <= tweetsMaxId, + String.format("MAX_ID (%s) must be bigger then current SINCE_ID(%s)", tweetsMaxId, this.sinceId)); + this.pageMaxId = Math.max(this.pageMaxId, tweetsMaxId); + }); this.countDown(tweets.size()); } @@ -160,7 +162,8 @@ private void restartSearchFromMostRecent() { } public String status() { - return String.format("MaxId: %s, SinceId: %s, Page Counter# %s, pageMaxId: %s", - this.maxId, this.sinceId, this.pageCounter, this.pageMaxId); + return String.format("MaxId: %s, SinceId: %s, Page Counter# %s, pageMaxId: %s", this.maxId, this.sinceId, + this.pageCounter, this.pageMaxId); } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierConfiguration.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierConfiguration.java index 8b04df48..e153cbb1 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierConfiguration.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierConfiguration.java @@ -39,7 +39,9 @@ import org.springframework.util.StringUtils; /** - * Search pagination with max_id and since_id: https://developer.twitter.com/en/docs/tweets/timelines/guides/working-with-timelines.html . + * Search pagination with max_id and since_id: + * https://developer.twitter.com/en/docs/tweets/timelines/guides/working-with-timelines.html + * . * * @author Christian Tzolov * @author Chris Bono @@ -61,12 +63,10 @@ public class TwitterSearchSupplierConfiguration { @Bean public SearchPagination searchPage() { - return new SearchPagination( - this.searchProperties.getPage(), + return new SearchPagination(this.searchProperties.getPage(), this.searchProperties.isRestartFromMostRecentOnEmptyResponse()); } - @Bean public Supplier> twitterSearchSupplier(SearchPagination searchPage) { return () -> { @@ -108,11 +108,9 @@ private Query toQuery(TwitterSearchSupplierProperties searchProperties, SearchPa } if (searchProperties.getGeocode().isValid()) { query.setGeoCode( - new GeoLocation( - searchProperties.getGeocode().getLatitude(), + new GeoLocation(searchProperties.getGeocode().getLatitude(), searchProperties.getGeocode().getLongitude()), - searchProperties.getGeocode().getRadius(), - Query.KILOMETERS); + searchProperties.getGeocode().getRadius(), Query.KILOMETERS); } if (searchProperties.getResultType() != Query.ResultType.mixed) { @@ -132,4 +130,5 @@ private Query toQuery(TwitterSearchSupplierProperties searchProperties, SearchPa return query; } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierProperties.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierProperties.java index 2cc9d726..76e9509c 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierProperties.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/search/TwitterSearchSupplierProperties.java @@ -41,9 +41,9 @@ public class TwitterSearchSupplierProperties { private String query; /** - * Number of pages (e.g. requests) to search backwards (from most recent to the oldest tweets) before start - * the search from the most recent tweets again. - * The total amount of tweets searched backwards is (page * count) + * Number of pages (e.g. requests) to search backwards (from most recent to the oldest + * tweets) before start the search from the most recent tweets again. The total amount + * of tweets searched backwards is (page * count) */ @Positive private int page = 3; @@ -56,36 +56,37 @@ public class TwitterSearchSupplierProperties { private int count = 100; /** - * Restricts searched tweets to the given language, given by an http://en.wikipedia.org/wiki/ISO_639-1 . + * Restricts searched tweets to the given language, given by an + * http://en.wikipedia.org/wiki/ISO_639-1 . */ private String lang = null; /** - * If specified, returns tweets with since the given date. Date should be formatted as YYYY-MM-DD. + * If specified, returns tweets with since the given date. Date should be formatted as + * YYYY-MM-DD. */ @Pattern(regexp = "^\\d{4}-\\d{2}-\\d{2}$") private String since = null; /** - * If specified, returns tweets by users located within a given radius (in Km) of the given latitude/longitude, - * where the user's location is taken from their Twitter profile. - * Should be formatted as + * If specified, returns tweets by users located within a given radius (in Km) of the + * given latitude/longitude, where the user's location is taken from their Twitter + * profile. Should be formatted as */ private Geocode geocode = new Geocode(); /** - * Specifies what type of search results you would prefer to receive. - * The current default is "mixed." Valid values include: - * mixed : Include both popular and real time results in the response. - * recent : return only the most recent results in the response - * popular : return only the most popular results in the response + * Specifies what type of search results you would prefer to receive. The current + * default is "mixed." Valid values include: mixed : Include both popular and real + * time results in the response. recent : return only the most recent results in the + * response popular : return only the most popular results in the response */ @NotNull private Query.ResultType resultType = Query.ResultType.mixed; /** - * Restart search from the most recent tweets on empty response. - * Applied only after the first restart (e.g. when since_id != UNBOUNDED) + * Restart search from the most recent tweets on empty response. Applied only after + * the first restart (e.g. when since_id != UNBOUNDED) */ private boolean restartFromMostRecentOnEmptyResponse = false; @@ -193,5 +194,7 @@ public void setRadius(double radius) { public boolean isValid() { return this.radius > 0; } + } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierConfiguration.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierConfiguration.java index 9f9ee239..2eb2f9e1 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierConfiguration.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierConfiguration.java @@ -41,7 +41,6 @@ import org.springframework.util.MimeTypeUtils; /** - * * @author Christian Tzolov */ @@ -57,8 +56,8 @@ public FluxMessageChannel twitterStatusInputChannel() { } @Bean - public StatusListener twitterStatusListener(FluxMessageChannel twitterStatusInputChannel, TwitterStream twitterStream, - ObjectMapper objectMapper) { + public StatusListener twitterStatusListener(FluxMessageChannel twitterStatusInputChannel, + TwitterStream twitterStream, ObjectMapper objectMapper) { StatusListener statusListener = new StatusListener() { @@ -90,8 +89,8 @@ public void onStatus(Status status) { try { String json = objectMapper.writeValueAsString(status); Message message = MessageBuilder.withPayload(json.getBytes()) - .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE) - .build(); + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE) + .build(); twitterStatusInputChannel.send(message); } catch (JsonProcessingException e) { @@ -115,40 +114,38 @@ public void onTrackLimitationNotice(int numberOfLimitedStatuses) { public Supplier>> twitterStreamSupplier(TwitterStream twitterStream, FluxMessageChannel twitterStatusInputChannel, TwitterStreamSupplierProperties streamProperties) { - return () -> Flux.from(twitterStatusInputChannel) - .doOnSubscribe(subscription -> { - try { - switch (streamProperties.getType()) { - - case filter: - twitterStream.filter(streamProperties.getFilter().toFilterQuery()); - return; - - case sample: - twitterStream.sample(); - return; - - case firehose: - twitterStream.firehose(streamProperties.getFilter().getCount()); - return; - - case link: - twitterStream.links(streamProperties.getFilter().getCount()); - return; - default: - throw new IllegalArgumentException("Unknown stream type:" + streamProperties.getType()); - } - } - catch (Exception e) { - this.logger.error("Filter is not property set"); - } - }) - .doAfterTerminate(() -> { - this.logger.info("Proactive cancel for twitter stream"); - twitterStream.shutdown(); - }) - .doOnError(throwable -> { - this.logger.error(throwable.getMessage(), throwable); - }); + return () -> Flux.from(twitterStatusInputChannel).doOnSubscribe(subscription -> { + try { + switch (streamProperties.getType()) { + + case filter: + twitterStream.filter(streamProperties.getFilter().toFilterQuery()); + return; + + case sample: + twitterStream.sample(); + return; + + case firehose: + twitterStream.firehose(streamProperties.getFilter().getCount()); + return; + + case link: + twitterStream.links(streamProperties.getFilter().getCount()); + return; + default: + throw new IllegalArgumentException("Unknown stream type:" + streamProperties.getType()); + } + } + catch (Exception e) { + this.logger.error("Filter is not property set"); + } + }).doAfterTerminate(() -> { + this.logger.info("Proactive cancel for twitter stream"); + twitterStream.shutdown(); + }).doOnError(throwable -> { + this.logger.error(throwable.getMessage(), throwable); + }); } + } diff --git a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierProperties.java b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierProperties.java index 6de5b11e..51dfaa9c 100644 --- a/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierProperties.java +++ b/supplier/spring-twitter-supplier/src/main/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierProperties.java @@ -33,28 +33,41 @@ public class TwitterStreamSupplierProperties { public enum StreamType { - /** Starts listening on random sample of all public statuses. The default access level provides a small - * proportion of the Firehose. */ + + /** + * Starts listening on random sample of all public statuses. The default access + * level provides a small proportion of the Firehose. + */ sample, - /** Start consuming public statuses that match one or more filter predicates. At least one predicate parameter, - * follow, locations, or track must be specified. Multiple parameters may be specified which allows most - * clients to use a single connection to the Streaming API. Placing long parameters in the URL may cause the - * request to be rejected for excessive URL length.
- * The default access level allows up to 200 track keywords, 400 follow userids and 10 1-degree location boxes. - * Increased access levels allow 80,000 follow userids ('shadow' role), 400,000 follow userids ('birddog' role), - * 10,000 track keywords ('restricted track' role), 200,000 track keywords ('partner track' role), - * and 200 10-degree location boxes ('locRestricted' role). Increased track access levels also pass a higher - * proportion of statuses before limiting the stream.*/ + /** + * Start consuming public statuses that match one or more filter predicates. At + * least one predicate parameter, follow, locations, or track must be specified. + * Multiple parameters may be specified which allows most clients to use a single + * connection to the Streaming API. Placing long parameters in the URL may cause + * the request to be rejected for excessive URL length.
+ * The default access level allows up to 200 track keywords, 400 follow userids + * and 10 1-degree location boxes. Increased access levels allow 80,000 follow + * userids ('shadow' role), 400,000 follow userids ('birddog' role), 10,000 track + * keywords ('restricted track' role), 200,000 track keywords ('partner track' + * role), and 200 10-degree location boxes ('locRestricted' role). Increased track + * access levels also pass a higher proportion of statuses before limiting the + * stream. + */ filter, - /** tarts listening on all public statuses. Available only to approved parties and requires a signed agreement - * to access. */ + /** + * tarts listening on all public statuses. Available only to approved parties and + * requires a signed agreement to access. + */ firehose, - /** Starts listening on all public statuses containing links. - * Available only to approved parties and requires a signed agreement to access.*/ + /** + * Starts listening on all public statuses containing links. Available only to + * approved parties and requires a signed agreement to access. + */ link + } private StreamType type = StreamType.sample; @@ -76,12 +89,15 @@ public void setType(StreamType type) { public static class Filter { public enum FilterLevel { + /** filter level. */ all, none, low, medium + } /** - * Indicates the number of previous statuses to stream before transitioning to the live stream. + * Indicates the number of previous statuses to stream before transitioning to the + * live stream. */ private int count = 0; @@ -95,22 +111,21 @@ public enum FilterLevel { */ private List track; - /** - * Locations to track. Internally represented as 2D array. - * Bounding box is invalid: 52.38, 4.90, 51.51, -0.12. The first pair must be the SW corner of the box + * Locations to track. Internally represented as 2D array. Bounding box is + * invalid: 52.38, 4.90, 51.51, -0.12. The first pair must be the SW corner of the + * box */ private List locations = new ArrayList<>(); - /** * Specifies the tweets language of the stream. */ private List language; /** - * The filter level limits what tweets appear in the stream to those with a minimum filterLevel attribute value. - * One of either none, low, or medium. + * The filter level limits what tweets appear in the stream to those with a + * minimum filterLevel attribute value. One of either none, low, or medium. */ private FilterLevel filterLevel = FilterLevel.all; @@ -183,10 +198,10 @@ public FilterQuery toFilterQuery() { if (!CollectionUtils.isEmpty(this.locations)) { double[][] bboxLocations = new double[this.locations.size() * 2][2]; for (int i = 0; i < this.locations.size(); i = i + 2) { - //SW lat, lon + // SW lat, lon bboxLocations[i][0] = this.locations.get(i).getSw().getLat(); bboxLocations[i][1] = this.locations.get(i).getSw().getLon(); - //NE lat, lon + // NE lat, lon bboxLocations[i + 1][0] = this.locations.get(i).getNe().getLat(); bboxLocations[i + 1][1] = this.locations.get(i).getNe().getLon(); } @@ -232,6 +247,7 @@ public Geocode getNe() { public void setNe(Geocode ne) { this.ne = ne; } + } public static class Geocode { @@ -246,7 +262,6 @@ public static class Geocode { */ private double lon = -1; - public double getLat() { return lat; } @@ -262,6 +277,9 @@ public double getLon() { public void setLon(double lon) { this.lon = lon; } + } + } + } diff --git a/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPaginationTests.java b/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPaginationTests.java index 988822ea..a12272d2 100644 --- a/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPaginationTests.java +++ b/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/search/SearchPaginationTests.java @@ -115,7 +115,8 @@ public void tests2() { pagination.update(tweets(7, 4, 1)); - // Restart from Most Recent due to pageCounter == 0 while no reset have been performed so ar + // Restart from Most Recent due to pageCounter == 0 while no reset have been + // performed so ar assertThat(pagination.getSinceId()).isEqualTo(10L); assertThat(pagination.getMaxId()).isEqualTo(UNBOUNDED); assertThat(pagination.getPageMaxId()).isEqualTo(UNBOUNDED); @@ -345,5 +346,7 @@ public RateLimitStatus getRateLimitStatus() { public int getAccessLevel() { return 0; } + } + } diff --git a/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierTests.java b/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierTests.java index d6bc2b55..9f5a2249 100644 --- a/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierTests.java +++ b/supplier/spring-twitter-supplier/src/test/java/org/springframework/cloud/fn/supplier/twitter/status/stream/TwitterStreamSupplierTests.java @@ -55,14 +55,10 @@ /** * @author Christian Tzolov */ -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.NONE, - properties = { - "twitter.connection.consumerKey=consumerKey666", - "twitter.connection.consumerSecret=consumerSecret666", - "twitter.connection.accessToken=accessToken666", - "twitter.connection.accessTokenSecret=accessTokenSecret666" - }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { "twitter.connection.consumerKey=consumerKey666", + "twitter.connection.consumerSecret=consumerSecret666", "twitter.connection.accessToken=accessToken666", + "twitter.connection.accessTokenSecret=accessTokenSecret666" }) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class TwitterStreamSupplierTests { @@ -73,8 +69,11 @@ public abstract class TwitterStreamSupplierTests { private static ClientAndServer mockServer; private static MockServerClient mockClient; + private static HttpRequest streamFilterRequest; + private static HttpRequest streamSampleRequest; + private static HttpRequest streamFirehoseRequest; @Autowired @@ -87,24 +86,20 @@ public static void startServer() { mockClient = new MockServerClient(MOCK_SERVER_IP, MOCK_SERVER_PORT); - streamFilterRequest = mockClientRecordRequest(request() - .withMethod("POST") - .withPath("/stream/statuses/filter.json") - .withBody(new StringBody("count=0&track=Java%2CPython&stall_warnings=true"))); + streamFilterRequest = mockClientRecordRequest(request().withMethod("POST") + .withPath("/stream/statuses/filter.json") + .withBody(new StringBody("count=0&track=Java%2CPython&stall_warnings=true"))); - streamSampleRequest = mockClientRecordRequest(request() - .withMethod("GET") - .withPath("/stream/statuses/sample.json")); + streamSampleRequest = mockClientRecordRequest( + request().withMethod("GET").withPath("/stream/statuses/sample.json")); - streamFirehoseRequest = mockClientRecordRequest(request() - .withMethod("POST") - .withPath("/stream/statuses/links.json") - .withBody(new StringBody("count=0&stall_warnings=true"))); + streamFirehoseRequest = mockClientRecordRequest(request().withMethod("POST") + .withPath("/stream/statuses/links.json") + .withBody(new StringBody("count=0&stall_warnings=true"))); - streamFirehoseRequest = mockClientRecordRequest(request() - .withMethod("POST") - .withPath("/stream/statuses/firehose.json") - .withBody(new StringBody("count=0&stall_warnings=true"))); + streamFirehoseRequest = mockClientRecordRequest(request().withMethod("POST") + .withPath("/stream/statuses/firehose.json") + .withBody(new StringBody("count=0&stall_warnings=true"))); } @AfterAll @@ -113,21 +108,16 @@ public static void stopServer() { } private static HttpRequest mockClientRecordRequest(HttpRequest request) { - mockClient.when(request, /*unlimited())*/ exactly(1)) - .respond( - response() - .withStatusCode(200) - .withHeaders( - new Header("Content-Type", "application/json; charset=utf-8"), - new Header("Cache-Control", "public, max-age=86400")) - .withBody(TwitterTestUtils.asString("classpath:/response/stream_test_1.json")) - .withDelay(TimeUnit.SECONDS, 10)); + mockClient.when(request, /* unlimited()) */ exactly(1)) + .respond(response().withStatusCode(200) + .withHeaders(new Header("Content-Type", "application/json; charset=utf-8"), + new Header("Cache-Control", "public, max-age=86400")) + .withBody(TwitterTestUtils.asString("classpath:/response/stream_test_1.json")) + .withDelay(TimeUnit.SECONDS, 10)); return request; } - @TestPropertySource(properties = { - "twitter.stream.type=sample" - }) + @TestPropertySource(properties = { "twitter.stream.type=sample" }) public static class TwitterStreamSampleTests extends TwitterStreamSupplierTests { @Test @@ -135,21 +125,19 @@ public void testOne() { final Flux> messageFlux = twitterStreamSupplier.get(); final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) - .contains("\"id\":1075751718749659136")) - .thenCancel() - .verifyLater(); + .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) + .contains("\"id\":1075751718749659136")) + .thenCancel() + .verifyLater(); stepVerifier.verify(); mockClient.verify(streamSampleRequest, once()); } + } - @TestPropertySource(properties = { - "twitter.stream.type=filter", - "twitter.stream.filter.track=Java,Python" - }) + @TestPropertySource(properties = { "twitter.stream.type=filter", "twitter.stream.filter.track=Java,Python" }) public static class TwitterStreamFilterTests extends TwitterStreamSupplierTests { @Test @@ -157,20 +145,19 @@ public void testOne() { final Flux> messageFlux = twitterStreamSupplier.get(); final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) - .contains("\"id\":1075751718749659136")) - .thenCancel() - .verifyLater(); + .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) + .contains("\"id\":1075751718749659136")) + .thenCancel() + .verifyLater(); stepVerifier.verify(); mockClient.verify(streamFilterRequest, once()); } + } - @TestPropertySource(properties = { - "twitter.stream.type=firehose" - }) + @TestPropertySource(properties = { "twitter.stream.type=firehose" }) public static class TwitterStreamFirehoseTests extends TwitterStreamSupplierTests { @Test @@ -178,15 +165,16 @@ public void testOne() { final Flux> messageFlux = twitterStreamSupplier.get(); final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) - .contains("\"id\":1075751718749659136")) - .thenCancel() - .verifyLater(); + .assertNext((message) -> assertThat(new String((byte[]) message.getPayload())) + .contains("\"id\":1075751718749659136")) + .thenCancel() + .verifyLater(); stepVerifier.verify(); mockClient.verify(streamFirehoseRequest, once()); } + } @SpringBootConfiguration @@ -199,12 +187,13 @@ public static class TwitterStreamSupplierTestApplication { public twitter4j.conf.Configuration twitterConfiguration2(TwitterConnectionProperties properties, Function toConfigurationBuilder) { - Function mockedConfiguration = - toConfigurationBuilder.andThen( - new TwitterTestUtils().mockTwitterUrls( - String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); + Function mockedConfiguration = toConfigurationBuilder + .andThen(new TwitterTestUtils() + .mockTwitterUrls(String.format("http://%s:%s", MOCK_SERVER_IP, MOCK_SERVER_PORT))); return mockedConfiguration.apply(properties).build(); } + } + } diff --git a/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierConfiguration.java b/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierConfiguration.java index 60fd80a1..e3d32c06 100644 --- a/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierConfiguration.java +++ b/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierConfiguration.java @@ -50,23 +50,21 @@ public class WebsocketSupplierConfiguration { @Bean public Supplier>> websocketSupplier(Publisher> websocketPublisher, - WebSocketInboundChannelAdapter webSocketInboundChannelAdapter) { + WebSocketInboundChannelAdapter webSocketInboundChannelAdapter) { return () -> Flux.from(websocketPublisher) - .doOnSubscribe(subscription -> webSocketInboundChannelAdapter.start()) - .doOnTerminate(webSocketInboundChannelAdapter::stop); + .doOnSubscribe(subscription -> webSocketInboundChannelAdapter.start()) + .doOnTerminate(webSocketInboundChannelAdapter::stop); } @Bean public Publisher> websocketPublisher(IntegrationWebSocketContainer serverWebSocketContainer) { - return IntegrationFlow.from( - webSocketInboundChannelAdapter(serverWebSocketContainer)) - .toReactivePublisher(); + return IntegrationFlow.from(webSocketInboundChannelAdapter(serverWebSocketContainer)).toReactivePublisher(); } private WebSocketInboundChannelAdapter webSocketInboundChannelAdapter( IntegrationWebSocketContainer serverWebSocketContainer) { - WebSocketInboundChannelAdapter webSocketInboundChannelAdapter = - new WebSocketInboundChannelAdapter(serverWebSocketContainer); + WebSocketInboundChannelAdapter webSocketInboundChannelAdapter = new WebSocketInboundChannelAdapter( + serverWebSocketContainer); webSocketInboundChannelAdapter.setAutoStartup(false); return webSocketInboundChannelAdapter; } @@ -82,9 +80,8 @@ public ServerWebSocketContainer.SockJsServiceOptions sockJsServiceOptions() { @Bean public IntegrationWebSocketContainer serverWebSocketContainer( ObjectProvider sockJsServiceOptions) { - return new ServerWebSocketContainer(properties.getPath()) - .setAllowedOrigins(properties.getAllowedOrigins()) - .withSockJs(sockJsServiceOptions.getIfAvailable()); + return new ServerWebSocketContainer(properties.getPath()).setAllowedOrigins(properties.getAllowedOrigins()) + .withSockJs(sockJsServiceOptions.getIfAvailable()); } } diff --git a/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierProperties.java b/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierProperties.java index 3d23343c..815af41d 100644 --- a/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierProperties.java +++ b/supplier/spring-websocket-supplier/src/main/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierProperties.java @@ -93,4 +93,5 @@ public void setEnable(boolean enable) { } } + } diff --git a/supplier/spring-websocket-supplier/src/test/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierTests.java b/supplier/spring-websocket-supplier/src/test/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierTests.java index 1e40e644..0f3f746b 100644 --- a/supplier/spring-websocket-supplier/src/test/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierTests.java +++ b/supplier/spring-websocket-supplier/src/test/java/org/springframework/cloud/fn/supplier/websocket/WebsocketSupplierTests.java @@ -69,22 +69,17 @@ public void checkCmdlineArgs() { public void testBasicFlow() throws IOException { final Flux> messageFlux = websocketSupplier.get(); final StepVerifier stepVerifier = StepVerifier.create(messageFlux) - .assertNext((message) -> - assertThat(message.getPayload()) - .isEqualTo(messageString) - ) - .thenCancel() - .verifyLater(); + .assertNext((message) -> assertThat(message.getPayload()).isEqualTo(messageString)) + .thenCancel() + .verifyLater(); StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); - ClientWebSocketContainer clientWebSocketContainer = - new ClientWebSocketContainer(webSocketClient, "ws://localhost:{port}/{path}", - this.port, - this.properties.getPath()); + ClientWebSocketContainer clientWebSocketContainer = new ClientWebSocketContainer(webSocketClient, + "ws://localhost:{port}/{path}", this.port, this.properties.getPath()); HttpHeaders httpHeaders = new HttpHeaders(); String token = Base64Utils.encodeToString( (this.securityProperties.getUser().getName() + ":" + this.securityProperties.getUser().getPassword()) - .getBytes(StandardCharsets.UTF_8)); + .getBytes(StandardCharsets.UTF_8)); httpHeaders.set(HttpHeaders.AUTHORIZATION, "Basic " + token); clientWebSocketContainer.setHeaders(httpHeaders); clientWebSocketContainer.start(); diff --git a/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfiguration.java b/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfiguration.java index 2fa79356..a3f4015c 100644 --- a/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfiguration.java +++ b/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfiguration.java @@ -44,7 +44,8 @@ public class XmppSupplierConfiguration { private FluxMessageChannel output = new FluxMessageChannel(); @Bean - public ChatMessageListeningEndpoint chatMessageListeningEndpoint(XMPPConnection xmppConnection, XmppSupplierProperties properties) { + public ChatMessageListeningEndpoint chatMessageListeningEndpoint(XMPPConnection xmppConnection, + XmppSupplierProperties properties) { var chatMessageListeningEndpoint = new ChatMessageListeningEndpoint(xmppConnection); diff --git a/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierProperties.java b/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierProperties.java index 7e8c4a26..f32df62c 100644 --- a/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierProperties.java +++ b/supplier/spring-xmpp-supplier/src/main/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierProperties.java @@ -24,7 +24,6 @@ import org.springframework.validation.annotation.Validated; /** - * * @author Daniel Frey * @since 4.0.0 */ @@ -47,6 +46,7 @@ public StanzaFilter getStanzaFilter() { public void setPayloadExpression(Expression payloadExpression) { this.payloadExpression = payloadExpression; } + public Expression getPayloadExpression() { return payloadExpression; } diff --git a/supplier/spring-xmpp-supplier/src/test/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfigurationTests.java b/supplier/spring-xmpp-supplier/src/test/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfigurationTests.java index 48acd9eb..a52d7daa 100644 --- a/supplier/spring-xmpp-supplier/src/test/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfigurationTests.java +++ b/supplier/spring-xmpp-supplier/src/test/java/org/springframework/cloud/fn/supplier/xmpp/XmppSupplierConfigurationTests.java @@ -54,14 +54,12 @@ /** * @author Daniel Frey */ -@SpringBootTest( - properties = { - "xmpp.factory.user=" + JANE_USER, // Connect as user intended to listen for messages on behalf of - "xmpp.factory.password=" + USER_PW, - "xmpp.factory.service-name=" + SERVICE_NAME, - "xmpp.factory.security-mode=disabled" - } -) +@SpringBootTest(properties = { "xmpp.factory.user=" + JANE_USER, // Connect as user + // intended to listen + // for messages on + // behalf of + "xmpp.factory.password=" + USER_PW, "xmpp.factory.service-name=" + SERVICE_NAME, + "xmpp.factory.security-mode=disabled" }) public class XmppSupplierConfigurationTests implements XmppTestContainerSupport { @DynamicPropertySource @@ -84,8 +82,9 @@ void setup() throws IOException, SmackException, XMPPException, InterruptedExcep builder.setHost(XmppTestContainerSupport.getXmppHost()); builder.setPort(XmppTestContainerSupport.getXmppMappedPort()); builder.setResource(SERVICE_NAME); - builder.setUsernameAndPassword(JOHN_USER, USER_PW) // Connect as user intended to send messages from - .setXmppDomain(SERVICE_NAME); + builder.setUsernameAndPassword(JOHN_USER, USER_PW) // Connect as user intended to + // send messages from + .setXmppDomain(SERVICE_NAME); this.sourceConnection = new XMPPTCPConnection(builder.build()); this.sourceConnection.connect(); this.sourceConnection.login(); @@ -98,24 +97,21 @@ void teardown() { } @Test - void testSubscriptionConfiguration() throws XmppStringprepException, SmackException.NotConnectedException, InterruptedException { + void testSubscriptionConfiguration() + throws XmppStringprepException, SmackException.NotConnectedException, InterruptedException { var payload = "test"; - var stepVerifier = - StepVerifier.create(subject.get()) - .assertNext((message) -> { + var stepVerifier = StepVerifier.create(subject.get()).assertNext((message) -> { - assertThat(message.getPayload()) - .asInstanceOf(InstanceOfAssertFactories.type(String.class)) - .isEqualTo(payload); + assertThat(message.getPayload()).asInstanceOf(InstanceOfAssertFactories.type(String.class)) + .isEqualTo(payload); - assertThat(message.getHeaders().containsKey(XmppHeaders.TO)).isTrue(); - assertThat(message.getHeaders().get(XmppHeaders.TO, String.class)).isEqualTo(JANE_USER + "@" + SERVICE_NAME); + assertThat(message.getHeaders().containsKey(XmppHeaders.TO)).isTrue(); + assertThat(message.getHeaders().get(XmppHeaders.TO, String.class)) + .isEqualTo(JANE_USER + "@" + SERVICE_NAME); - }) - .thenCancel() - .verifyLater(); + }).thenCancel().verifyLater(); var chatManager = ChatManager.getInstanceFor(this.sourceConnection); var jid = JidCreate.entityBareFrom(JANE_USER + "@" + SERVICE_NAME); @@ -129,6 +125,8 @@ void testSubscriptionConfiguration() throws XmppStringprepException, SmackExcept @SpringBootConfiguration @EnableAutoConfiguration @Import(XmppSupplierConfiguration.class) - static class XmppSupplierTestApplication { } + static class XmppSupplierTestApplication { + + } } diff --git a/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfiguration.java b/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfiguration.java index c55bc008..f1df85d8 100644 --- a/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfiguration.java +++ b/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfiguration.java @@ -52,7 +52,7 @@ public ZContext zContext() { @Bean public ZeroMqMessageProducer adapter(ZeroMqSupplierProperties properties, ZContext zContext, - @Autowired(required = false) Consumer socketConfigurer) { + @Autowired(required = false) Consumer socketConfigurer) { ZeroMqMessageProducer zeroMqMessageProducer = new ZeroMqMessageProducer(zContext, properties.getSocketType()); diff --git a/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierProperties.java b/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierProperties.java index 08651c57..26889cdd 100644 --- a/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierProperties.java +++ b/supplier/spring-zeromq-supplier/src/main/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierProperties.java @@ -27,7 +27,6 @@ import org.springframework.validation.annotation.Validated; /** - * * @author Daniel Frey * @since 3.1.0 */ @@ -58,7 +57,7 @@ public class ZeroMqSupplierProperties { /** * The Topics to subscribe to. */ - private String[] topics = {""}; + private String[] topics = { "" }; /** * @param socketType the {@link SocketType} to establish. @@ -78,7 +77,6 @@ public String getConnectUrl() { } /** - * * @param connectUrl The ZeroMQ server connect url * * @see org.springframework.integration.zeromq.inbound.ZeroMqMessageProducer#setConnectUrl(String) @@ -119,7 +117,6 @@ public String[] getTopics() { } /** - * * @param topics The ZeroMQ Topics to subscribe to * * @see org.springframework.integration.zeromq.inbound.ZeroMqMessageProducer#setTopics(String...) diff --git a/supplier/spring-zeromq-supplier/src/test/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfigurationTests.java b/supplier/spring-zeromq-supplier/src/test/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfigurationTests.java index 7239fab8..d99bc196 100644 --- a/supplier/spring-zeromq-supplier/src/test/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfigurationTests.java +++ b/supplier/spring-zeromq-supplier/src/test/java/org/springframework/cloud/fn/supplier/zeromq/ZeroMqSupplierConfigurationTests.java @@ -40,14 +40,14 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * @author Daniel Frey - * since 3.1.0 + * @author Daniel Frey since 3.1.0 */ -@SpringBootTest(properties = {"zeromq.supplier.topics=test-topic"}) +@SpringBootTest(properties = { "zeromq.supplier.topics=test-topic" }) @DirtiesContext public class ZeroMqSupplierConfigurationTests { private static final ZContext CONTEXT = new ZContext(); + private static ZMQ.Socket socket; @Autowired @@ -73,15 +73,12 @@ static void tearDown() { @Test void testSubscriptionConfiguration() throws InterruptedException { - StepVerifier stepVerifier = - StepVerifier.create(subject.get()) - .assertNext((message) -> - assertThat(message.getPayload()) - .asInstanceOf(InstanceOfAssertFactories.type(byte[].class)) - .isEqualTo("test".getBytes(ZMQ.CHARSET)) - ) - .thenCancel() - .verifyLater(); + StepVerifier stepVerifier = StepVerifier.create(subject.get()) + .assertNext((message) -> assertThat(message.getPayload()) + .asInstanceOf(InstanceOfAssertFactories.type(byte[].class)) + .isEqualTo("test".getBytes(ZMQ.CHARSET))) + .thenCancel() + .verifyLater(); Thread.sleep(2000); @@ -94,6 +91,8 @@ void testSubscriptionConfiguration() throws InterruptedException { } @SpringBootApplication - public static class ZeroMqSourceTestApplication { } + public static class ZeroMqSourceTestApplication { + + } }