How to access values from list of maps in Apache camel message body - arraylist

Perhaps this is easy, but I am somehow not able to crack it yet. Message body for an exchange is basically a list of maps with both key & value being string. As example,
[{'key'='val1'}, {'key'='val2'},...]
I am using simple expression to set this as a property which I would be using in subsequent routes. This is how I am setting it:
.setProperty("myProperty", simple("${body}"))
But this sets the complete body. I just want to (somehow) set only the values part to avoid setting the entire list of maps. What I have tried and not working so far:
.setProperty("myProperty", simple("${body}['key']"))
.setProperty("myProperty", simple("${body}[*]['key']"))
.setProperty("myProperty", simple("${body}[0]['key']")) // this returns only the first value, I want all
Any idea/suggestion how can I achieve this ?

You can access every level of your body with Simple expressions:
${body} // get whole list of maps
${body[0]} // get first map in the list (index 0)
${body[0][key]} // get value of key "key" from the first map in the list
What you cannot do in a Simple expression is a conversion of your data structure in another one.
However, you can simply plug a Java bean into your route
from("direct:start")
...
.bean(MyConversionBean.class)
...;
And do the conversion with Java
public class MyConversionBean {
public List<String> convertBody() {
// extract all values (or whatever) with Java;
return listOfValues;
}
}

Related

What does it mean by "segment variables matched by the URL pattern" in the following?

