Quantcast
Channel: Sleepless Dev
Viewing all articles
Browse latest Browse all 217

QBit: Intercepting method calls, grabbing http request, using BeforeMethodCall, AOP like features with qbit

$
0
0
Recently someone asked me if you could capture the request parameters from a request with QBit REST support. You can.
QBit has this interface.

BeforeMethodCall

packageio.advantageous.qbit.service;

importio.advantageous.qbit.message.MethodCall;

/**
* Use this to register for before method calls for services.
* <p>
* created by Richard on 8/26/14.
*
* @author rhightower
*/
publicinterfaceBeforeMethodCall {

booleanbefore(MethodCallcall);
}
With this BeforeMethodCall interface you can intercept a method call. If you register it with a ServiceQueue via the ServiceBuilder then the method interception happens in the same thread as the service queue method calls.
If you return false from the before method then the call will not be made. You can also intercept calls at the ServiceBundle and the ServiceEndpointServer levels using theEndpointServerBuilder and the ServiceBundleBuilder. When you register aBeforeMethodCall with a service bundle or and server end point, it gets called before the method is enqueued to the actual service queue. When you register aBeforeMethodCall with a service queue, it gets called right before the method gets invoked in the same thread as the service queue, i.e., in the service thread, which is most useful for capturing the HttpRequest.
But let's say that you want to access the HttpRequest object to do something special with it. Perhaps read the request params.
This is possible. One merely has to intercept the call. Every Request object has a property called originatingRequest. A MethodCall is a Request object as is anHttpRequest. This means that you just have to intercept the call withBeforeMethodCall grab the methodCall, and then use it to get the HttpRequest.

Service example

/**
* Created by rhightower.
*/
@RequestMapping("/api")
publicclassPushService {

privatefinalThreadLocal<HttpRequest> currentRequest;

publicPushService() {
this.currentRequest =newThreadLocal<>();
}


@RequestMapping(value="/event", method=RequestMethod.POST)
publicvoidevent(finalCallback<Boolean>callback, finalEventevent) {

finalHttpRequest httpRequest = currentRequest.get();
System.out.println(httpRequest.address());
System.out.println(httpRequest.params().size());
...
}
Now in the main method, we will need to construct the service and then register the service with the endpoint.
Notice the private final ThreadLocal<HttpRequest> currentRequest; because we will use that to store the current http request.

Register a ServiceQueue with an end point server

finalManagedServiceBuilder managedServiceBuilder =ManagedServiceBuilder.managedServiceBuilder();

finalPushService pushService =newPushService();


finalServiceEndpointServer serviceEndpointServer =
managedServiceBuilder.getEndpointServerBuilder()
.setUri("/")
.build();

...


finalServiceQueue pushServiceQueue =...
serviceEndpointServer.addServiceQueue("/api/pushservice", pushServiceQueue);
Notice when we create the service queue separately we have to register the address it is bound under.
When we create the service queue (pushServiceQueue) for pushService, we want to tell it to use the same response queue as our endpoint server and register the beforeCall lambda to capture the HttpRequest from the MethodCall.

Creating a lambda expression to populate the currentRequest from the originatingRequest of the MethodCall (call)

finalServiceQueue pushServiceQueue = managedServiceBuilder
.createServiceBuilderForServiceObject(pushService)
.setResponseQueue(serviceEndpointServer.serviceBundle().responses())
.setBeforeMethodCall(call -> {

pushService.currentRequest.set((HttpRequest) call.originatingRequest());
returntrue;
})
.buildAndStart();
The full example is a bit longer as it has some other things not mentioned in this article.
publicclassEvent {

privatefinalString name;

publicEvent(Stringname) {
this.name = name;
}

publicStringgetName() {
return name;
}

}

....


importio.advantageous.qbit.annotation.*;
importio.advantageous.qbit.admin.ManagedServiceBuilder;
importio.advantageous.qbit.http.request.HttpRequest;
importio.advantageous.qbit.reactive.Callback;
importio.advantageous.qbit.reactive.Reactor;
importio.advantageous.qbit.reactive.ReactorBuilder;
importio.advantageous.qbit.server.ServiceEndpointServer;
importio.advantageous.qbit.service.ServiceQueue;

importjava.util.concurrent.TimeUnit;



/**
* Created by rhightower.
*/
@RequestMapping("/api")
publicclassPushService {


privatefinalReactor reactor;
privatefinalStoreServiceClient storeServiceClient;

privatefinalThreadLocal<HttpRequest> currentRequest;

publicPushService(finalReactorreactor,
finalStoreServiceClientstoreServiceClient) {
this.reactor = reactor;
this.storeServiceClient = storeServiceClient;
this.currentRequest =newThreadLocal<>();
}

@RequestMapping("/hi")
publicStringsayHi() {
return"hi";
}

@RequestMapping(value="/event", method=RequestMethod.POST)
publicvoidevent(finalCallback<Boolean>callback, finalEventevent) {

finalHttpRequest httpRequest = currentRequest.get();

System.out.println(httpRequest.address());

System.out.println(httpRequest.params().baseMap());
storeServiceClient.addEvent(callback, event);

}

@QueueCallback({QueueCallbackType.LIMIT, QueueCallbackType.EMPTY, QueueCallbackType.IDLE})
publicvoidload() {

reactor.process();
}


publicstaticvoidmain(String... args) {


/* Using new snapshot 2. */
finalManagedServiceBuilder managedServiceBuilder =ManagedServiceBuilder.managedServiceBuilder();

finalStoreService storeService =newStoreService();


finalServiceQueue serviceQueue = managedServiceBuilder.createServiceBuilderForServiceObject(storeService)
.buildAndStartAll();

finalStoreServiceClient storeServiceClient = serviceQueue.createProxyWithAutoFlush(StoreServiceClient.class,
100, TimeUnit.MILLISECONDS);


finalPushService pushService =newPushService(ReactorBuilder.reactorBuilder().build(),
storeServiceClient);

finalServiceEndpointServer serviceEndpointServer = managedServiceBuilder.getEndpointServerBuilder()
.setUri("/")
.build();

finalServiceQueue pushServiceQueue = managedServiceBuilder
.createServiceBuilderForServiceObject(pushService)
.setResponseQueue(serviceEndpointServer.serviceBundle().responses())
.setBeforeMethodCall(call -> {

pushService.currentRequest.set((HttpRequest) call.originatingRequest());
returntrue;
})
.buildAndStart();

serviceEndpointServer.addServiceQueue("/api/pushservice", pushServiceQueue);


serviceEndpointServer.startServer();

/* Wait for the service to shutdown. */
managedServiceBuilder.getSystemManager().waitForShutdown();

}

}
...

publicclassStoreService {

publicbooleanaddEvent(finalEventevent) {

returntrue;
}

}
...

importio.advantageous.qbit.reactive.Callback;

publicinterfaceStoreServiceClient {

voidaddEvent(finalCallback<Boolean>callback, finalEventevent);
}
...
importio.advantageous.boon.json.JsonFactory;
importio.advantageous.qbit.http.HTTP;

import staticio.advantageous.boon.core.IO.puts;

publicclassTestMain {

publicstaticvoidmain(finalString... args) throwsException {


HTTP.Response hello =HTTP.jsonRestCallViaPOST("http://localhost:9090/api/event", JsonFactory.toJson(newEvent("hello")));

puts(hello.body(), hello.status());
}
}

Viewing all articles
Browse latest Browse all 217

Latest Images

Trending Articles



Latest Images