Play framework 2.6 java websockets akka dependency injection - java

I am using java websockets in play framework 2.6 and having hard time figuring out Guice DI. Below I am injecting DbService (which perform some db operations) but I am getting DbService as null and throwing NPE at line
User user = dbService.findByName(inEvent.getUsername());
dbService is null. I am not sure why its not injecting DbService. Although this work when I don't use it via akka actors. I do bind DbService to its implementation.
Actor
public class TestActor extends AbstractActor {
#Inject
private DbService dbService;
private ActorRef out;
public static Props props(final ActorRef out) {
return Props.create(TestActor.class, out);
}
public TestActor(ActorRef out) {
this.out = out;
}
#Override
public Receive createReceive() {
return receiveBuilder()
.match(InEvent.class, inEvent -> {
System.out.println(inEvent.getUsername());
User user = dbService.findByName(inEvent.getUsername());
System.out.println(user.getFirstName());
out.tell("userName is ", self());
}
)
.build();
}
}
Controller
public class Application extends Controller {
public WebSocket TestWebSocket() {
return WebSocket.json(InEvent.class).acceptOrResult(request -> {
final Token token = verifyToken(request());
if (token == null) {
return CompletableFuture.completedFuture(F.Either.Left(forbidden()));
}
return CompletableFuture.completedFuture(
F.Either.Right(ActorFlow.actorRef(out -> TestActor.props(out), actorSystem, materializer)));
});
}
}

Your actor will be constructed based on the parameters used in Props.create().
In your example:
Props.create(Class<TestActor>, ActorRef);
Will match the constructor in the TestActor.class with one argument of type ActorRef, and that constructor will be calle with the arguments that you provide.
You can change your constructor signature and the props method like this:
...
public static Prop props(ActorRef out, DBServide db) {
return Props.create(TestActor.class, out, db);
}
...
public TestActor(ActorRef out, DBService db) {
this.out = out;
this.dbService = db;
}
...
With this, the constructor TestActor(ActorRef, DBService) will be used and you will get the instance of DBService used when you called the static method props.

Related

Incorporating Guice and AOP

