How do I factor out my use of `try {...} catch (Error e) {log_error(e);}` - error-handling

I need errors to be logged in the same way across a large number of function calls. Here I want errors from foo.create(...) and File.new_tmp(...) to be logged by handle_error(...).
// compile with `valac --pkg gio-2.0 main.vala`
void log_error(Error e) {
// error logging here
}
void main() {
var foo = File.new_for_path("foo");
try {
foo.create(FileCreateFlags.NONE);
} catch (Error e) {
log_error(e);
}
FileIOStream tmp_stream;
try {
File.new_tmp(null, out tmp_stream);
} catch (Error e) {
log_error(e);
}
}
(Yes, main should continue with the FileIOStream stuff if foo.create fails, which is why they're in separate try/catch blocks.)
I want to factor out the use of try {...} catch (Error e) {log_error(e);} into a function like so:
delegate void Action();
void log_error(global::Action action) {
try {
action();
} catch (Error e) {
// error logging here
}
}
void main() {
var foo = File.new_for_path("foo");
log_error(() => foo.create(FileCreateFlags.NONE));
FileIOStream tmp_stream;
log_error(() => File.new_tmp(null, out tmp_stream));
}
But valac gives the warning unhandled error 'GLib.IOError' because you can't seem to catch errors thrown within a closure, nor can I just rewrite log_error(...) as a #define macro as vala doesn't support them. So what can I do?

You can catch exceptions thrown in closures, you just need to have the delegate throw the exception. What you want is probably something like this:
public delegate T? Action<T> () throws GLib.Error;
T? log_error<T> (global::Action<T> func) {
try {
return func ();
} catch (GLib.Error e) {
// error logging here
return null;
}
}
void main () {
var foo = File.new_for_path("foo");
log_error<GLib.FileOutputStream> (() => foo.create (FileCreateFlags.NONE));
FileIOStream? tmp_stream = null;
GLib.File? f = log_error<GLib.File> (() => File.new_tmp (null, out tmp_stream));
}
Note that I've made it a generic so you can actually use a return value. If you want it should be trivial to remove the generic type argument and just return void, though you'll lose some flexivility.

Related

Spring R2dbc: Is there are way to get constant stream from postgresql database and process them?

I want to fetch records for newly created records in a table in postgresql as a live/continuous stream. Is it possible to use using spring r2dbc? If so what options do I have?
Thanks
You need to use pg_notify and start to listing on it. Any change that you want to see should be wrapped in simple trigger that will send message to pg_notify.
I have an example of this on my github, but long story short:
prepare function and trigger:
CREATE OR REPLACE FUNCTION notify_member_saved()
RETURNS TRIGGER
AS $$
BEGIN
PERFORM pg_notify('MEMBER_SAVED', row_to_json(NEW)::text);
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER member_saved_trigger
AFTER INSERT OR UPDATE
ON members
FOR EACH ROW
EXECUTE PROCEDURE notify_member_saved();
In java code prepare listener
#Service
#RequiredArgsConstructor
#Slf4j
class NotificationService {
private final ConnectionFactory connectionFactory;
private final Set<NotificationTopic> watchedTopics = Collections.synchronizedSet(new HashSet<>());
#Qualifier("postgres-event-mapper")
private final ObjectMapper objectMapper;
private PostgresqlConnection connection;
#PreDestroy
private void preDestroy() {
this.getConnection().close().subscribe();
}
private PostgresqlConnection getConnection() {
if(connection == null) {
synchronized(NotificationService.class) {
if(connection == null) {
try {
connection = Mono.from(connectionFactory.create())
.cast(Wrapped.class)
.map(Wrapped::unwrap)
.cast(PostgresqlConnection.class)
.toFuture().get();
} catch(InterruptedException e) {
throw new RuntimeException(e);
} catch(ExecutionException e) {
throw new RuntimeException(e);
}
}
}
}
return this.connection;
}
public <T> Flux<T> listen(final NotificationTopic topic, final Class<T> clazz) {
if(!watchedTopics.contains(topic)) {
executeListenStatement(topic);
}
return getConnection().getNotifications()
.log("notifications")
.filter(notification -> topic.name().equals(notification.getName()) && notification.getParameter() != null)
.handle((notification, sink) -> {
final String json = notification.getParameter();
if(!StringUtils.isBlank(json)) {
try {
sink.next(objectMapper.readValue(json, clazz));
} catch(JsonProcessingException e) {
log.error(String.format("Problem deserializing an instance of [%s] " +
"with the following json: %s ", clazz.getSimpleName(), json), e);
Mono.error(new DeserializationException(topic, e));
}
}
});
}
private void executeListenStatement(final NotificationTopic topic) {
getConnection().createStatement(String.format("LISTEN \"%s\"", topic)).execute()
.doOnComplete(() -> watchedTopics.add(topic))
.subscribe();
}
public void unlisten(final NotificationTopic topic) {
if(watchedTopics.contains(topic)) {
executeUnlistenStatement(topic);
}
}
private void executeUnlistenStatement(final NotificationTopic topic) {
getConnection().createStatement(String.format("UNLISTEN \"%s\"", topic)).execute()
.doOnComplete(() -> watchedTopics.remove(topic))
.subscribe();
}
}
start listiong from controller
#GetMapping("/events")
public Flux<ServerSentEvent<Object>> listenToEvents() {
return Flux.merge(listenToDeletedItems(), listenToSavedItems())
.map(o -> ServerSentEvent.builder()
.retry(Duration.ofSeconds(4L))
.event(o.getClass().getName())
.data(o).build()
);
}
#GetMapping("/unevents")
public Mono<ResponseEntity<Void>> unlistenToEvents() {
unlistenToDeletedItems();
unlistenToSavedItems();
return Mono.just(
ResponseEntity
.status(HttpStatus.I_AM_A_TEAPOT)
.body(null)
);
}
private Flux<Member> listenToSavedItems() {
return this.notificationService.listen(MEMBER_SAVED, Member.class);
}
private void unlistenToSavedItems() {
this.notificationService.unlisten(MEMBER_SAVED);
}
but remember that if something broke then you lost pg_notify events for some time so it is for non-mission-citical solutions.

Getting a warning when use objectmapper in flux inappropriate blocking method call in java reactor

i am new to reactor, i tried to create a flux from Iterable. then i want to convert my object into string by using object mapper. then the ide warns a message like this in this part of the code new ObjectMapper().writeValueAsString(event). the message Inappropriate blocking method call. there is no compile error. could you suggest a solution.
Flux.fromIterable(Arrays.asList(new Event(), new Event()))
.flatMap(event -> {
try {
return Mono.just(new ObjectMapper().writeValueAsString(event));
} catch (JsonProcessingException e) {
return Mono.error(e);
}
})
.subscribe(jsonStrin -> {
System.out.println("jsonStrin = " + jsonStrin);
});
I will give you an answer, but I don't pretty sure this is what you want. it seems like block the thread. so then you can't get the exact benefits of reactive if you block the thread. that's why the IDE warns you. you can create the mono with monoSink. like below.
AtomicReference<ObjectMapper> objectMapper = new AtomicReference<>(new ObjectMapper());
Flux.fromIterable(Arrays.asList(new Event(), new Event()))
.flatMap(event -> {
return Mono.create(monoSink -> {
try {
monoSink.success(objectMapper .writeValueAsString(event));
} catch (JsonProcessingException e) {
monoSink.error(e);
}
});
})
.cast(String.class) // this cast will help you to axact data type that you want to continue the pipeline
.subscribe(jsonString -> {
System.out.println("jsonString = " + jsonString);
});
please try out this method and check that error will be gone.
it doesn't matter if objectMapper is be a normal java object as you did. (if you don't change). it is not necessary for your case.
You need to do it like this:
Flux.fromIterable(Arrays.asList(new Event(), new Event()))
.flatMap(event -> {
try {
return Mono.just(new ObjectMapper().writeValueAsString(event));
} catch (JsonProcessingException e) {
return Mono.error(e);
}
})
.subscribe(jsonStrin -> {
System.out.println("jsonStrin = " + jsonStrin);
});

