REST API Autowire remote or local implementation of a service automatically - java

I have a REST API built on Spring Boot consisting of 2 seperate web services. I don't know if those two web services will be hosted on the same machine so I want to make remote and local implementation for all services. Example below:
Local service implementation:
public class LocalExampleService implements ExampleService{
public Item getItem(long id){
//Get item using implementation from another local project
}
}
Remote service implementation:
public class RemoteExampleService implements ExampleService{
#Value("${serviceURL}")
private String serviceURL;
public Item getItem(long id){
//Get item calling remote service
}
}
Controller:
public class MyController{
#Autowired
private ExampleService exampleService;
}
Web service has many services with local and remote implementation and I want to let Spring know which type of implementation it should choose for all services.
I've been thinking about putting url in properties file and during intialization the app would check whether properties contain url and then autowire service approprietly. But then I would have to write logic for every service autowiring.
What's the best option to autowire correct service implementation automatically?

You can use Spring profiles to control which version of implementation should be used via spring properties.
In spring properties add below entry
spring.profiles.active=NAME_OF_ACTIVE_PROFILE
Every service implementation needs profile annotation. That's how your services implementation should look like:
#Component
#Profile("local")
public class LocalExampleService implements ExampleService{}
#Component
#Profile("remote")
public class RemoteExampleService implements ExampleService{}
If your project needs to use local implementation of a service then in properties instead of NAME_OF_ACTIVE_PROFILE insert local otherwise remote.
For fully automatic auto-wiring you need to add method running at the startup that checks whether local implementation class exists and then set profile properly. To do this you need to modify code in spring boot main method:
public static void main(String[] args){
String profile = checkCurrentProfile(); //Method that decides which profile should be used
System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, profile);
SpringApplication.run(MyApplication.class, args);
}
If you choose this approach then you don't need previous entry in properties file.

My attempt to implement something like this https://github.com/StanislavLapitsky/SpringSOAProxy
The idea is to check if a spring bean cannot be found locally then automatically create a Proxy which uses RestTemplate internally to call the same service remotely.
You need to define contract - services interfaces plus DTO and define URL resolver to specify which URL should be used for each service.

Related

Elasticsearch spring implementation error