I'm building a package that is trying to intercept a function's return value based on a flag. My design involves some AOP. The idea is that a class FirstIntercept intercepts a call firstCall and stores parameters in a Parameters object. Then later, a second class SecondIntercept intercepts another call secondCall and does some logic based on what is populated in Parameters:
// pseudoish code
public class FirstIntercept {
private Parameters param;
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// logic handling payload returned from firstCall()
// logic provides a Boolean flag
this.param = new Parameters(flag);
}
}
public class Parameters {
#Getter
private Boolean flag;
public Parameters(Boolean flag) {
this.flag = flag;
}
}
public class SecondIntercept {
private static Parameters params;
#Around("execution(* ...secondCall(..))")
public void handleSecondCallIntercept(ProceedingJoinPoint joinPoint) {
// want to do logic here based on what params contains
}
}
What I want to achieve is that the Parameters object is loaded once and for all when FirstIntercept.loadParam is invoked through AOP. I'm not too sure how I can go about with this persistence. I looked online and Google guice seems to be promising. I believe a first step would to use dependency injection on the Parameters, but I'm really not sure. Can someone help point me in the right direction?
edit:
So I tried this setup:
public class FirstIntercept implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("invoked!");
return invocation.proceed();
}
#AfterReturning(pointcut = "execution(* ...firstCall(..))", returning = "payload")
public void loadParam(Joinpoint joinPoint, Object payload) {
// do stuff
}
public String firstCall() {
return "hello";
}
}
public class InterceptionModule extends AbstractModule {
protected void configure() {
FirstIntercept first = new FirstIntercept();
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class), first);
}
}
public class FirstIterceptTest {
#Test
public void dummy() {
Injector injector = Guice.createInjector(new InterceptionModule());
FirstIntercept intercept = injector.getInstance(FirstIntercept.class);
intercept.firstCall();
}
}
When I do .firstCall(), I can see the #AfterReturning running but the invoke is not being called.
If you expand upon the documentation for AOP https://github.com/google/guice/wiki/AOP you should get something close to:
public class FirstInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
// your logic based on result to set parameters.setFlag()
return result;
}
}
Then the second:
public class SecondInterceptor implements MethodInterceptor {
#Inject Parameters parameters; // Injected with singleton Parameter
public Object invoke(MethodInvocation invocation) throws Throwable {
boolean flag = parameters.getFlag();
// your logic here
return invocation.proceed(); // maybe maybe not?
}
}
Your parameters is the key, you'll need to ensure it's thread safe, which is another topic. But to inject these you need:
public class InterceptionModule extends AbstractModule {
protected void configure() {
// Ensure there is only ever one Parameter injected
bind(Parameter.class).in(Scopes.SINGLETON);
// Now inject and bind the first interceptor
FirstInterceptor firstInterceptor = new FirstInterceptor();
requestInjection(firstInterceptor );
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
firstInterceptor);
// Now inject and bind the second interceptor
SecondInterceptor SecondInterceptor = new SecondInterceptor ();
requestInjection(firstInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AfterReturning.class),
SecondInterceptor);
}
}
Edit
Look at what you're doing.
You're telling Guice to wrap a method with #AfterReturn with the FirstInterceptor
Then you're calling interceptor.firstCall()
First call does not have #AfterReturn annotation, so why would it be matched against that configuration?
I'm guessing if you called:
intercept.loadParam();
you would see the invoke method. Also, this is great for a test, but in real life you want to have a Service level class have the #AfterReturn which is then Injected into another Api/Job/Etc that will call LoadParam.
edit
Oh no. Take a look at this line
bindInterceptor(Matchers.any(), // a class with this matcher
Matchers.annotatedWith(AfterReturning.class), // a method with this
firstInterceptor);
This means that the injector only fires on the loadParams. You need to annotate the method of the class youw ish to cause the interception with #AfterReturning. And you want the loadParams to be the invoke method.

how to set dynamic header in spring remoting