Catch Exception A Throw Exception B - Coverage Junit5

Iam catch FeignException, but im throws FeingClientException(customized exception).
Sonar says that this FeingClientExceptionis not coveraged by junit test.
Any idea to cover it.
My exception is like this:
public class FeignClientException extends RuntimeException {
public FeignClientException(FeignException ex, ErrorMessageEnum errorMessageEnum, ContextExceptionEnum contextExceptionEnum, String cpf) {
throwException(ex, contextExceptionEnum, errorMessageEnum, cpf);
}
private void throwException(FeignException ex, ContextExceptionEnum contextExceptionEnum, ErrorMessageEnum errorMessageEnum, String cpf) {
if (ex.status() == HttpStatus.NOT_FOUND.value() || ex instanceof FeignException.NotFound) {
throw new FeignClientNotFoundException(
errorMessageEnum != null ? errorMessageEnum.msgUserFormatted(cpf) : ErrorMessageEnum.REGISTRO_NAO_ENCONTRADO.msgUserFormatted(cpf),
errorMessageEnum != null ? errorMessageEnum.msgDeveloper() : ErrorMessageEnum.REGISTRO_NAO_ENCONTRADO.msgDeveloper(),
String.valueOf(HttpStatus.NOT_FOUND.value()),
contextExceptionEnum.value());
}
if (ex.status() == HttpStatus.SERVICE_UNAVAILABLE.value() || ex instanceof RetryableException) {
throw new ServicoForaDoArException(
ErrorMessageEnum.SERVICO_FORA_AR.msgUserFormatted(contextExceptionEnum.value()),
ErrorMessageEnum.SERVICO_FORA_AR.msgDeveloper(),
String.valueOf(HttpStatus.SERVICE_UNAVAILABLE.value()),
contextExceptionEnum.value());
}
if (ex.status() == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
throw new FeignClientInternalServerErrorException(
ErrorMessageEnum.SERVICO_RETORNOU_ERRO.msgUserFormatted(contextExceptionEnum.value()),
ErrorMessageEnum.SERVICO_RETORNOU_ERRO.msgDeveloper(),
String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()),
contextExceptionEnum.value());
}
throw new FeignBadGatewayException (
ErrorMessageEnum.SERVICO_RETORNOU_ERRO.msgUserFormatted(contextExceptionEnum.value()),
ErrorMessageEnum.SERVICO_RETORNOU_ERRO.msgDeveloper(),
String.valueOf(HttpStatus.BAD_GATEWAY.value()),
contextExceptionEnum.value());
}
}
My test is:
void test2() {
doThrow(FeignException.NotFound.class).when(preAprovadoClient).consultaPreAprovadoCDC(Mockito.anyString(), Mockito.anyString());
assertThrows(FeignClientException.FeignClientNotFoundException.class, () ->{
PreAprovado preAprovado = preAprovadoGateway.consultarPreAprovadoCDC("01234567890");
});
}
I think you're mocking the wrong method. You're calling the method consultarPreAprovadoCDC with one parameter, but you have mocked it with two String parameters, maybe that is causing this confusion.
Try to either changing the call to use two String parameters or mock the method with only one anyString() as parameter.

