How to handle multiple flatMaps with one defaultOnEmpty handler in Spring WebFlux - spring

How can I handle empty responses from multiple flatMap's with a single defaultOnEmpty?
Like I have the following chain. The defaultOnEmpty gets only triggered if the last flatMap returns an empty result, but I want to get it also triggerd when e.g. the first flatmap returns an empty result (and just skip the other flatMap's).
repository.findById(id)
.flatMap(...)
.flatMap(...)
.flatMap(...)
.defaultOnEmpty(0)

Related

Response Assertion JMeter on Array

I'm trying to get assert a response body from a list of objects that were deleted with AWS SDK, the scenario is this:
I use a Delete Http request to a endpoint passing an array, with a list of object names, then aws should return the list with the objects that were deleted, but it's not in the same order of the list that i've passed, so i'm using a Contains to see if the objects are in the response body.
Someone can help me? I think that is a problem with Regex from JMeter but I'm freeze with this.
You're using Contains pattern matching rule which expects the pattern to be a Perl-5 compatible regular expression
In this case you will need to properly escape all the meta characters either manually or using a __groovy() function calling Pattern.quote() method instead:
${__groovy(java.util.regex.Pattern.quote(vars.get('listOfObjects')),)}
If you want to check whether the response just contains your ${listOfObjects} variable switch to Substring pattern matching rule

How to return and write data into a file using apache camel?

After a rest call, I am trying to set me camel route to return the data and write it into a cvs file. Problem is that I can get it to do only one of the two.
from("direct:select")
.setBody(constant("select * from animal")).to("jdbc:dataSource").marshal().csv()
.to("file:///tmp?fileName=MY_TEST_FILE.csv");
In the current version it writes into the file correctly but the rest response is just a bunch of numbers. Though if I change the order of functions like:
from("direct:select")
.setBody(constant("select * from animal"))
.to("file:///tmp?fileName=MY_TEST_FILE.csv").marshal().csv().to("jdbc:dataSource");
I get the correct rest response but in the file I get:
select * from applicant
Is there a way to do both from a single camel route?
Camel just executes the routing/transformation instructions in the order that you define them.
Your first attempt makes some sense: you run the select query, get the list of rows out of the JDBC call, convert it to CSV, then write it to file and return it as reply of your route.
That last part is important to understand: the reply from your route will be whatever your exchange body contains at the end of the (synchronous) processing.
Given that you're not happy with this first attempt, I will go and assume that the CSV format is not what you intend to return as reply.
Now looking at your second attempt, you say that it returns the expected reply but that is surprising to me: you're trying to convert the literal string "select * from animal" to CSV, which is throwing an exception on my end:
org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: java.lang.String to the required type: java.util.List with value select * from animal
Now if you remove the .marshal().csv(), the route is working. It writes "select * from animal" to file as you've observed (but that's exactly what the route is instructing to do) and it returns as reply the content of the exchange body at the end of the route, meaning the List that results from the JDBC call. I will thus make another assumption that this list is in fact what you're intending to return (you probably want to return JSON, so List does indeed fit the bill for seamless JSON conversion).
With all this in mind, let's try to find you a route that does what you want. However, we hit a bit of a wall with your requirement to "do both from a single camel route". Let's hope that you didn't mean to exclude the usage of sub-routes linked by direct: endpoints (I don't see any good reason why you'd want to avoid that).
Here's a first solution that does everything synchronously (JDBC call + writing to file both done by the originating thread):
from("direct:select")
.setBody(constant("select * from animal"))
.to("jdbc:dataSource")
.enrich("direct:file", new UseOriginalAggregationStrategy());
from("direct:file")
.marshal().csv()
.to("file:///tmp?fileName=MY_TEST_FILE.csv");
See Camel Enrich EIP for more details.
And here's one that will write to file asynchronously (i.e. in a separate thread), meaning that your REST call should be a bit faster to respond:
from("direct:select")
.setBody(constant("select * from animal"))
.to("jdbc:dataSource")
.wireTap("direct:file");
from("direct:file")
.marshal().csv()
.to("file:///tmp?fileName=MY_TEST_FILE.csv");
See Camel Wire Tap EIP for more details.

How to get the result of a asynchronous action in NGXS?