We need to call a Bean class using spring remoting and also set dynamic header in the call. We can set custom HttpInvokerRequestExecutor in the HttpInvokerProxyFactoryBean and add header but how to set dynamic header generated on the fly for the request?
In the Config class, declaring the HttpInvokerProxyFactoryBean
#Bean
#Qualifier("service")
public HttpInvokerProxyFactoryBean invoker() {
HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
invoker.setServiceUrl(url);
invoker.setServiceInterface(Service.class);
return invoker;
}
In the invoker class
#Autowired
Service service;
public void invoke(Bean bean) {
service.process(bean);
}
Its been a long time that I used spring remoting but as far as I remember I found a solution to this by subclassing of SimpleHttpInvokerRequestExecutor which is default when you do not set any custom request executor to HttpInvokerProxyFactoryBean.
IMHO you can write a custom request executor which you can set custom header values and a simple helper component which sets the dynamically provided values to the executor before the next request.
CustomHttpInvokerRequestExecutor:
public class CustomHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {
private Map<String, String> headers;
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
#Override
protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
super.prepareConnection(connection, contentLength);
if (headers != null) {
// adding our custom headers
for (String headerName : headers.keySet()) {
connection.setRequestProperty(headerName, headers.get(headerName));
}
// do not want to persist headers for another request!
headers.clear();
}
}
}
CustomRemoteExecutor:
#Component
public class CustomRemoteExecutor {
#Autowired
private HttpInvokerProxyFactoryBean factoryBean;
/*
* May be you should need a synchronized modifier here if there is possibility
* of multiple threads access here at the same time
*/
public void executeInTemplate(Map<String, String> headers, Runnable task) {
CustomHttpInvokerRequestExecutor executor = (CustomHttpInvokerRequestExecutor) factoryBean.getHttpInvokerRequestExecutor();
executor.setHeaders(headers);
task.run();
}
}
And then you can use it by below:
#Bean
#Qualifier("service")
public HttpInvokerProxyFactoryBean invoker() {
HttpInvokerProxyFactoryBean invoker = new HttpInvokerProxyFactoryBean();
invoker.setServiceUrl(testUrl);
invoker.setServiceInterface(Service.class);
// set our custom request executor
CustomHttpInvokerRequestExecutor executor = new CustomHttpInvokerRequestExecutor();
invoker.setHttpInvokerRequestExecutor(executor);
return invoker;
}
#Autowired
CustomRemoteExecutor executor;
#Autowired
Service service;
public void invoke(Bean bean) {
// when you need custom headers
Map<String, String> headers = new HashMap<>();
headers.put("CUSTOM_HEADER", "CUSTOM_VALUE");
headers.put("CUSTOM_HEADER2", "CUSTOM_VALUE2");
executor.executeInTemplate(headers, () -> service.process(bean));
}
There is one drawback here as I also stated in comments, if you execute your proxy service client in a multithreaded environment (server to server requests may be) you should consider to make executeInTemplate method synchronized
An addition to my answer if your service method needs to return some object then you can add another helper method to CustomRemoteExecutor and use it when you need to return something. The method can have the same name here so it can overload the former one which is much better I think.
public <T> T executeInTemplate(Map<String, String> headers, Callable<T> task) {
CustomHttpInvokerRequestExecutor executor = (CustomHttpInvokerRequestExecutor) factoryBean.getHttpInvokerRequestExecutor();
executor.setHeaders(headers);
try {
return task.call();
} catch (Exception e) {
// it is better to log this exception by your preferred logger (log4j, logback
// etc.)
e.printStackTrace();
}
return null;
}
And again you can use like below:
#Autowired
CustomRemoteExecutor executor;
#Autowired
ISampleService service;
public void invoke(Bean bean) {
// when you need custom headers
Map<String, String> headers = new HashMap<>();
headers.put("CUSTOM_HEADER", "CUSTOM_VALUE");
headers.put("CUSTOM_HEADER2", "CUSTOM_VALUE2");
// assume that service.returnSomething() method returns String
String value = executor.executeInTemplate(headers, () -> service.returnSomething(bean));
}
Hope it helps.

how to create multiple instance of same type using google Guice

