I am new to microservices and Lagom framework, in the service api where we make ServiceCalls I do not understand the difference of namedcall, pathcall and restcall. where and when should we use which?
for instance in these calls:
ServiceCall<NotUsed, Cargo, Done> register();
restCall(Method.POST, "/api/registration", register()
ServiceCall<NotUsed, NotUsed, Source<Cargo, ?>> getLiveRegistrations();
pathCall("/api/registration/live", getLiveRegistrations())
ServiceCall<User, NotUsed> createUser();
namedCall("/api/users", this::createUser)
The Lagom Documentation covers it pretty well:
Named
The simplest type of identifier is a name, and by default, that name is set to be the same name as the name of the method on the interface that implements it. A custom name can also be supplied, by passing it to the namedCall method:
default Descriptor descriptor() {
return named("hello").withCalls(
namedCall("hello", this::sayHello)
);
}
In this case, we’ve named it hello, instead of the default of sayHello. When implemented using REST, this will mean this call will have a path of /hello.
Path
The second type of identifier is a path based identifier. This uses a URI path and query string to route calls, and from it dynamic path parameters can optionally be extracted out. They can be configured using the pathCall method.
Dynamic path parameters are extracted from the path by declaring dynamic parts in the path. These are prefixed with a colon, for example, a path of /order/:id has a dynamic part called id. Lagom will extract this parameter from the path, and pass it to the service call method.
ServiceCall<NotUsed, Order> getOrder(long id);
default Descriptor descriptor() {
return named("orders").withCalls(
pathCall("/order/:id", this::getOrder)
);
}
Multiple parameters can of course be extracted out, these will be passed to your service call method in the order they are extracted from the URL:
Rest Call
The final type of identifier is a REST identifier. REST identifiers are designed to be used when creating semantic REST APIs. They use both a path, as with the path based identifier, and a request method, to identify them. They can be configured using the restCall method:
ServiceCall<Item, NotUsed> addItem(long orderId);
ServiceCall<NotUsed, Item> getItem(long orderId, String itemId);
ServiceCall<NotUsed, NotUsed> deleteItem(long orderId, String itemId);
default Descriptor descriptor() {
return named("orders").withCalls(
restCall(Method.POST, "/order/:orderId/item", this::addItem),
restCall(Method.GET, "/order/:orderId/item/:itemId", this::getItem),
restCall(Method.DELETE, "/order/:orderId/item/:itemId", this::deleteItem)
);
}
Related
TLDR: Multiple Pathparameters and Endpoints with Swagger
What i would like to to is some API Endpoint like this:
/foo/{id}/bar
Now afaik foo or the first node in the path is defining the endpoint and also the resource to aqcuire. Therefore a FooApiServiceImpl is generated.
The generated ProjectsApiService stub looks like this atm:
#GET
#Path("/{id}/bars")
...
public Response getBarsByFooId(#ApiParam(value = "The id of the foo with the bars",required=true ) #PathParam("id") String id)
throws NotFoundException {
return delegate.getBarByFooId(id);
}
Now my wished behaviour would be to GET all the Bar resources that are connectted to the Foo with the given {id}. Kinda like the reverse order. Is this somehow possible?
If this is not possible... then would also like to ask, how can i get url nodes (foo, bar) that are not defined as {xxx} paramaters in brackets?
Something like this:
public Response getBarsByFooId(String foo, String id, String bar)
throws NotFoundException {
return delegate.getBarByFooId(id);
}
To get the paths segments, inject a UriInfo in your resource class or method:
#Context
private UriInfo uriInfo;
And then invoke UriInfo.getPathSegments() from it:
List<PathSegment> segments = uriInfo.getPathSegments();
See the UriInfo.getPathSegments() documentation:
Get the path of the current request relative to the base URI as a list of PathSegment. This method is useful when the path needs to be parsed, particularly when matrix parameters may be present in the path. All sequences of escaped octets in path segments and matrix parameter values are decoded, equivalent to getPathSegments(true).
I'm a new User of POCO and could get HTTP response after HTTP::Request.
By the way, How do I create HTTP request with some parameters? For example, I want to set URI, http://xxxx/index.html?name=hoge&id=fuga&data=foo.
Of course I know it's possible if I set this uri directly. But I want to realize this like below. Does anyone know this way?
URI uri("http://xxx/index.html");
uri.setParam("name", "hoge");
uri.setParam("id", "fuga");
uri.setParam("data", "foo");
If you had looked up the documentation for Poco::URI, you'd see it's done with uri.addQueryParameter("name", "value"):
void addQueryParameter(
const std::string & param,
const std::string & val = ""
);
Adds "param=val" to the query; "param" may not be empty. If val is empty, only '=' is appended to the parameter.
In addition to regular encoding, function also encodes '&' and '=', if found in param or val.
You can also set all the parameters with setQueryParameters.
Unfortunately, Poco doesn't let you set the value of an existing query parameter (or remove it). If you want to do that, you have to clear the query portion of the URI and readd all the parameters you want with their values.
I am passing an Employee Object Form Client in RestFul webservices Jaxrs2/jersy2
#GET
#Path("{empObj}")
#Produces(MediaType.APPLICATION_XML)
public Response readPK(#PathParam("empObj")Employee empObj) {
//do Some Work
System.out.println(empObj.getName());
return Response.status(Response.Status.OK).entity(result).build();
}
how can achive this object using GET method??
thanx in advance
By using #PathParam on a method parameter / class field you're basically telling JAX-RS runtime to inject path segment (usually string) to your (String) parameter. If you're sending an object (Employee) representation directly via your URI (query param, path param) you should also provide ParamConverterProvider. Beware that this is not possible in some situation and it's not a recommended practice. However, if you're sending the object from client to server in message body, simply remove #PathParam and MessageBodyReader will take care of converting input stream to your type:
#GET
#Path("{empObj}")
#Produces(MediaType.APPLICATION_XML)
public Response readPK(Employee empObj) {
//do Some Work
System.out.println(empObj.getName());
return Response.status(Response.Status.OK).entity(result).build();
}
I want to extend the Wso2 CEP product in our needs and try to write a custom condition as indicated in this official wso2 cep link.
I am able to write an extension class that extends "org.wso2.siddhi.core.executor.conditon.AbstractGenericConditionExecutor" and implement its abstract method as indicated below:
#SiddhiExtension(namespace = "myext", function = "startswithA")
public class StringUtils extends
org.wso2.siddhi.core.executor.conditon.AbstractGenericConditionExecutor {
static Log log = LogFactory.getLog(StringUtils.class);
#Override
public boolean execute(AtomicEvent atomicEvent) {
log.error("Entered the execute method");
log.error("Atomic event to string: " + atomicEvent.toString());
return true;
}
}
when i use this extensioned method as:
from allEventsStream[myext:startswithA(name)]
insert into selectedEventsStream *;
In this situation, i want that startswithA method returns true if the name field has 'A' at the begining of it. However when i run this query in CEP the whole event drops into my execute function i.e. there is no sign to show that i send "name" field is sent to startswithA method as argument.
How can i understand which field of the stream is sent to my extended method as argument?
Also i want to write conditions like
from allEventsStream[myext:startswith('A', name)]
insert into selectedEventsStream *;
How can i achive this?
In 'AbstractGenericConditionExecutor' there's another method that gives you the set of expression executors that are included in the parameters when executor instantiates:
public void setExpressionExecutors(List<ExpressionExecutor> expressionExecutors)
You don't necessarily have to override this method and store the list, it is already stored there in the 'AbastractGenericConditionExecutor' as a list named expressionExecutors. You can pass the event to these executors to retrieve the relevant values from the event in order.
For an example, if you include a variable (like 'name') in the query (as a parameter at index 0), you'll get a 'VariableExpressionExecutor' in the list at index 0 that will fetch you the value of the variable from the event. Similarly for a constant like 'A', you'll get a different executor that will give you the value 'A' when called.
To add to Rajeev's answer, if you want to filter all the names that starts with 'A', you can override the execute method of your custom Siddhi extension similar to the following segment.
#Override
public boolean execute(AtomicEvent atomicEvent) {
if(!this.expressionExecutors.isEmpty()) {
String name = (String)this.expressionExecutors.get(0).execute(atomicEvent);
if(name.startsWith("A")) {
return true;
}
}
return false;
}
When writing the query, it would be similar to
from allEventStream[myext:startsWithA(name)]
insert into filteredStream *;
You can extend this behaviour to achieve an extension that supports
from allEventsStream[myext:startswith('A', name)]
type queries as well.
HTH,
Lasantha
I'd like to load 2 different input models (a .bpel and a .wsdl) in my main template of Acceleo.
I loaded the ecore metamodels for both bpel and wsdl and I'd like to be able to use something like this:
[comment encoding = UTF-8 /]
[module generate('http:///org/eclipse/bpel/model/bpel.ecore','http://www.eclipse.org/wsdl/2003/WSDL')/]
[import org::eclipse::acceleo::module::sample::files::processJavaFile /]
[template public generate(aProcess : Process, aDefinition : Definition)]
[comment #main /]
Process Name : [aProcess.name/]
Def Location : [aDefinition.location/]
[/template]
but when I run the acceleo template I get this error:
An internal error occurred during: "Launching Generate".
Could not find public template generate in module generate.
I think I have to modify the java launcher (generate.java) because right now it can't take 2 models as arguments. Do you know how?
Thanks!
** EDIT from Kellindil suggestions:
Just to know if I understood it right, before I get to modify stuff:
I'm trying to modify the Generate() constructor.
I changed it in:
//MODIFIED CODE
public Generate(URI modelURI, URI modelURI2, File targetFolder,
List<? extends Object> arguments) {
initialize(modelURI, targetFolder, arguments);
}
In the generic case, I can see it calls the AbstractAcceleoGenerator.initialize(URI, File, List>?>), shall I call it twice, once per each model? like:
initialize(modelURI, targetFolder, arguments);
initialize(modelURI2, targetFolder, arguments);
Then, to mimic in my Generate() constructor the code that is in the super-implementation:
//NON MODIFIED ACCELEO CODE
Map<String, String> AbstractAcceleoLauncher.generate(Monitor monitor) {
File target = getTargetFolder();
if (!target.exists() && !target.mkdirs()) {
throw new IOException("target directory " + target + " couldn't be created."); //$NON-NLS-1$ //$NON-NLS-2$
}
AcceleoService service = createAcceleoService();
String[] templateNames = getTemplateNames();
Map<String, String> result = new HashMap<String, String>();
for (int i = 0; i < templateNames.length; i++) {
result.putAll(service.doGenerate(getModule(), templateNames[i], getModel(), getArguments(),
target, monitor));
}
postGenerate(getModule().eResource().getResourceSet());
originalResources.clear();
return result;
}
what shall I do? Shall I try to mimic what this method is doing in my Generate() constructor after the initialize() calls?
What you wish to do is indeed possible with Acceleo, but it is not the "default" case that the generated launcher expects.
You'll have to mark the "generate" method of the generated java class as "#generated NOT" (or remove the "#generated" annotation from its javadoc altogether). In this method, what you need to do is mimic the behavior of the super-implementation (in AbstractAcceleoLauncher) does, loading two models instead of one and passing them on to AcceleoService#doGenerate.
In other words, you will need to look at the API Acceleo provides to generate code, and use it in the way that fits your need. Our generated java launcher and the AcceleoService class are there to provide an example that fits the general use case. Changing the behavior can be done by following these samples.
You should'nt need to modify the Generate.java class. By default, it should allow you to perform the code generation.
You need to create a launch config and provide the right arguments (process and definition) in this launch config, that's all.
I don't understand the 'client.xmi' URI that is the 1st argument of your module. It looks like it is your model file, if so remove it from the arguments, which must only contain your metamodels URIs.