I want to perform an action based to the result of an asynchronous NGXS action.
In a Angular frontend app I'm using NGXS for state management. Some of the actions involve talking to a backend via REST calls. Those actions are implemented as asynchronous actions, with the reducer functions in my state classes returning an Observable.
What I'm looking for is a way to get hands on the result of the backend call, to be able to perform some action.
One use case I'm trying to implement is navigation to just created objects: Business objects are created in the frontend (Angular) app with a couple of domain properties. They get persisted in the backend, and as a result an ID for this object is created and returned to the frontend, and incorporated into the NGXS store. As a direct response to this, I'd like to navigate to a detail view for the new object. To do so, I need
(a) the information that the call has been returned successful, and
(b) the answer from the backend (the ID in this case).
Another slightly more complicated use case is the assignment of a number of tags to an business object. The tags are entities by themselfes, and have an ID each. In the UI, the user can either pick existing or add new tags. Either way, multiple tags can be added in a single step in the UI, which means I have to
call the backend for each new tag to create the ID
after all missing tags are created, update the business object with the list of tag IDs
In general, there are use cases in the frontend that depend on the result of a backend call, and there is no clean way to find this result in the store (although it's in there)
I know I can subscribe to the Observable returned from the store's dispatch method (as shown in asynchronous actions).
I also know about action handlers. In both cases I can attach code to the event of an action finished, but neither option enables me to get the result of the backend call. In the fist case, the Observable carries the whole store, while in the latter case I get the original Action, which is unfortunately missing the essential information (the ID).
The part you're missing here are selectors. Dispatching actions is not supposed to give you back a result. The only purpose of the Observable returned by store.dispatch() is to tell you when the action's handlers are done.
To get to the data returned by your calls to the backend, you have to patch the state inside your action handler. And then, outside of your state, you can access the data using store.select() or store.selectSnapshot() depending on what you need. Your state class should look somewhat like this (untested):
#State()
export class SampleState {
#Selector(SampleState)
sampleSelector(state) {
return state.sampleObject;
}
#Action(SampleAction)
sampleAction(ctx: StateContext<any>, action: sampleAction) {
return sampleBackendCall(/* ... */).pipe(
tap((result) => {
ctx.patchState({ sampleObject: result });
})
);
}
}
Now you can access this result where ever you need using the Store. For the use case of navigating to an element after its creation, you can combine a subscription to store.dispatch() with a store.selectSnapshot() like this:
store.dispatch(new SampleAction()).subscribe(() => {
navigateTo(store.selectSnapshot(SampleState.sampleSelector));
});
Note that in this easy case a selectSnapshot is perfectly fine, as we only want to get the value we just finished writing into the state. In most cases though, you will want to use store.select() or the #Select() decorator because they return Observables which enable you to also correctly display changes in your state.
That said, I'd like to add that if saving data inside the state is not necessary for you at all, then probably NGXS is the wrong library for you in the first place and you could as well just use an ordinary angular service directly returning the result of the backend call, like suggested in the comments.

Usage of filter_path with helpers.scan in elastisearch client

When doing a search operation in elasticsearch i want the metadata to be filtered out and return only "_source" in the response. I'm able to achieve the same through "search" in the following way:
out1 = es.search(index='index.com', filter_path=['hits.hits._id',
'hits.hits._source'])
But when i do the same with scan method it just returns an empty list:
out2 = helpers.scan(es, query, index='index.com',
doc_type='2016-07-27',filter_path= ['hits.hits._source'])
The problem may be with the way i'm processing the response of 'scan' method or with the way i'm passing the value to filter_path. To check the output i parse out2 to a list.
The scan helper currently doesn't allow passing extra parameters to the scroll API so your filter_path doesn't apply to it. It does, however, get applied to the initial search API call which is used to initiate the scan/scroll cycle. This means that the scroll_id is stripped from the response causing the entire operation to fail.
In your case even passing the filter_path parameter to the scroll API calls would cause the helper to fail because it would strip the scroll_id which is needed for this operation to work and also because the helper relies on the structure of the response.
My recommendation would be to use source filtering if you need to limit the size of the response or use smaller size parameter than the default 1000.
Hope this helps,
Honza
You could pass filter_path=['_scroll_id', '_shards', 'hits.hits._source'] to the scan helper to get it to work. Obviously that leaves some metadata in the response but it removes as much as possible while allowing the scroll to work. _shards is required because it is used internally by the scan helper.

Jersey Rest Client with empty string param

I'm using Jersey to consume some rest services, but I having a problem when I try to sent a parameter empty because seems that Jersey doesn't map the empty or null parameter.
Jersey generate something like (value is the empty string, the equals is lost and I get a 500 error):
http://myservice.test.com/services/rest/setAttribute?id=555&value&test=test
If I go to the browser an enter (this one works!!!):
http://myservice.test.com/services/rest/setAttribute?id=555&value=&test=test
The value field is required so I need to sent it every request, but I cannot set it in empty and sometimes I need the value an empty string.
Thanks...
You can add #JsonWriteNullProperties to the class you serializes to force it to write null values.

Resources