We have used Google Guice framework for dependency injection. I need to create multiple insatnce of an interface in java.
The execution starts from here: KfhRecordValidator.java class in the below code:
public class KfhRecordValidator implements RequestHandler<Request, Response> {
public Response handleRequest(Request request, Context context)
{
// Resolve the necessary dependencies, and process the request.
Injector injector = Guice.createInjector(new
DependencyModule());
Processor processor =
injector.getInstance(Processor.class);
return processor.process(request, context);
}}
The process class is having reference of RecordValidationHelper class and the injection is through constructor.
IRecordValidationService.java is an interface that is having validate method.
public interface IRecordValidationService {
void validate(Record record) throws ValidationException;}
class processor is having one method called process that is being called in RecordValidationHelper class.
class Processor {
private final RecordValidationHelper recordValidationHelper;
#Inject
#SuppressWarnings({"WeakerAccess"})
public Processor(IRecordValidationService recordValidationService,
IRecordService<ErrorRecord> recordService,
S3UtilsInterface s3Utils, IEnvironmentVariableReader
environmentVariableReader) {
this.recordValidationHelper = new
RecordValidationHelper(recordValidationService);
this.errorRecordHelper = new
ErrorRecordHelper(recordService, environmentVariableReader);
}
public Response process(Request request, #SuppressWarnings("unused") Context context) {
// Validate records
List<LambdaRecord> records = recordValidationHelper.processRecords(request.getRecords());}
Class DependencyModule.java extneds AbstractModule class of Guice injection that is having configure method.
class DependencyModule extends AbstractModule {
#Override
protected void configure() {
String validationType = System.getenv("ValidationType");
validationType= validationType.toLowerCase(Locale.ENGLISH);
String valType[]= validationType.split(",");
int length= valType.length;
for(int i=0;i<length;i++){
switch(valType[i]){
case "json":
bind(IRecordValidationService.class).to(JsonValidationService.class);
break;
case "avro":
bind(IRecordValidationService.class).to(AvroSchemaValidationService.class);
break;
case "clientlogging":
bind(IRecordValidationService.class).to(ClientLoggingValidationService.class);
break;
case "servicelogs":
bind(IRecordValidationService.class).to(ServiceLoggingValidationService.class);
break;
default:
throw new UnsupportedOperationException(String.format("Encountered an unsupported ValidationType of '%s'.", valType[i]));
}
} } }
SO the issue is if I am getting validation type as AVRO, JSON then it will bind IRecordValidationService to respective JsonValidationService/AvroSchemaValidationService class. I need to create multiple instance for that but it supports only once instance at a time.
Below is the RecordValidationHelper.java class
public class RecordValidationHelper extends AbstractModule {
private final IRecordValidationService recordValidationService;
#Inject
public RecordValidationHelper(IRecordValidationService recordValidationService) {
this.recordValidationService = recordValidationService;
}
public List processRecords(List requestRecords) {
List records = new ArrayList<>();
for (RequestRecord record : requestRecords) {
try {
Record domainRecord = new Record();
domainRecord.setKey(record.getRecordId());
domainRecord.setValue(new String(Base64.getDecoder().decode(record.getData())));
// Use the injected logic to validate the record.
((IRecordValidationService)
recordValidationService).validate(domainRecord);}
catch (ValidationException ex) {}}}
return records;}
Anyone having any idea about how it should be implemented to get multiple instance suitable for this.
Use #Named bindings
In your DependencyModule, bind using names:
bind(IRecordValidationService.class)
.annotatedWith(Names.named("json"))
.to(JsonValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("avro"))
.to(AvroSchemaValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("clientlogging"))
.to(ClientLoggingValidationService.class);
bind(IRecordValidationService.class)
.annotatedWith(Names.named("servicelogs"))
.to(ServiceLoggingValidationService.class);
Then in your injectee:
#Inject
public RecordValidationHelper(
#Named("json") IRecordValidationService jsonValidation,
#Named("avro") IRecordValidationService avroValidation,
#Named("clientlogging") IRecordValidationService clientLoggingValidation,
#Named("servicelogs") IRecordValidationService serviceLogsValidation,
) {
this.jsonValidation = jsonValidation;
this.avroValidation = avroValidation;
this.clientLoggingValidation = clientLoggingValidation;
this.serviceLogsValidation = serviceLogsValidation;
}
See Guice's BindingAnnotation wiki page for more info.

Implementing shared logic for multiple KafkaListeners in spring-kafka

My Spring Boot application contains several #KafkaListeners, and each listener performs the same steps before and after actually processing the payload: Validate the payload, check whether the event has been processed already, check whether it's a tombstone (null) message, decide whether processing should be retried in case of failure, emit metrics, etc.
These steps are currently implemented in a base class, but because the topics passed to #KafkaListener must be constant at runtime, the method annotated with #KafkaListener is defined in the subclass, and does nothing but pass its parameters to a method in the base class.
This works just fine, but I wonder if there's a more elegant solution. I assume my base class would have to create a listener container programmatically, but after a quick look at KafkaListenerAnnotationBeanPostProcessor, it seems to be quite involved.
Does anyone have any recommendadtions?
Having stumbled upon this question while looking to implement something similar, I first started with Artem Bilan's answer. However this did not work because annotations by default are not inherited in child classes unless they are themselves annotated with #Inherited. Despite this there may yet be a way to make an annotation approach work and I will update this answer if and when I get it to work. Thankfully though I have achieved the desired behavour using programtic registration of the Kafka listeners.
My code is something like the following:
Interface:
public interface GenericKafkaListener {
String METHOD = "handleMessage";
void handleMessage(ConsumerRecord<String, String> record);
}
Abstract Class:
public abstract class AbstractGenericKafkaListener implements GenericKafkaListener {
private final String kafkaTopic;
public AbstractGenericKafkaListener(final String kafkaTopic) {
this.kafakTopic = kafkaTopic;
}
#Override
public void handleMessage(final ConsumerRecord<String, String> record) {
//do common logic here
specificLogic(record);
}
protected abstract specificLogic(ConsumerRecord<String, String> record);
public String getKafkaTopic() {
return kafkaTopic;
}
}
We can then programtically register all beans of type AbstractGenericKafkaListener in a KafkaListenerConfigurer:
#Configuration
public class KafkaListenerConfigurataion implements KafkaListenerConfigurer {
#Autowired
private final List<AbstractGenericKafkaListener> listeners;
#Autowired
private final BeanFactory beanFactory;
#Autowired
private final MessageHandlerMethodFactory messageHandlerMethodFactory;
#Autowired
private final KafkaListenerContainerFactory kafkaListenerContainerFactory;
#Value("${your.kafka.consumer.group-id}")
private String consumerGroup;
#Value("${your.application.name}")
private String service;
#Override
public void configureKafkaListeners(
final KafkaListenerEndpointRegistrar registrar) {
final Method listenerMethod = lookUpMethod();
listeners.forEach(listener -> {
registerListenerEndpoint(listener, listenerMethod, registrar);
});
}
private void registerListenerEndpoint(final AbstractGenericKafkaListener listener,
final Method listenerMethod,
final KafkaListenerEndpointRegistrar registrar) {
log.info("Registering {} endpoint on topic {}", listener.getClass(),
listener.getKafkaTopic());
final MethodKafkaListenerEndpoint<String, String> endpoint =
createListenerEndpoint(listener, listenerMethod);
registrar.registerEndpoint(endpoint);
}
private MethodKafkaListenerEndpoint<String, String> createListenerEndpoint(
final AbstractGenericKafkaListener listener, final Method listenerMethod) {
final MethodKafkaListenerEndpoint<String, String> endpoint = new MethodKafkaListenerEndpoint<>();
endpoint.setBeanFactory(beanFactory);
endpoint.setBean(listener);
endpoint.setMethod(listenerMethod);
endpoint.setId(service + "-" + listener.getKafkaTopic());
endpoint.setGroup(consumerGroup);
endpoint.setTopics(listener.getKafkaTopic());
endpoint.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
return endpoint;
}
private Method lookUpMethod() {
return Arrays.stream(GenericKafkaListener.class.getMethods())
.filter(m -> m.getName().equals(GenericKafkaListener.METHOD))
.findAny()
.orElseThrow(() ->
new IllegalStateException("Could not find method " + GenericKafkaListener.METHOD));
}
}
How about this:
public abstract class BaseKafkaProcessingLogic {
#KafkaHandler
public void handle(Object payload) {
}
}
#KafkaListener(topics = "topic1")
public class Topic1Handler extends BaseKafkaProcessingLogic {
}
#KafkaListener(topics = "topic2")
public class Topic2Handler extends BaseKafkaProcessingLogic {
}
?
I needed the same functionality and came up with solution close to Artem Bilan answer. Yes, #KafkaHandler annotation is not inherited by the child classes but defined in interface it is. Here is the solution:
interface AbstractKafkaListener<T> {
default Class<T> getCommandType() {
TypeToken<T> type = new TypeToken<>(getClass()) {};
return (Class<T>) type.getRawType();
}
#KafkaHandler
default void handle(String message) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
T value = objectMapper.readValue(message, getCommandType());
handle(value);
}
void handle(T message);
}
The class should implement the handle method only:
#Component
#KafkaListener(topics = "my_topic")
public class KafkaListenerForMyCustomMessage implements AbstractKafkaListener<MyCustomMessage> {
#Override
public void handle(MyCustomMessage message) {
System.out.println(message);
}
}
The 2 implemented methods in the interface should be private/protected but because they are in interface this cannot be done. default methods are always public. Actually, all methods defined in interface are always public.
I use this solution to dynamically parse the message from kafka (received in String) to the custom class.
getCommandType method returns the class of the T generic param. TypeToken is from Google Guava package.