Do an action when an error occurs RxJava

I need to create a folder when it doesn't exist. In my case, the only way to do so is to capture the error and handle it to create the folder wanted.
But all i can find is
public static Observable<Boolean> folderExists(final Context context, final String targetPath, final String currentpath) {
Application application = Application.get(context);
//i browse the folder to get all the items
return browseFolderObservable(context,currentpath)
.subscribeOn(application.defaultSubscribeScheduler())
.doOnError(new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
BsSdkLog.d("Error no file found");
}
})
.map(new Func1<ArrayList<Item>, Boolean>() {
#Override
public Boolean call(ArrayList<Item> items) {
if(items.isEmpty()) {
BsSdkLog.d(" No items");
return false;
}else {
for(int i=0;i<items.size();i++)
{
Item item=items.get(i);
BsSdkLog.d(item.toString());
}
BsSdkLog.d("Right-here");
return true;
}
}
});
}
I want to call the method that i have that creates the folder when the error occurs but i don't know how to do that.
I'm new to this so i'd really appreciate the help
Thanks
The basic principe looks like this. I used the Java NIO library for testing.
The method 'createFolder' just wraps creating a folder. The test 'name' invokes the Single and checks for an Exception. If it is an IOException it will return a fallback value. You may do something different in there. You just provide a fallback single. If it is an error different from IOException, it will return the error.
#Test
void name() throws Exception {
final String TO_CREATE = "/home/sergej/Downloads/Wurstbrot";
this.createFolder(TO_CREATE)
.onErrorResumeNext(throwable -> { // handle Exception:
// Validate Exception
if (throwable instanceof IOException) {
// Return fallback
return Single.just(Paths.get("/home/sergej/Downloads/"));
}
return Single.error(throwable);
})
.test()
.await()
.assertValueCount(1)
.assertValue(path -> path.endsWith(TO_CREATE))
.assertNoErrors();
}
private Single<Path> createFolder(String p) {
return Single.defer(() -> { // may throw some IOException
Path path = Paths.get(p);
if (!Files.exists(path)) {
Path createdDirectory = Files.createDirectory(path); // will throw if already exists
return Single.just(createdDirectory);
}
// Or just return Path, because it already exists???
return Single.error(new IOException("Already exists"));
});
}