Reading the book Pro ASP.NET Core 3, by Adam Free Man, I saw some lines saying as follow:
The endpoint in Listing 13-7 enumerates the HttpRequest.RouteValues property to generate
a response that lists the names and value of the segment variables matched by the URL pattern.
I got confused with the highlighted part above. Could anyone explain about the following part:
the names and value of the segment variables matched by the URL pattern.
Here is the full text I mentioned in above:
endpoints.MapGet("{first}/{second}/{third}", async context => {
foreach (var kvp in context.Request.RouteValues) {
await context.Response.WriteAsync($"{kvp.Key}: {kvp.Value}\n");
} } ```
The RouteValuesDictionary class is enumerable, which means that it can
be used in a foreach loop to generate a sequence of
KeyValuePair<string, object> objects, each of which corresponds to the
name of a segment variable and the corresponding value extracted from
the request URL. The endpoint in Listing 13-7 enumerates the
HttpRequest.RouteValues property to generate a response that lists
the names and value of the segment variables matched by the URL
pattern. The names of the segment variables are first, second, and
third, and you can see the values extracted from the URL by
restarting ASP.NET Core and requesting any three-segment URL, such as
http://localhost:5000/apples/oranges/cherries, which produces the
response shown in Figure 13-8.
The string "{first}/{second}/{third}" is a URL pattern(route template) which is used to configure how the endpoint is matched.
In your case,"{first}/{second}/{third}"would match url like
https://localhost:7192/a/b/c
https://localhost:7192/1/2/3
but the url like
https://localhost:7192/a/b/c/d
https://localhost:7192/a/b
won't match
And the first segment of url path awould be bound to the {first} parameter,b would be bound to {second} and so on.all of them would be stored in HttpRequest.RouteValues in a key value format:
first:a,
second :b,
thrid :c
The official document related

Api Platform pagination custom page_parameter_name

I have very specific question on which I cannot find any answer and/or solution provided for Api Platform.
By default, the documentation states, that if you want to pass a page parameter for paging action, you must do the following:
pagination:
page_parameter_name: _page
However, due to the nature of our frontend we're not able to pass this variable to the request. It is hardcoded to the frontend request and is something like page[number]=1.
Is it possible to configure page_parameter_name to receive this variable or we need to transform it somehow in the Api itself?
Thank you!
ApiPlatform\Core\EventListener\ReadListener::onKernelRequest gets $context['filters'] from the request through ApiPlatform\Core\Util\RequestParser::parseRequestParams which ultimately uses PHP's parse_str function so the value of 'page[number]' will be in $context$context['filters']['page']['number'].
ApiPlatform\Core\DataProvider\Pagination::getPage retrieves the page number from $context['filters'][$parameterName] so whatever the value of [$parameterName] it will at best retrieve the array ['number'=> 1].
Then ::getPage casts that to int, which happens to be 1. But will (at least with PHP7) be 1 for any value under 'number'.
Conclusion: You need to transform it somehow in the Api itself. For example by decoration of the ApiPlatform\Core\DataProvider\Pagination service (api_platform.pagination).
API_URL?page[number]=2
print_r($request->attributes->get('_api_pagination'));
Array(
[number] => 2
)
The value of the "page_parameter_name" parameter should be "number" .
api_platform.yaml
collection:
pagination:
page_parameter_name: number
This may not work in version 3
vendor/api-platform/core/src/JsonApi/EventListener/TransformPaginationParametersListener.php
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
$pageParameter = $request->query->all()['page'] ?? null;
...
/* #TODO remove the `_api_pagination` attribute in 3.0 */
$request->attributes->set('_api_pagination', $pageParameter);
}

Native Query Mapping on the fly openJPA

I am wondering if it is possible to map a named native query on the fly instead of getting back a list of Object[] and then looping through and setting up the object that way. I have a call which I know ill return a massive data set and I want to be able to map it right to my entity. Can I do that or will I have to continue looping through the result set.
Here is what I am doing now...
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5)).getResultList();
That is my entity, the List (my entity is the provider). Normally I would just return a List<Object[]>
and then I would loop through that to get back all the objects and set them up as new providers and add them to a list....
//List<Provider> provList = new ArrayList<Provider>();
/*for(Object[] obj: ObjList)
{
provList.add(this.GetProviderFromObj(obj));
}*/
As you can see I commented that section of the code out to try this out. I know you can map named native queries if you put your native query in the entity itself and then call it via createNamedQuery. I would do it that way, but I need to use the IN oracle keyword because I have a list of ID's that I want to check against. It is not just one that is needed. And as we all know, native queruies don't handle the in keyword to well. Any advice?
Sigh, If only the IN keyword was supported well for NamedNativeQueries.
Assuming that Provider is configured as a JPA entity, you should be able to specify the class as the second parameter to your createNativeQuery call. For example:
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5), Provider.class).getResultList();
According to the documentation, "At a minimum, your SQL must select the class' primary key columns, discriminator column (if mapped), and version column (also if mapped)."
See the OpenJPA documentation for more details.

How to define complex routes with named parameters in express.js?

I want to set up some more complex routes that can include a number of optional parameters. Preferably, I would like to use named parameters for ease of access. Here is an example of what I'm trying to achieve:
// The following routes should be matched based on parameters provided:
// GET /books/:category/:author
// GET /books/:category/:author/limit/:limit
// GET /books/:category/:author/skip/:skip
// GET /books/:category/:author/limit/:limit/skip/:skip
// GET /books/:category/:author/sort/:sortby
// GET /books/:category/:author/sort/:sortby/limit/:limit
// GET /books/:category/:author/sort/:sortby/skip/:skip
// GET /books/:category/:author/sort/:sortby/limit/:limit/skip/:skip
app.get('/books/:category/:author/(sort/:sortby)?/(limit/:limit)?/(skip/:skip)?', myController.index);
As you can see, I'm trying to group the optional parameters with (paramKey/paramValue)?. That way I was hoping to be able to "mix and match" the optional parameters while still making use of the parameter naming. Unfortunately, this doesn't seem to work.
Is there any way to get this working without having to write straight regular expressions and adding additional logic to parse any resulting index-based parameter groups?
Basically, I'm looking for an easy way to parse key/value pairs from the route.
It looks like you want to re-implement the query string using the URL path. My guess is that if you really wanted that, yes, you would have to write your own parsing/interpreting logic. AFAIK express path parameters are positional, whereas the query string is not. Just use a query string and express will parse it for you automatically.
/books?category=sports&author=jack&limit=15?sortby=title
That will enable you to do
req.query.sortby
You may be able to get express to do 1/2 of the parsing for you with a regular expression path like (:key/:value)* or something along those lines (that will match multiple key/value pairs), but express isn't going to then further parse those results for you.
you can send data to view as follow:
//in the server side ...
app.get('/search/:qkey/:qvalue', function(req, res){
res.write(JSON.stringify({
qkey:req.params.qkey;
qvalue:req.params.qvalue;
}));
});
and in the client side... call to ajax
$.ajax({
type:"POST",
url:"/search/"+qkey+"/"+qvalue,
success: function(data){
var string = eval("(" + data + ")");
//you access to server response with
console.log(string.qkey+" and "+ string.qvalue);
}
});

Extract Drupal encoded data using MySQL from Ubercart table

I am writing an integration piece between Drupal/Ubercart and a in-house admin system.
The customer uses Ubercart products with attributes (e.g. a Plaque, which can contain a name, a company, a registration date and month). When an order is placed, the values entered for the attributes are written to uc_order_products, where the data field contains the actual values entered by the user. As far as I can tell, this is the only place where product attributes values, as entered by an end user to place an order, is stored.
The encoded attribute values uses a format seen all over Drupal tables to encode objects:
a:3:{s:10:"attributes";a:4:{s:26:"Name (to appear on plaque)";a:1:{i:0;s:10:"Some
Namee";}s:7:"Company";a:1:{i:0;s:28:"Some Company Name Goes here_";}s:19:"Certification
Month";a:1:{i:0;s:0:"";}s:18:"Certification Year";a:1:
{i:0;s:4:"2011";}}s:9:"shippable";s:1:"1";s:6:"module";s:10:"uc_product";}
And expanded, it looks like this:
a:3:
{
s:10:"attributes";
a:4:
{
s:26:"Name (to appear on plaque)";
a:1:
{
i:0;
s:10:"Some Namee";
}
s:7:"Company";
a:1:
{
i:0;
s:28:"Some Company Name Goes Herep";
}
s:19:"Certification Month";
a:1:
{
i:0;
s:0:"";
}
s:18:"Certification Year";
a:1:
{
i:0;
s:4:"2011";
}
}
s:9:"shippable";
s:1:"1";
s:6:"module";
s:10:"uc_product";
}
I there a simple way to get to the individual field values within this text using SQL? I can write a SQL function to go look for specifics, but I'd like to know if someone knows of an existing MySQL approach (perhaps within Drupal) which would do this.
Thanks!
That's a serialized array, meaning data that was processed by PHP's serialize() function before Drupal inserted it into the database. Use the opposite function unserialize() to turn that string back into an array.
Don't know if any built-in solution exists, but I ended up writing a SQL Function which takes as parameter text such as Name (to appear on plaque). The function then locates the text and extracts the succeeding { ... } block and from it retrieves the corresponding string value. Rough, but works in this case.
If someone has a better solution, I'd like to hear about it!