Simple question. Is it possible to create endpoints without #Endpoint?
I want to create rather dynamic endpoints by a file and depending on the content to its context.
Thanks!
Update about my idea. I would to create something like a plugin system, to make my application more extensible for maintenance and future features.
It is worth to be mentioned I am using Micronaut with Kotlin. Right now I've got fixed defined Endpoints, which matches my command scripts.
My description files will be under /src/main/resources
I've got following example description file how it might look like.
ENDPOINT: GET /myapi/customendpoint/version
COMMAND: """
#!/usr/bin/env bash
# This will be executed via SSH and streamed to stdout for further handling
echo "1.0.0"
"""
# This is a template JSON which will generate a JSON as production on the endpoint
OUTPUT: """
{
"version": "Server version: $RESULT"
}
"""
How I would like to make it work with the application.
import io.micronaut.docs.context.events.SampleEvent
import io.micronaut.context.event.StartupEvent
import io.micronaut.context.event.ShutdownEvent
import io.micronaut.runtime.event.annotation.EventListener
#Singleton
class SampleEventListener {
/*var invocationCounter = 0
#EventListener
internal fun onSampleEvent(event: SampleEvent) {
invocationCounter++
}*/
#EventListener
internal fun onStartupEvent(event: StartupEvent) {
// 1. I read all my description files
// 2. Parse them (for what I created a parser)
// 3. Now the tricky part, how to add those information to Micronaut Runtime
val do = MyDescription() // After I parsed
// Would be awesome if it is that simple! :)
Micronaut.addEndpoint(
do.getEndpoint(), do.getHttpOption(),
MyCustomRequestHandler(do.getCommand()) // Maybe there is a base class for inheritance?
)
}
#EventListener
internal fun onShutdownEvent(event: ShutdownEvent) {
// shutdown logic here
}
}
You can create a custom RouteBuilder that will register your custom endpoints at runtime:
#Singleton
class CustomRouteBuilder extends DefaultRouteBuilder {
#PostConstruct
fun initRoutes() {
val do = MyDescription();
val method = do.getMethod();
val routeUri = do.getEndpoint();
val routeHandle = MethodExecutionHandle<Object, Object>() {
// implement the 'MethodExecutionHandle' in a suitable manner to invoke the 'do.getCommand()'
};
buildRoute(HttpMethod.parse(method), routeUri, routeHandle);
}
}
Note that while this would still feasible, it would be better to consider another extension path as the solution defeats the whole Micronaut philosophy of being an AOT compilation framework.
It was actually pretty easy. The solution for me was to implement a HttpServerFilter.
#Filter("/api/sws/custom/**")
class SwsRouteFilter(
private val swsService: SwsService
): HttpServerFilter {
override fun doFilter(request: HttpRequest<*>?, chain: ServerFilterChain?): Publisher<MutableHttpResponse<*>> {
return Flux.from(Mono.fromCallable {
runBlocking {
swsService.execute(request)
}
}.subscribeOn(Schedulers.boundedElastic()).flux())
}
}
And the service can process with the HttpRequest object:
suspend fun execute(request: HttpRequest<*>?): MutableHttpResponse<Feedback> {
val path = request!!.path.split("/api/sws/custom")[1]
val httpMethod = request.method
val parameters: Map<String, List<String>> = request.parameters.asMap()
// TODO: Handle request body
// and do your stuff ...
}
Related
I am trying to send message on kafka when there is an insertion in a particular table Record.
I consider that this part of the application will be considered a Supplier/Producer.
I have following code.
#Bean
public Supplier<RecordAlteredEvent> affectedRecordEventEmitter() {
return (/*how do I pass the data?*/) -> {
log.info("SENDING_MESSAGE TO RECORD_EVENT_TOPIC");
return new RecordAlteredEvent();
};
}
I actually want to send the data. So, I am looking for something more like following:
#Bean
public Function<RecordAlteredEvent, RecordAlteredEvent> alteredRecordEventEmitter() {
return (RecordAlteredEvent recordAlteredEvent) -> {
log.info(SENDING_MESSAGE, VDP_USERS_EVENT_TOPIC, recordAlteredEvent.toString());
return recordAlteredEvent;
};
}
Is this possible? How do I configure that ? So, for example if
I declare a 'Supplier' then how do I pass data to it ?
And if I declare a 'Function' it seems that the input will be received from the topic and forwarded. And I am not receiving the data from topic. I am receiving data from REST API/DB.
I am not sure if the following can somehow help: But with a basic try I could not succeed. hence, an example will help a lot.
#Autowired
private StreamBridge streamBridge;
// Can following work somehow in-side a function that is, for example, in spring-boot-service
streamBridge.send("myDestination", body);
For reference:
https://cloud.spring.io/spring-cloud-stream/reference/html/spring-cloud-stream.html#spring_cloud_function
https://tanzu.vmware.com/developer/guides/scs-gs/
Section : Generating Loan Applications
How can create a producer using Spring Cloud Kafka Stream 3.1
Following worked
declare field
private final StreamBridge streamBridge;
Declared functions
public void delegateRecordsEventSupplier(#NotNull final RecordsEvent alteredRecordsEvent) {
streamBridge.send("affectedRecordsEvent-out-0", alteredRecordsEvent);
}
These functions when called will place the message on the topic
Currently, I have some scenario like this where I have java interface callback which looks something like this.
Java Callback
interface Callback<T> {
void onComplete(T result)
void onException(HttpResponse response, Exception ex)
}
Suspending function for the above look like this
suspend inline fun <T> awaitCallback(crossinline block: (Callback<T>) -> Unit) : T =
suspendCancellableCoroutine { cont ->
block(object : Callback<T> {
override fun onComplete(result: T) = cont.resume(result)
override fun onException(e: Exception?) {
e?.let { cont.resumeWithException(it) }
}
})
}
My calling function looks like this
fun getMovies(callback: Callback<Movie>) {
launch(UI) {
awaitCallback<Movie> {
// I want to delegate exceptions here.
fetchMovies(it)
}
}
What I'm currently doing to catch exception is this
fun getMovies(callback: CallbackWrapper<Movie>) {
launch(UI) {
try{
val data = awaitCallback<Movie> {
// I want to delegate exceptions here.
fetchMovies(it)
}
callback.onComplete(data)
}catch(ex: Exception) {
callback.onFailure(ex)
}
}
}
// I have to make a wrapper kotlin callback interface for achieving the above
interface CallbackWrapper<T> {
fun onComplete(result: T)
fun onFailure(ex: Exception)
}
Questions
The above works but is there any better way to do this?? One of the main thing is I'm currently migrating this code from callback so I have ~20 api calls and I don't want to add try/catch everywhere to delegate the result along with the exception.
Also, I'm only able to get exception from my suspending function is there any way to get both HttpResponse as well as the exception. Or is it possible to use existing JAVA interface.
Is there any better way to delegate the result from getMovies without using callback??
Is there any better way to delegate the result from getMovies without using callback?
Let me start with some assumptions:
you're using some async HTTP client library. It has some methods to send requests, for example httpGet and httpPost. They take callbacks.
you have ~20 methods like fetchMovies that send HTTP requests.
I propose to create an extension suspend fun for each HTTP client method that sends a request. For example, this turns an async client.httpGet() into a suspending client.awaitGet():
suspend fun <T> HttpClient.awaitGet(url: String) =
suspendCancellableCoroutine<T> { cont ->
httpGet(url, object : HttpCallback<T> {
override fun onComplete(result: T) = cont.resume(result)
override fun onException(response: HttpResponse?, e: Exception?) {
e?.also {
cont.resumeWithException(it)
} ?: run {
cont.resumeWithException(HttpException(
"${response!!.statusCode()}: ${response.message()}"
))
}
}
})
}
Based on this you can write suspend fun fetchMovies() or any other:
suspend fun fetchMovies(): List<Movie> =
client.awaitGet("http://example.org/movies")
My reduced example is missing the parsing logic that turns the HTTP response into Movie objects, but I don't think this affects the approach.
I'm currently migrating this code from callback so I have ~20 api calls and I don't want to add try/catch everywhere to delegate the result along with the exception.
You don't need a try-catch around each individual call. Organize your code so you just let the exception propagate upwards to the caller and have a central place where you handle exceptions. If you can't do that, it means you've got a specific way to handle each exception; then the try-catch is the best and idiomatic option. It's what you would write if you had a plain blocking API. Especially note how trivial it is to wrap many HTTP calls in a single try-catch, something you can't replicate with callbacks.
I'm only able to get exception from my suspending function is there any way to get both HttpResponse as well as the exception.
This is probably not what you need. What exactly do you plan to do with the response, knowing that it's an error response? In the example above I wrote some standard logic that creates an exception from the response. If you have to, you can catch that exception and provide custom logic at the call site.
I am not so sure whether you really need that awaitCallback or not.
If you really have lots of Callback already in place and that's why you used it then your functions will probably already have everything in place that works correctly with the Callback, e.g. I expect some methods as follows:
fun fetchMovies(callback : Callback<List<Movie>>) {
try {
// get some values from db or from a service...
callback.onComplete(listOf(Movie(1), Movie(2)))
} catch (e : Exception) {
callback.onFailure(e)
}
}
If you do not have something like this in place, you may not even need awaitCallback at all. So if your fetchMovies function rather has a signature as follows:
fun fetchMovies() : List<Movie>
and in getMovies you pass your Callback, then all you need is probably a simple async, e.g.:
fun getMovies(callback: Callback<List<Movie>>) {
GlobalScope.launch { // NOTE: this is now a suspend-block, check the parameters for launch
val job = async { fetchMovies() }
try {
callback.onComplete(job.await())
} catch (e: Exception) {
callback.onException(e)
}
}
}
This sample can of course be changed to many similar variants, e.g. the following will also work:
fun getMovies(callback: Callback<List<Movie>>) {
GlobalScope.launch { // NOTE: this is now a suspend-block, check the parameters for launch
val job = async { fetchMovies() } // you could now also cancel/await, or whatever the job
job.join() // we just join now as a sample
job.getCompletionExceptionOrNull()?.also(callback::onFailure)
?: job.getCompleted().also(callback::onComplete)
}
}
You could also add something like job.invokeOnCompletion. If you just wanted to pass any exception to your callback in your current code, you could just have used callback.onException(RuntimeException()) at the place where you put your comment I want to delegate exceptions here..
(note that I am using Kotlin 1.3 which is a RC now...)
My Constraints are, I got a api.jar from client which I can not edit.
The java code pasted below is from the test class which I wrote to test the api.jar.
Consumer<DemoAdapter> callbackLogin = demoAdapter -> {
if (webBrowser != null) {
webBrowser.stop();
}
};
Consumer<DemoAdapter> callbackLogout = demoAdapter -> {
if (webBrowser != null) {
webBrowser.stop();
}
};
// Create
AdapterConfig config = Builder.buildConfig();
//Constructor which I need to call from C++;Issue is with above to consumer.
keycloakAdapterApplication = new KeycloakAdapterApplication(callbackLogin,callbackLogout, config);
Now same jar(api.jar) I want to use from C++.So I am supposed to write the test class in C++ using JNI.
I wrote the test class for all the methods which doesn't involve Consumer & BiConsumer of java in their call.
The parameters mentioned above (callbackLogin,callbackLogout) receives callbacks in test class.
Please help me on how to create these two parameters at C++ side?
I have a service called TestService which extends AbstractVerticle:
public class TestService extends AbstractVerticle {
#Override
public void start() throws Exception {
//Do things
}
}
I then deploy that verticle with vertx like this:
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(TestService.class.getName());
How can I get a reference to my deployed TestService after vertx instantiates it?
You should use an alternative method for deployment:
vertx.deployVerticle(TestService.class.getName(), deployment -> {
if (deployment.succeeded()) {
// here is your ID
String deploymentId = deployment.result();
} else {
// deployment failed...
}
});
If you're just interested in listing all deployed verticles then you can just request the list of ids:
vertx.deploymentIDs()
I know this question is old however it may be useful to someone to see an example of how to do this.
You will often see examples for deployment like this from vertx-examples
this follows as asynchronous micro service framework, however its really easy to get the reference as the method 'deployVerticle' (see line 29 in the link) will take an instance as shown in the simple example below, and u can get a reference in the call back as shown.
example in Kotlin easily translate to java
MyVert: io.vertx.core.AbstractVerticle() {
override fun start() {
// init
}
fun someFunction() {
}
}
fun main() {
val vertx = Vertx.vertx()
val myVert = MyVert()
vertx.deployVerticle(myVert) {
if(it.succeeded() ) {
myVert.someFunction()
}
else { println(it.cause().localizedMessage)} }
}
you can get all deployed verticles in current vertx instance by this way
Set<String> strings = vertx.deploymentIDs();
strings
.stream()
.map(id -> ((VertxImpl)vertx.getDelegate()).getDeployment(id))
.forEach(deployment -> System.out.println(deployment.verticleIdentifier() + " " + deployment.isChild() ));
Looks like the vertx API does not allow you to retrieve the Verticle objects once they are deployed. Maybe because verticles can be distributed over multiple JVM.
I needed to do it for unit tests though and I came up with this.
This is unreliable since you rely on VertxImpl (it can break at any vertx version upgrade). But I prefer this over changing production code to be able to test it.
private static <T extends Verticle> List<T> retrieveVerticles(Vertx vertx, Class<T> verticleClass) {
VertxImpl vertxImpl = (VertxImpl) vertx;
return vertxImpl.deploymentIDs().stream().
map(vertxImpl::getDeployment).
map(Deployment::getVerticles).
flatMap(Set::stream).
filter(verticleClass::isInstance).
map(verticleClass::cast).
collect(Collectors.toList());
}
Usage example:
vertx.deployVerticle(new MainVerticle());
// some MyCustomVerticle instances are deployed from the MainVerticle.start
// you can't reach the MyCustomVerticle objects from there
// so the trick is to rely on VertxImpl
List<MyCustomVerticle> deployedVerticles = retrieveVerticles(vertx, MyCustomVerticle.class);
In my configuration's spring/resources.xml file, I define a bean like this :
<bean id="myService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="http://${remote.host}:8080/MyAgent/remoting/MyService"/>
<property name="serviceInterface" value="services.MyService"/>
</bean>
In my Config.groovy file I have :
remote.host = "someipaddress"
Now I'd like to change this placeholder's value at runtime. In a regular spring app, I do this through a PropertyPlaceHolderConfigurer, then I refresh the context and it works.
In Grails, how can I refresh the context ?
Regards,
Philippe
Ok I give up the refreshing approach.
As a workaround, I created a grails service that looks like this :
class myService {
def myRemoteService
static transactional = false
private MyRemoteService getService(String remoteServiceURL) {
HessianProxyFactory factory = new HessianProxyFactory();
try {
return (MyRemoteService) factory.create(MyRemoteService.class, url);
}
catch (MalformedURLException e) {
e.printStackTrace()
}
return null
}
def someRemoteMethod(String remoteServiceURL) {
getService(remoteServiceURL).myRemoteMethod()
}
}
This allows me to invoke the remote service on any distant machine dinamically.
I'm still interested in a cleaner solution as this makes me rewrite a wrapper method for each remote method :-S
Why not just update the value directly:
def blabla
...
void someServiceMethod() {
blabla.someProperty = 'new value'
}
or
def blabla
...
def someControllerAction = {
blabla.someProperty = 'new value'
}
grailsApplication expose a refresh() method, i'm not sure if it will reload spring context, you could try.
I did a quick search in grails mailing list, and looks like grails do not support app-context reload.
You could try implement InitializingBean and get the values direct from app config.
import org.springframework.beans.factory.InitializingBean
class ExampleService implements InitializingBean {
def grailsApplication
def setting
void afterPropertiesSet() {
this.setting = grailsApplication.config.setting
}
}
Maybe you can listen for changes in the config or get the property every time you need to use it, i do not know, i can not create a app to run some tests right now.
Not tested, but try:
import grails.spring.BeanBuilder
def bb = new BeanBuilder(
application.parentContext,
new GroovyClassLoader(application.classLoader))
def beans = bb.beans {
myService(org.springframework.remoting.caucho.HessianProxyFactoryBean) {
...
}
}
beans.registerBeans(application.mainContext)
This is pretty much what plugins do when they need to swap in new bean instances. You could also raise a JIRA issue for a nicer way of doing this.