Is there an equivalent of Guice Providers in Simple Injector?

Is there an equivalent injecting Guice Providers in Simple Injector?
I need to inject a dependency into a constructor that will let me create as many instances of a dependency as needed. In guice it would look like this...
public class RealBillingService implements BillingService {
private final Provider<CreditCardProcessor> processorProvider;
private final Provider<TransactionLog> transactionLogProvider;
#Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
// each call to get creates a new instance in Guice as per scope configs
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
}
}
So perhaps a C# equivalent could be this inside SimpleInjector?
private readonly MailSender _mailSenderProvider;
public MailService(Func<MailSender> mailSenderProvider)
{
_mailSenderProvider = mailSenderProvider;
}
public void SendMail()
{
var mailSender = _mailSenderProvider.Invoke();
mailSender.SendSomeMail("Hello world");
}
I tried injecting Func in my real code and got this...
{"No registration for type BootStrapper could be found and an implicit registration could not be made. The constructor of type BootStrapper contains the parameter of type Func with name 'storeType' that is not registered. Please ensure Func is registered in the container, or change the constructor of BootStrapper."}
You need to explicitly configure factory delegates with Simple Injector (see here)
var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<MailSender>>(() => container.GetInstance<MailSender>());
You may want to consider separating concerns by adding a new abstraction. If you define an IMailSender you can then create a MailSenderProxy that is responsible for ensuring a new MailSender instance for each message.
public interface IMailSender {
void Send(string message);
}
public class MailSender : IMailSender {
public void Send(string message) {
}
}
public class MailSenderProxy : IMailSender {
private readonly Func<IMailSender> mailSenderFactory;
public MailSenderProxy(Func<IMailSender> mailSenderFactory) {
this.mailSenderFactory = mailSenderFactory;
}
public void Send(string message) {
this.mailSenderFactory().Send(message);
}
}
This abstracts away the requirement of creating a new MailSender for each mail (this is possibly not something the MailService should know about)
public class MailService {
private readonly IMailSender sender;
public MailService(MailSender sender) {
this.sender = sender;
}
public void SendMail() {
this.sender.Send("Message");
}
}
The Container configuration would look something like this
var container = new Container();
container.Register<MailSender>();
container.RegisterSingle<Func<IMailSender>>(() =>
container.GetInstance<MailSender>());
container.Register<IMailSender, MailSenderProxy>();
container.Verify();
I found the following example in the SimpleInjector docs
http://simpleinjector.readthedocs.org/en/latest/howto.html#register-factory-delegates
public static void AllowResolvingFuncFactories(this ContainerOptions options)
{
options.Container.ResolveUnregisteredType += (s, e) =>
{
var type = e.UnregisteredServiceType;
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Func<>))
{
return;
}
Type serviceType = type.GetGenericArguments().First();
InstanceProducer registration = options.Container.GetRegistration(serviceType, true);
Type funcType = typeof(Func<>).MakeGenericType(serviceType);
var factoryDelegate = Expression.Lambda(funcType,
registration.BuildExpression()).Compile();
e.Register(Expression.Constant(factoryDelegate));
};
}
Then on my container I call this...
// Allow types of Func<T> to be resolved
container.Options.AllowResolvingFuncFactories();
// 3. Optionally verify the container's configuration.
container.Verify();
Now I can inject Func< MyClass > and when I invoke the Func it returns as many instances as I want of that type.
All thanks to C# reified types and Simpleinjector's awesome api!

Categories

Resources