Converting objective-c block to Swift closure

I am trying to convert this Objective-C block into Swift:
[self.client downloadEntity:#"Students" withParams: nil success:^(id response) {
// execute code
}
failure:^(NSError *error) {
// Execute code
}];
This is my code in Swift, but the syntax seems to be a bit off:
client.downloadEntity("Students", withParams: nil, success: {(students: [AnyObject]!) -> Void in
print("here")
}, failure: { (error: NSError!) -> Void! in
print ("here")
}
This is giving me a few compilation errors:
Value of 'AnyObject' has no member 'downloadEntity'
It is complaining about the lack of commas (,) right after the failure part of the code
Try this:
client.downloadEntity("Student", withParams: nil,
success: { (responseObj) -> Void in
print("success: \(responseObj)")
},
failure: { (errorObj) -> Void in
print("treat here (in this block) the error! error:\(errorObj)")
})
You need to switch to the new Swift error syntax, and you can also using trailing closures. I had to use a bool for the example to show how you would call your success closure, or you would throw an error.
var wasSuccessful = true // This is just here so this compiles and runs
// This is a custom error type. If you are using something that throws an
// NSError, you don't need this.
enum Error:ErrorType {
case DownloadFailed
}
// Hopefully you have control over this method and you can update
// the signature and body to something similar to this:
func downloadEntity(entityName: String, success: ([AnyObject]) -> Void) throws {
let students = [AnyObject]()
// download your entity
if wasSuccessful {
// Call your success completion handler
success(students)
}
else {
throw Error.DownloadFailed
}
}
When you have a function that can throw an error, you need to call it with try inside a do/catch block.
// Calling a function that can throw
do {
try downloadEntity("Students") { students in
print("Download Succeded")
}
}
catch Error.DownloadFailed {
print("Download Failed")
}
// If you are handling NSError use this block instead of the one above
// catch let error as NSError {
// print(error.description)
// }