I have a interface which has function used to query ElasticSearch. It extends the ElasticsearchRepository for doing it.
public interface HouseholdRepository extends ElasticsearchRepository<SearchHouseholdESBean, String> {
List<SearchHouseholdESBean> findByPhoneNumberAndActiveInd(String phoneNumber, String activeInd);
The problem is how do i call this in my business class where i need to get the results. This being an interface , i can't create an object of this to call the methods. Also, the implementation is implicit to the jars in the Elastic Search.
To use elastichsearch repositories you must follow the next steps:
1. add annotation #EnableElasticsearchRepositories on your SpringBootApplication
#SpringBootApplication
#EnableElasticsearchRepositories
public class Application {
//...
2. Make sure that the interface HouseholdRepository is scanned by the spring-boot application. You can simple achieve this by placing it under the same root package as your Application class.
3.You will just #Autowire HouseholdRepository in your service without further changes. The idea behind spring boot data is that the code will be generated based on that interface.
OBS: make sure that you have the proper project dependencies. You should depend on spring-boot-starter-data-elasticsearch to avoid extra configuration effort.

How to dynamically lookup an EJB at runtime

I have this scenario where i have my EJB3 beans in a jar file, deployed successfully to Jboss EAP-6.4.
Then I have another web project that looks up these EJB's inside a REST POJO class. I can currently access the EJB's from inside the web project using #Inject and #EJB, but my use case is one that i don't know which beans i need to load until runtime and the list is not static, so i might need to lookup 10 EJB's or none for a particular request etc.
I know I can possibly use
InitialContext.lookup('ejb:/.....')
to retrieve my EJB beans from inside the web project, but is there a way that i can retrieve them without that round trip(i believe), or maybe what am just looking for is a more elegant way to do EJB look-up at runtime just like the statically typed #EJB and #Inject versions.
Any suggestions are greatly appreciated.
EDIT
In my REST POJO classes i don't want to hard code any #Inject or #EJB annotations, rather i want that when a request comes in i look-up(for lack of better word) the EJB's that will handle the request, so all the decision is made at runtime really, as shown below
#Path("/path")
public class TestService {
#GET("/{id}")
public String loadGetPath(#Param id int id){
//at this point i want to dynamically resolve the EJB based on
//the value of id
}
}
Whoopdicity blog: Developing a dynamic JEE service client with CDI seems to have what you are looking for. At the end it claims you can do:
public class MyServiceConsumer {
#Inject #ServiceClient
private MyBusinessService service;
...
}
Instead of
public class MyServiceConsumer {
#EJB(lookup="...")
private MyBusinessService service;
...
}

Dynamic OSGi service replacement as development aid

We are using Apache Felix annotations to handle all the OSGi stuff in our application. I have a provider class that talks to a server. I have a consumer class that does stuff with data from the server. What I want is to create another provider instance (new class implementing interface) that is for debug purposes only that returns canned responses to requests by the consumer. Ideally I would like the consumer to be unaware of this handoff. It's provider service reference would simply be replaced.
The use case: When the developer is running on a machine without access to the actual server, he presses a button in our running app to switch from the real provider instance to our debug provider instance.
What is the recommended way to accomplish this?
Example code:
public interface IProvider{
public String getDataFromServer();
}
#Component
#Service(value=IProvider.class)
public class RealProvider implements IProvider{
#Override
public String getDataFromServer(){
...
}
}
#Component
#Service(value=IProvider.class)
public class DebugProvider implements IProvider{
#Override
public String getDataFromServer(){
return "Hello World";
}
}
#Component
public class Consumer{
private #Reference IProvider provider;
public void doSomething(){
provider.getDataFromServer();
}
}
If the two providers are in separate bundles, you can stop Bundle A and start Bundle B to switch between implementations of the service.
If the two providers are in the same bundle, you'd need to either drop down to the OSGI API and register/unregister the services manually, or create a proxy version of IProvider that has a debugMode flag and delegates to the specific implementation.

Dependency injeection at runtime in Java

I have read through the dependency capabilities through Java CDI but could not figure out so far how to inject a class by runtime. Let me explain the scenario first.
Lets assume I have a JSF web app with a central Email service.
I am defining an interface
public interface EmailService {
public String sendEmail(Email email);
}
Then next I have a concrete implementation of the EmailService using Smtp:
public class SmtpEmailServiceImpl implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation using Smtp
}
}
Now in my web app I am having a JSF backing bean that should get the EmailService injected in order to sende the e-mail
public class JSFBackingBean {
// This is the EmailService to be injected
private EmailService emailService;
public String sendEmail(){
emailService.sendEmail(new Email());
}
}
Now lets assume the Smtp-Server is down for maintenance. In this scenario I would like to spool all the Emails in a Database and process them later when the Smtp server is up and running. In this case I would like to have a second implementation of the EmailService:
public class DatabaseEmailService implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation writing the email to a database
}
}
Now I understand from CDI that I can use Annotations to inject the proper service implementation but that would mean that I would have to re-build and deploy my classes in case I would like to change the appropriate service. Is there a better solution where I can use e.g. a configuration file in order to change the injection at runtime of the application?
Thanks for your answers in advance
Pred
In cases like this, you could write a custom Producer and Qualifier. Instead of injecting the EmailService, inject for example a "#Failsafe EmailService".
Then write a producer
#Produces
#Failsafe
private EmailService failsafeEmailService() {
// here you can check if the Mail Server is available and then decide
// to return the "real" Service or the DB-Queue.
}
Instead of creating/looking up the Services inside the method body, you could also let CDI inject both alternatives (directly or via Instance<>) and then decide which one to propagate.
#Produces
#Failsafe
private EmailService failsafeEmailService(MailServiceBean bean, DBQueue queue) {
return (check_if_mail_server_is_running) ? bean : queue
}
(of course both DBQueue and Bean have to implement EmailService).
Well, I doubt you want to make it so that every client to this email service is aware that the mail service needs to be switched out, even if you used annotations and instance selectors, e.g.:
#Inject
private Instance<EmailService> emailServiceInstance;
// few lines down
emailServiceInstance.select(new SmtpLiteral()).get();
Which is how you would do it in a CDI fashion. What I would recommend is that this logic belongs in your EmailService and itself injects a reference to some DB class that persist the message to the database until the SMTP server is back online.

Exclude/remove services from Dependency Indejection in JBoss

We currently have a project that consists of multiple applications as well as a base library.
Both, the applications as well as the base library contain stateless EJBs and each application might introduce an EJB that inherits from a base library EJBand thus implements the same interface.
A short example:
In the base library we have:
#Stateless
#Local( IUserService.class )
public UserServiceBean implements IUserService {
public void login(String user, String password) {...}
}
In the application we need to override login(...) and thus we have:
#Stateless
#Local( { ISpecificUserService.class, IUserService.class } )
public SpecificUserServiceBean extends UserServiceBean implements ISpecificUserService {
public void login(String user, String password) { ... } //override
}
If I now have another EJB in the application that needs to have a reference to SpecificUserServiceBean I'd do #EJB ISpecificUserService userService;.
However, if there is an EJB in the base library, it would contain #EJB IUserService userService; and here's the problem:
We need to get the specific service in the application be injected in the base library EJB. However, there are two EJBs registered for the same local interface, which means that the container might return the base EJB or the specific EJB.
You could say "Don't add the base library jar as a module in application.xml" but that's not possible right now, since it contains other EJBs that need to be deployed. We could move the EJBs to be overridden to a different jar but since almost every EJB might be overridden, depending on the application, we'd end up with a jar per EJB.
Thus, I'd like to exclude or remove the base EJB from the dependency injection container if there exists a specific override. Since I know that at deploy time, I could also use a configuration file to tell the container not to load a specific EJB class.
I might add a service that modifies the container afterwards but that would be my last resort.
Do you have any ideas on what we could do?
Thanks in advance.
Btw, we're working on JBoss 4.2.3 with EJB 3.0.
The problem is that you're wiring your app partially in the base lib which is bad since you can't override this wiring.
So the solution is to remove #Stateless #Local( IUserService.class ) from UserServiceBean in your base lib; the base lib just provides default implementations for the beans but it must not wire them.
In your apps, you need this code:
#Stateless
#Local( IUserService.class )
public AppUserServiceBean extends UserServiceBean {}
to create the wiring. Move all those beans into a special package which you can copy into each app so you get the default wiring for everything.

Categories