Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/handle amqp fatal errors (#1111)
* Adding support to handle lengthy error msgs more precisely Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Added check at conditionalHandler level and changes assertions in test class Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Fixed sonar lint issues Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Reverted the change on making class final Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * To trigger the circle-ci build and check Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Addressed last set of PR comments Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Fixe sonar issue for nullpointer dereference Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com> * Handling null case explicitly Signed-off-by: Shruthi Manavalli Ramanna <shruthimanavalli.ramanna@bosch-si.com>
- Loading branch information
Showing
11 changed files
with
472 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
...dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AbstractAmqpErrorHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import org.springframework.amqp.AmqpRejectAndDontRequeueException; | ||
|
||
/** | ||
* An abstract error handler for errors resulting from AMQP. | ||
*/ | ||
public abstract class AbstractAmqpErrorHandler<T> implements AmqpErrorHandler{ | ||
|
||
@Override | ||
public void doHandle(Throwable throwable, AmqpErrorHandlerChain chain) { | ||
// retrieving the cause of throwable as it contains the actual class of | ||
// exception | ||
final Throwable cause = throwable.getCause(); | ||
if (getExceptionClass().isAssignableFrom(cause.getClass())) { | ||
throw new AmqpRejectAndDontRequeueException(getErrorMessage(throwable)); | ||
} else { | ||
chain.handle(throwable); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the class of the exception. | ||
* | ||
* @return | ||
* the exception class | ||
*/ | ||
public abstract Class<T> getExceptionClass(); | ||
|
||
/** | ||
* Returns the customized error message. | ||
* | ||
* @return | ||
* the customized error message | ||
*/ | ||
public String getErrorMessage(Throwable throwable){ | ||
return AmqpErrorMessageComposer.constructErrorMessage(throwable); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
hawkbit-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpErrorHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
/** | ||
* Interface declaration of {@link AmqpErrorHandler} that handles errors based on the | ||
* types of exception. | ||
*/ | ||
@FunctionalInterface | ||
public interface AmqpErrorHandler { | ||
|
||
/** | ||
* Handles the error based on the type of exception | ||
* | ||
* @param throwable | ||
* the throwable | ||
* @param chain | ||
* an {@link AmqpErrorHandlerChain} | ||
*/ | ||
void doHandle(final Throwable throwable, final AmqpErrorHandlerChain chain); | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
...it-dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpErrorHandlerChain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import org.springframework.util.ErrorHandler; | ||
|
||
import java.util.Iterator; | ||
import java.util.List; | ||
|
||
/** | ||
* An error handler chain that delegates the error to the matching error handler based on the type of exception | ||
*/ | ||
public final class AmqpErrorHandlerChain { | ||
private final Iterator<AmqpErrorHandler> iterator; | ||
private final ErrorHandler defaultHandler; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param iterator | ||
* the {@link AmqpErrorHandler} iterator | ||
* @param defaultHandler | ||
* the default handler | ||
*/ | ||
private AmqpErrorHandlerChain(Iterator<AmqpErrorHandler> iterator, ErrorHandler defaultHandler) { | ||
this.iterator = iterator; | ||
this.defaultHandler = defaultHandler; | ||
} | ||
|
||
/** | ||
* Returns an {@link AmqpErrorHandlerChain} | ||
* | ||
* @param errorHandlers | ||
* {@link List} of error handlers | ||
* @param defaultHandler | ||
* the default error handler | ||
* @return an {@link AmqpErrorHandlerChain} | ||
*/ | ||
public static AmqpErrorHandlerChain getHandlerChain(final List<AmqpErrorHandler> errorHandlers, final ErrorHandler defaultHandler) { | ||
return new AmqpErrorHandlerChain(errorHandlers.iterator(), defaultHandler); | ||
} | ||
|
||
/** | ||
* Handles the error based on the type of exception | ||
* | ||
* @param error | ||
* the throwable containing the cause of exception | ||
*/ | ||
public void handle(final Throwable error) { | ||
if (iterator.hasNext()) { | ||
final AmqpErrorHandler handler = iterator.next(); | ||
handler.doHandle(error, this); | ||
} else { | ||
defaultHandler.handleError(error); | ||
} | ||
} | ||
} | ||
|
53 changes: 53 additions & 0 deletions
53
...dmf/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpErrorMessageComposer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import java.util.Collection; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
import org.springframework.amqp.core.Message; | ||
import org.springframework.amqp.rabbit.support.ListenerExecutionFailedException; | ||
|
||
/** | ||
* Class that composes a meaningful error message and enhances it with properties from failed message | ||
*/ | ||
public final class AmqpErrorMessageComposer { | ||
|
||
private AmqpErrorMessageComposer() { | ||
} | ||
|
||
/** | ||
* Constructs an error message based on failed message content | ||
* | ||
* @param throwable | ||
* the throwable containing failed message content | ||
* @return | ||
* meaningful error message | ||
*/ | ||
public static String constructErrorMessage(final Throwable throwable) { | ||
StringBuilder completeErrorMessage = new StringBuilder(); | ||
final String mainErrorMsg = throwable.getCause().getMessage(); | ||
|
||
if (throwable instanceof ListenerExecutionFailedException) { | ||
Collection<Message> failedMessages = ((ListenerExecutionFailedException) throwable).getFailedMessages(); | ||
// since the intended message content is always on top of the collection, we only extract the first one | ||
final Message failedMessage = failedMessages.iterator().next(); | ||
final byte[] amqpFailedMsgBody = failedMessage.getBody(); | ||
final Map<String, Object> amqpFailedMsgHeaders = failedMessage.getMessageProperties().getHeaders(); | ||
|
||
String amqpFailedMsgConcatenatedHeaders = amqpFailedMsgHeaders.keySet().stream() | ||
.map(key -> key + "=" + amqpFailedMsgHeaders.get(key)).collect(Collectors.joining(", ", "{", "}")); | ||
completeErrorMessage.append(mainErrorMsg).append(new String(amqpFailedMsgBody)) | ||
.append(amqpFailedMsgConcatenatedHeaders); | ||
return completeErrorMessage.toString(); | ||
} | ||
return mainErrorMsg; | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...it-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DelegatingConditionalErrorHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import java.util.List; | ||
import javax.validation.constraints.NotNull; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.amqp.AmqpRejectAndDontRequeueException; | ||
import org.springframework.util.ErrorHandler; | ||
|
||
/** | ||
* An error handler delegates error handling to the matching {@link AmqpErrorHandler} based on the type of exception | ||
*/ | ||
public class DelegatingConditionalErrorHandler implements ErrorHandler { | ||
private static final Logger LOG = LoggerFactory.getLogger(DelegatingConditionalErrorHandler.class); | ||
private final List<AmqpErrorHandler> handlers; | ||
private final ErrorHandler defaultHandler; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param handlers | ||
* {@link List} of error handlers | ||
* @param defaultHandler | ||
* the default error handler | ||
*/ | ||
public DelegatingConditionalErrorHandler(final List<AmqpErrorHandler> handlers, @NotNull final ErrorHandler defaultHandler) { | ||
this.handlers = handlers; | ||
this.defaultHandler = defaultHandler; | ||
} | ||
|
||
@Override | ||
public void handleError(final Throwable t) { | ||
if (t.getCause() == null) { | ||
LOG.error("Cannot handle the error as the cause of the error is null!"); | ||
return; | ||
} | ||
|
||
if (includesAmqpRejectException(t.getCause())) { | ||
LOG.error("Received an AmqpRejectAndDontRequeueException due to {}", t.getCause().getMessage()); | ||
return; | ||
} | ||
|
||
AmqpErrorHandlerChain.getHandlerChain(handlers, defaultHandler).handle(t); | ||
} | ||
|
||
private boolean includesAmqpRejectException(final Throwable t) { | ||
if (t instanceof AmqpRejectAndDontRequeueException){ | ||
return true; | ||
} | ||
if (t.getCause() != null) { | ||
return includesAmqpRejectException(t.getCause()); | ||
} | ||
return false; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...wkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/EntityNotFoundExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; | ||
|
||
/** | ||
* An error handler for entity not found exception resulting from AMQP. | ||
*/ | ||
public class EntityNotFoundExceptionHandler extends AbstractAmqpErrorHandler<EntityNotFoundException> { | ||
|
||
@Override | ||
public Class<EntityNotFoundException> getExceptionClass() { | ||
return EntityNotFoundException.class; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
...f-amqp/src/main/java/org/eclipse/hawkbit/amqp/InvalidTargetAttributeExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* Copyright (c) 2021 Bosch.IO GmbH and others. | ||
* | ||
* All rights reserved. This program and the accompanying materials | ||
* are made available under the terms of the Eclipse Public License v1.0 | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v10.html | ||
*/ | ||
package org.eclipse.hawkbit.amqp; | ||
|
||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException; | ||
|
||
/** | ||
* An error handler for all invalid target attributes resulting from AMQP. | ||
*/ | ||
public class InvalidTargetAttributeExceptionHandler extends AbstractAmqpErrorHandler<InvalidTargetAttributeException> { | ||
|
||
@Override | ||
public Class<InvalidTargetAttributeException> getExceptionClass() { | ||
return InvalidTargetAttributeException.class; | ||
} | ||
} |
Oops, something went wrong.