How to replace Flux elements when an exception is thrown? - spring-webflux

How to replace Flux element and continue stream when an exception is thrown?
public class TEST {
public static void main(String[] args) {
Flux.just(1, 2, 3, 4, 5)
.map(i -> {
if (i == 3) {
throw new RuntimeException();
}
return i;
})
.onErrorResume(e -> Mono.just(-1))
.subscribe(System.out::println);
}
}
output:
1
2
-1
as you see the stream is terminated after exception.
what I want:
1
2
-1
4
5
is this possible in Reactor? I do not want to handle this in map operator!

Related

How to simulate an error to setBatchErrorHandler() in kafka consumer container?

I've a kafka consumer application that uses ConcurrentKafkaListenerContainerFactory and I read that setBatchErrorHandler is used to handle errors when there is an error during batch listening. Below is my codes for configuring the factory and receiving function. May I know how can I simulate the error to use BatchErrorHandler?
#Bean(name = "xxxconsumer")
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(ConsumerFactory<String, String> consumerFactory) {
final ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory);
factory.setConcurrency(14);
factory.setBatchListener(true);
factory.setBatchErrorHandler(new BatchLoggingErrorHandler());
return factory;
}
#KafkaListener(
topics = "filler.name.1",
containerFactory = "xxxconsumer"
)
public void receive(#Payload List<String> messages) {
for (int i = 0; i < messages.size(); i++) {
log.info("Received message='{}' ", messages.get(i));
transform(messages.get(i));
}
log.info("All batch messages received");
}
I'm using spring-kafka v2.3.7.
You can throw a RuntimeException in the listener to simulate an error and see the BatchLoggingErrorHandler kicking in.
Consider this application:
#SpringBootApplication
public class SO71276422 {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SO71276422.class, args);
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {
Thread.interrupted();
throw new RuntimeException("Interrupted");
}
KafkaOperations kafkaTemplate = context.getBean("kafkaTemplate", KafkaOperations.class);
for (int i = 0; i < 10; i++) {
kafkaTemplate.send("filler.name.1", "My message " + i);
}
}
Logger log = LoggerFactory.getLogger(this.getClass());
#KafkaListener(
topics = "filler.name.1",
containerFactory = "xxxconsumer"
)
public void receive(#Payload List<String> messages) {
log.info("Received messages: " + messages);
for (int i = 0; i < messages.size(); i++) {
log.info("Received message='{}' ", messages.get(i));
transform(messages.get(i));
}
throw new RuntimeException("Test exception");
}
private void transform(String s) {
log.info("Transforming message " + s);
}
#Configuration
static class MyConfiguration {
#Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.GROUP_ID_CONFIG, "grp_STRING");
return new DefaultKafkaConsumerFactory<>(config);
//inject consumer factory to kafka listener consumer factory
}
#Bean(name = "xxxconsumer")
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(ConsumerFactory<String, String> consumerFactory) {
final ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory);
factory.setConcurrency(14);
factory.setBatchListener(true);
factory.setBatchErrorHandler(new BatchLoggingErrorHandler());
return factory;
}
}
}
Will produce this logs:
2022-02-28 15:22:54.795 INFO 19058 --- [ntainer#0-0-C-1] 1276422$$EnhancerBySpringCGLIB$$7449d5be : Received messages: [My message 0, My message 1, My message 2, My message 3, My message 4, My message 5, My message 6, My message 7, My message 8, My message 9]
...
2022-02-28 15:22:54.796 INFO 19058 --- [ntainer#0-0-C-1] 1276422$$EnhancerBySpringCGLIB$$7449d5be : Transforming message My message 9
2022-02-28 15:22:54.799 ERROR 19058 --- [ntainer#0-0-C-1] o.s.k.listener.BatchLoggingErrorHandler : Error while processing:
filler.name.1-0#40
filler.name.1-0#41
filler.name.1-0#42
filler.name.1-0#43
filler.name.1-0#44
filler.name.1-0#45
filler.name.1-0#46
filler.name.1-0#47
filler.name.1-0#48
filler.name.1-0#49

How to mock an s3ObjectStream

I have code to test as follows:
#BeforeEach
static void setup() throws IOException {
Context context = new MockLambdaContext();
mockAmazonS3Client();
}
#Test
#DisplayName("Testing handleRequest returns complete when middle base64 piece")
public void handleRequestTestMiddlePiece() throws IOException {
ApplicationHandler applicationHandler = new ApplicationHandler();
mockAmazonS3Client();
input.replace("tag","middle");
assertEquals("complete", applicationHandler.handleRequest(input, context));
}
public static void mockAmazonS3Client() throws IOException {
AmazonS3Client mockAmazonS3Client = mock(AmazonS3Client.class);
S3Object s3Object = mock(S3Object.class);
S3ObjectInputStream s3ObjectInputStream = mock(S3ObjectInputStream.class);
InputStream testInputStream = new ByteArrayInputStream("Test".getBytes());
when(mockAmazonS3Client.getObject(any(String.class), any(String.class))).thenAnswer(invocationOnMock -> {
return s3Object;
});
when(s3ObjectInputStream.read(any(byte[].class))).thenAnswer(invocation -> {
return testInputStream.read(invocation.getArgument(0));
});
when(s3Object.getObjectContent()).thenReturn(s3ObjectInputStream);
new MockUp<AmazonS3Client>() {
#Mock
public S3Object getObject(String bucketName, String key) throws SdkClientException, AmazonServiceException {
return s3Object;
}
};
new MockUp<AmazonS3Client>() {
#Mock
PutObjectResult putObject(PutObjectRequest var1) throws SdkClientException, AmazonServiceException {
return null;
}
};
new MockUp<AmazonS3Client>() {
#Mock
public S3ObjectInputStream getObjectContent() {
return s3ObjectInputStream;
}
};
}
In the mockAmazonS3Client I have mocked the S3Object and the S3ObjectStream that getObject produces using mockito. I have managed to use a 'when' to have getObjectContent call an S3ObjectStream. However, when I use another 'when' to mock what happens if the S3ObjectSteam is read it throws an exception where 0 bytes are returned:
java.io.IOException: Underlying input stream returned zero bytes
It could be the second 'when' that is failing for some reason, though I'm not sure. Any thoughts will be gratefully received. Thanks.

org.apache.fop.fo.flow.ExternalGraphic catches and logs ImageException I want to handle myself

I am transforming an Image into pdf for test purposes.
To ensure that the Image is compatible with the printing process later on, I'm running a quick test print during the upload.
I'm creating a simple Test-PDF with a transformer. When I try to print an image with an incompatible format, the ImageManager of the transformer throws an ImageException, starting in the preloadImage() function:
public ImageInfo preloadImage(String uri, Source src)
throws ImageException, IOException {
Iterator iter = registry.getPreloaderIterator();
while (iter.hasNext()) {
ImagePreloader preloader = (ImagePreloader)iter.next();
ImageInfo info = preloader.preloadImage(uri, src, imageContext);
if (info != null) {
return info;
}
}
throw new ImageException("The file format is not supported. No ImagePreloader found for "
+ uri);
}
throwing it to:
public ImageInfo needImageInfo(String uri, ImageSessionContext session, ImageManager manager)
throws ImageException, IOException {
//Fetch unique version of the URI and use it for synchronization so we have some sort of
//"row-level" locking instead of "table-level" locking (to use a database analogy).
//The fine locking strategy is necessary since preloading an image is a potentially long
//operation.
if (isInvalidURI(uri)) {
throw new FileNotFoundException("Image not found: " + uri);
}
String lockURI = uri.intern();
synchronized (lockURI) {
ImageInfo info = getImageInfo(uri);
if (info == null) {
try {
Source src = session.needSource(uri);
if (src == null) {
registerInvalidURI(uri);
throw new FileNotFoundException("Image not found: " + uri);
}
info = manager.preloadImage(uri, src);
session.returnSource(uri, src);
} catch (IOException ioe) {
registerInvalidURI(uri);
throw ioe;
} catch (ImageException e) {
registerInvalidURI(uri);
throw e;
}
putImageInfo(info);
}
return info;
}
}
throwing it to :
public ImageInfo getImageInfo(String uri, ImageSessionContext session)
throws ImageException, IOException {
if (getCache() != null) {
return getCache().needImageInfo(uri, session, this);
} else {
return preloadImage(uri, session);
}
}
Finally it gets caught and logged in the ExternalGraphic.class:
/** {#inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
src = pList.get(PR_SRC).getString();
//Additional processing: obtain the image's intrinsic size and baseline information
url = URISpecification.getURL(src);
FOUserAgent userAgent = getUserAgent();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageInfo info = null;
try {
info = manager.getImageInfo(url, userAgent.getImageSessionContext());
} catch (ImageException e) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageError(this, url, e, getLocator());
} catch (FileNotFoundException fnfe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageNotFound(this, url, fnfe, getLocator());
} catch (IOException ioe) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageIOError(this, url, ioe, getLocator());
}
if (info != null) {
this.intrinsicWidth = info.getSize().getWidthMpt();
this.intrinsicHeight = info.getSize().getHeightMpt();
int baseline = info.getSize().getBaselinePositionFromBottom();
if (baseline != 0) {
this.intrinsicAlignmentAdjust
= FixedLength.getInstance(-baseline);
}
}
}
That way it isn't accessible for me in my code that uses the transformer.
I tried to use a custom ErrorListener, but the transformer only registers fatalErrors to the ErrorListener.
Is there any way to access the Exception and handle it myself without changing the code of the library?
It was easier than I thought. Before I call the transformation I register a costum EventListener to the User Agent of the Fop I'm using. This Listener just stores the Information what kind of Event was triggered, so I can throw an Exception if it's an ImageError.
My Listener:
import org.apache.fop.events.Event;
import org.apache.fop.events.EventListener;
public class ImageErrorListener implements EventListener
{
private String eventKey = "";
private boolean imageError = false;
#Override
public void processEvent(Event event)
{
eventKey = event.getEventKey();
if(eventKey.equals("imageError")) {
imageError = true;
}
}
public String getEventKey()
{
return eventKey;
}
public void setEventKey(String eventKey)
{
this.eventKey = eventKey;
}
public boolean isImageError()
{
return imageError;
}
public void setImageError(boolean imageError)
{
this.imageError = imageError;
}
}
Use of the Listener:
// Start XSLT transformation and FOP processing
ImageErrorListener imageListener = new ImageErrorListener();
fop.getUserAgent().getEventBroadcaster().addEventListener(imageListener);
if (res != null)
{
transformer.transform(xmlDomStreamSource, res);
}
if(imageListener.isImageError()) {
throw new ImageException("");
}
fop is of the type Fop ,xmlDomStreamSource ist the xml-Source I want to transform and res is my SAXResult.

Testing Spring-Integration with subscriber channel

I have the following:
Direct-Channel => Splitter => PublishSubscribeChannel
I would like to send data to the direct-channel and test the outcome in the publish-subscribe-channel
What I have so far partly taken from Spring.io (and it works only if I step through debug mode) is:
DirectChannel incomeChannel
PublishSubscribeChannel subscribeChannel
#Test
public void test() {
final AtomicInteger count = new AtomicInteger()
assert true == subscribeChannel.subscribe(new MessageHandler() {
void handleMessage(Message<?> message) throws MessagingException {
count.getAndIncrement();
Entity response = message.getPayload()
assert response != null
// assertions ...
}
})
def request = MessageBuilder.withPayload(entities).build()
assert incomeChannel.send(request) == true
Thread.sleep(10000)
assert 0 < count.get()
}
You don't show your configuration but, if your pub sub channel has a task executor, you need to add a latch; you also should do the asserts on the main thread...
#Test
public void test() {
final AtomicReference<Message<?>> messageRef = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
assert true == subscriberChannel.subscribe(new MessageHandler() {
void handleMessage(Message<?> message) throws MessagingException {
messageRef.set(message);
latch.countDown();
}
})
def request = MessageBuilder.withPayload(entities).build()
assert incomeChannel.send(request) == true
assert true == latch.await(10, TimeUnit.SECONDS)
Entity response = msg.get().getPayload()
assert response != null
// assertions ...
}

wait.until(ExpectedCondition) generating error

After upgrading to selenium Java 3.8.1 the wait.until(ExpectedCondition) has started giving error message.
For the following piece of code
WebElement framei = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//*[#id='ctl00_ContentPlaceHolder1_dlgModal_IFrame']")));
driver.switchTo().frame(framei);
WebElement AcceptRadioButton=wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='RblStatus']/tbody/tr[1]/td/label")));
AcceptRadioButton.click();
The following error is given:
Type The method until(Function<? super WebDriver,V>) in the type FluentWait<WebDriver> is not applicable for the arguments (ExpectedCondition<WebElement>)
I tried to resolve the following issue by removing the Selenium java version 3.8.1 of
Same problem as you but not so sure about Eugene S answer I search in sources of selenium-java 2.53.1 and 3.8.1 to see what was different between FluentWait class. Here are until fonctions of the different version:
2.53.1 :
public void until(final Predicate<T> isTrue) {
until(new Function<T, Boolean>() {
public Boolean apply(T input) {
return isTrue.apply(input);
}
public String toString() {
return isTrue.toString();
}
});
}
OR
public <V> V until(Function<? super T, V> isTrue) {
long end = clock.laterBy(timeout.in(MILLISECONDS));
Throwable lastException = null;
while (true) {
try {
V value = isTrue.apply(input);
if (value != null && Boolean.class.equals(value.getClass())) {
if (Boolean.TRUE.equals(value)) {
return value;
}
} else if (value != null) {
return value;
}
} catch (Throwable e) {
lastException = propagateIfNotIgnored(e);
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!clock.isNowBefore(end)) {
String message = messageSupplier != null ?
messageSupplier.get() : null;
String toAppend = message == null ?
" waiting for " + isTrue.toString() : ": " + message;
String timeoutMessage = String.format("Timed out after %d seconds%s",
timeout.in(SECONDS), toAppend);
throw timeoutException(timeoutMessage, lastException);
}
try {
sleeper.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new WebDriverException(e);
}
}
}
AND IN 3.8.1:
public <V> V until(Function<? super T, V> isTrue) {
long end = clock.laterBy(timeout.in(MILLISECONDS));
Throwable lastException;
while (true) {
try {
V value = isTrue.apply(input);
if (value != null && (Boolean.class != value.getClass() || Boolean.TRUE.equals(value))) {
return value;
}
// Clear the last exception; if another retry or timeout exception would
// be caused by a false or null value, the last exception is not the
// cause of the timeout.
lastException = null;
} catch (Throwable e) {
lastException = propagateIfNotIgnored(e);
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!clock.isNowBefore(end)) {
String message = messageSupplier != null ?
messageSupplier.get() : null;
String timeoutMessage = String.format(
"Expected condition failed: %s (tried for %d second(s) with %s interval)",
message == null ? "waiting for " + isTrue : message,
timeout.in(SECONDS), interval);
throw timeoutException(timeoutMessage, lastException);
}
try {
sleeper.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new WebDriverException(e);
}
}
}
I don't see any difference between the three functions arguments but the project I work on did not return me any error with 2.53.1 version but with 3.8.1 I have the same error than Akhil.
As it says in the error message:
FluentWait<WebDriver> is not applicable for the arguments (ExpectedCondition<WebElement>)
Starting from Selenium 3, until method declaration now looks like this:
public <V> V until(Function<? super T, V> isTrue)
where Function is:
public interface Function<T, R>
So it has been converted to use Java 8 functional interface. You will need to rewrite your expected conditions accordingly.
As per best practices we must try to switch to a <iframe> with proper WebDriverWait as follows :
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[#id='ctl00_ContentPlaceHolder1_dlgModal_IFrame']")));