I have an application. Each user corresponds to the entity "Client". During the session, the user works with his entity.
I have JAX-RS + EJB application. I want this entity to be visible and used in all services, as a singleton. I want to achieve it using CDI.
First, the user login to the application. After login, I want to get its entity from the base and assign it to a singleton, but I didn't succeed. I tried the #Singleton annotations (javax.inject), #SessionScoped and #ApplicationScoped.
How can I do it?
//Entity
#Entity
#SessionScope //or #Singlton/#ApplicationScope
class Client { fields }
//login service
#Inject
Client client;
//After login I want to assign an entity from db[cleintEntity]
//to entity which is available everywhere[client]
client = clientEntity;
I want to do this:
//some ejb
#Inject
Client client;
//use entity
I don't want to transmit a link to the instance throughout the application, but I want it to be available everywhere using CDI.
Or do I need to create a separate ClientDAO, which will be my singleton?
Based on your comment, you must use the #SessionScope. The #Singleton and #ApplicationScope could be used if you wanted to have a single instance for all your users.
To solve your problem:
You want to instantiate the Client when user logs in. So when you're in the login service, this object is not instantiated yet, so you can't #Inject it into your login service and you should remember to remove the #Inject annotation.
You need to use the #Produces annotation. This annotation is used when you want to have control on the way your class is getting instantiated. When CDI container wants to find an implementation of the Client class, if it finds a method that returns Client and has #Produces annotation, it calls that method instead of just instantiating the Client itself. You should do your login business, then create an instance of Client and store it in your login service as a member variable. Then add a method in this class which returns that client object and annotate the method with #Produces. The final structure of your login service would be something like this:
#SessionScope
public class LoginService {
private Client client;
public void login(String username, String password) {
// implement login business
// if login is successful
client = clientEntity;
}
#Produces
#SessionScope
public Client clientProducer() {
return this.client;
}
}
You can also put the #Produces annotation on top of a field. In such cases, the CDI container will use the value stored on that field instead of calling a method.
#SessionScope
public class LoginService {
#Produces
#SessionScope
private Client client;
public void login(String username, String password) {
// implement login business
// if login is successful
client = clientEntity;
}
}
Of course this should be considered as a sort of pseudocode. I don't know about all the details of your business. Maybe the way you're implementing the logic is completely wrong ;). But to solve this specific problem, the #Produces should work.
Related
I've created a OAuth2 Resource Server that accepts and validates JWT tokens and extracts user information from the claims in order to determine user information such as username and authorities. I've largely done this using spring-security-oauth2-autoconfigure library.
After a user is authenticated, I'd like to call custom code that puts a message on a Kafka stream to indicate that a user has logged in. Where is the most appropriate place to do this?
I could do this in OAuth2AuthenticationManager.authenticate, but I'd have to extend that class and override that method, and then wire it in. It seems like Spring should have something already in place to handle this.
OAuth2AuthenticationProcessingFilter, which calls the authenticate method mentioned in the question, has a member called eventPublisher. Its methods include publishAuthenticationSuccess, which is called following a successful authentication.
To tie custom code in to this, create an event listener that gets picked up as a bean by Spring. Something like this:
#Component
public class MyAuthenticationEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
private static final Logger logger = LoggerFactory.getLogger(MyAuthenticationEventListener.class);
#Override
public void onApplicationEvent(AuthenticationSuccessEvent authenticationSuccessEvent) {
logger.info("User logged in: " + authenticationSuccessEvent.getAuthentication().getName());
}
}
I'm pretty new to the concept of patterns. I am practising my dependency injection skills as well as using DAO principles. The code I have written works but I feel that it can be written in a more elegant fashion. I've tried restructuring it a pattern I saw but that complicated things so not sure if I implemented it correctly. As a general rule when a web application communicates with a database and throws out result, how should one structure their project?
I've heard of the MVC principle but that doesn't necessarily add database to the mix.
This is what I have so far:
A class containing a controller in a Controller package:
#RestController
public class ResponseController {
#Autowired
MongoBase dbConnection;
#RequestMapping(value = "/jsonresult", method = RequestMethod.GET)
#ResponseBody
public String jsonresult(#RequestParam(value = "id", required = true) String id){
return dbConnection.documentToJSON(id, Constants.database,Constants.collection);
}
#RequestMapping(value = "/alljsonresult", method = RequestMethod.GET)
#ResponseBody
public String alljsonresult(){
return dbConnection.allDocumentToJSON(Constants.database,Constants.collection);
}}
A class containing CRUD methods to the database in a Database package:
#Component
public class MongoBase {
#Autowired
MongoClient mongoClient;
public MongoBase() {
try {
mongoClient = new MongoClient("localhost", 27017);
} catch (Exception e) {
e.printStackTrace();
}
}
public void printAllCollection(String databaseName, String collectionName) {
...
}
So is there a better way/more efficient way of writing thi? Also I feel I haven't fully implemented DI in the Monogbase class since it contains the new keyword..
If you are using springboot, then you don't need this old style
also don't need to create mongoClient bean your self, spring boot help you in it
You just need to add following properties in application.properties file
#mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1
Also declares a spring-boot-starter-data-mongodb in your pom or gradle
it's a cool and super awesome dependency for accessing Data with MongoDB
you can read about it from here[https://spring.io/guides/gs/accessing-data-mongodb/]
suppose you have a domain
#Document(collection = "domain")
public class User {
#Id
private long id;
#Indexed(unique = true)
private String domain;
private boolean displayAds;
//getters and setters
}
Now if we need to perform curd operation on this domain, extends MongoRepository, you have CRUD function automatically. Spring data come with many magic findBy queries, review the official Spring data MongoDB – Query methods for detail.
public interface UserRepository extends MongoRepository<User, Long> {
Domain findFirstByDomain(String domain);
Domain findByDomainAndDisplayAds(String domain, boolean displayAds);
//Supports native JSON query string
#Query("{domain:'?0'}")
Domain findCustomByDomain(String domain);
#Query("{domain: { $regex: ?0 } })")
List<Domain> findCustomByRegExDomain(String domain);
}
UserRepository extends the MongoRepository interface and plugs in the type of values and id it works with: User and Long. Out-of-the-box, this interface comes with many operations, including standard CRUD operations (create-read-update-delete).
now you can easly use it in your controller
#RestController
public class ResponseController {
#Autowired
UserRepository userRepository;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
User create(#RequestBody #Valid User user) {
return userRepository.create(user);
}
}
also you can do with it lot of things. you just need to go throw with it doc.
Also you you can use mongoTemplate for execute the query
#Autowired
MongoTemplate mongoTemplate;
When I build web applications I typically define the full chain as follows:
Client Side:
View - This is the V in MVC where you control visuals & user action derived workflow.
Controller - This is the C in MVC where workflow is managed. Most Client processing will go here and multiple Client calls can be made to get/send data or perform lookups.
Client - This is where you make a call to a REST web service and parse/deserialize the results/handle exceptions.
Server Side:
RestController (Sometimes Called Resource) - This is your REST API endpoint. Here you extract & validate a request.
Service - This is where most of your server logic will go. Sometimes you might have to make multiple data access calls or call other service functions.
DataAccessObject (Sometimes Called Provider) - This is your database interaction to pull data from your database into a model. CRUD operations (Create Read Update Delete)
Example Scenario:
Lets say we want to submit data & permissions for a given user
UserView.jsp - User types in user & permission data and hits submit.
UserController.java - validates User & permission data, does any necessary lookups, then calls UserClient.
UserClient.java - Builds the REST request and calls the /user/create REST endpoint.
UserRestController.java - Unpackages/Validates the request, then calls UserManagementService
UserManagementService.java - Server Logic happens here! Lets say I have two tables in my database. A User table and a Permissions table. I want to store the user information in the User table and the permission information in the permission table so I will call the UserDAO for the user data and the PermissionDAO for the permission data.
UserDAO & PermissionDAO - Saves The passed models to their respective tables.
Return to Service, Return to RestController, Return to Client (Parse Response), Return to Controller (Move the Workflow forward with a redirect or a success message).
Conclusion:
This may seem like a lot of in-between steps but this design provides a ton of flexibility, especially if your building large, complex web services. Each component has a specific purpose, follows an easy naming convention, and splits complex logic into smaller, simpler steps.
I'd like to recommend some improvements to your solution:
You're using Spring. You should not create any injected beans using new. Let Spring instantiate and manage those beans for you.
Use the #Repository annotation to mark your persistence class.
Make your repository class interface based.
Don't embed "Mongo" into the class name. You happen to be using Mongo as your persistence provider now, but you may change your mind later. Don't reveal implementation information in your class names - hide it.
The Controller is part of the UI. It uses repositories and/or services to fulfill use cases. It's perfectly correct to use Spring to inject the repository into the Controller.
I'd recommend that you use Spring Boot, an opinionated version of Spring. Have a look at their guides to learn how to use it properly.
I have created a utility jar file called email-util.jar. The main purpose of the utility is to send email via Amazon SES or Gmail SMTP. I have used factory pattern to decide the email type. (email-util.jar will be used in multiple projects)
EmailService.java (Interface)
public Status sendEmail(Email emailVO)
Implementation for Amazon SES
public class AmazonSimpleEmailServiceImpl implements EmailService {
public Status sendEmail(Email emailVO)
{
Amazon related stuff
}
Implementation for Gmail
public class GmailServiceImpl implements EmailService {
public Status sendEmail(Email emailVO)
{
Gmail related stuff
}
EmailVO will have ToAddress, FromAddress….. All email related info resides in EmailVO.
Using factory pattern I am able to create object of either AWS or Gmail and send email successfully.
Right now I have hardcoded all the configurations of Amazon SES and Gmail in their corresponding implementations. The configuration info of Amazon and Gmail is little different.
Gmail
Smpt host
Smtp port
…
Amazon SES
awsAccessKey
awsSecretKey
region
connectionTimeout
maxConnections
socketTimeout
maxErrorRetry ….
But I don’t want configuration info to be hardcoded. I introduced an additional parameter to sendEmail method.
public Status sendEmail(Email emailVO, EmailConfig config)
EmailConfig is a simple bean where I have the entire amazon and gmail related variables. Everything is working fine. But I have few concerns
Quesions
Is there a way we can separate Amazon SES configurations and Gmail related configurations.
One more issue is user doesn’t know which variables are mandatory and which variables are optional. I.e. if user opts for gmail then Region is optional. How to solve this problem
Any design pattern which addresses this issue
I tried creating a marker interface called EmailConfig and created two classes which implement EmailConfig.
AmazonSESConfig implements EmailConfig
amazonSES related variables.
GmailConfig implements EmailConfig
gmail related variables.
But it didn’t work out. Not able to store object of AmazonSES/Gmail in EmailConfig since it is a marker interface.
Is there a way we can separate Amazon SES configurations and Gmail
related configurations.
You can have two distinct classes that return configuration values but as these two providers don't rely on the same requirement, you should explicitly use this classes.
And having a common base class as you tried makes no sense :
public Status sendEmail(Email emailVO, EmailConfig config)
You should have one class for Amazon and another class for Gmail with each one a distinct method :
public Status sendEmail(Email emailVO, AmazonSESConfig config)
...
public Status sendEmail(Email emailVO, GmailConfig config)
One more issue is user doesn’t know which variables are mandatory and
which variables are optional. I.e. if user opts for gmail then Region
is optional. How to solve this problem
If you use a distinct configuration class for gmail and another one for amazon, you can easily check that all required fields were valued at runtime.
Each implementation could do its own check.
If you want to catch the problem at compile time, you could use a step builder to force the client to fill all required fields.
You could have something as :
AmazonSESConfig amazonConfig =
AmazonSESConfig.Builder().awsAccessKey(access).awsSecretKey(secret).region(region)...build();
where awsAccessKey() will return an instance of an interface that contains a awsSecretKey() method. The awsSecretKey() method will return an instance of an interface that contains a region() method. And so for...
If a mandatory field is not valued, the client could not call the build method as only the last one field to value will return an instance of an interface that provides the build() method.
Hide knowledge about particular EmailService implementation from user, incapsulate all configs in implementation classes and give user concrete implementation through factory.
class EmailServiceFactory {
public EmailService getService() {}
}
and you dont have to change this method signature
interface EmailService {
public Status sendEmail(Email email);
}
Consider an Struts 2 + Spring 4 project.
For each login the User object is put in session. As a very simple action it will look
public class LoginProcess implements ServletRequestAware {
#Inject
private AuthenticationServices authenticationServices;
public String execute() {
//The login method makes a new User and fills its setters
User newUser = authenticationServices.login(....);
getServletRequest().getSession().setAttribute("USER_SESSION", user);
}
}
As we manually make a new User object so it is not managed spring bean, and we can't use spring features in User class: #Inject , #Value ,...
I tried to change user as:
#Named
#Scope(value="session")
public class User { ...
#Inject
private AccountServices accountServices;
}
and inject the User in instead of calling new User, but I get the error:
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
Well although it describes the error, but I can not find how can I fix it, and I am not sure if this is the correct way at all. It seems that I can only use spring session scope been when I am using spring mvc
Any comments ?!
Why I need this ?! (Simplified situation)
The user object has a getAccounts() methods which get all user accounts. Getting user accounts is an expensive operation, and it is possible that a user does not require its accounts during its login.
So, instead of get user accounts as soon as user logs in, we let the get method get user accounts if it does not have it:
public class User() {
private Accounts accounts;
#Inject
private AccountServices accountServices;
Accounts getAccounts() {
if (accounts == null) {
accounts = accountServices.getUserAccountsFromDB(...)
}
return accounts;
}
Don't create a new instance of User by yourself, instead get a bean from Spring context.
For example you can achieve it by implementing ApplicationContextAware interface and calling one of getBean methods.
User user = applicationContext.getBean(User.class);
// populate user and put it into session
In that way it is a Spring managed bean an all required properties should be injected.
BUT consider changing your User to a simple POJO and moving all business logic (such as fetching users accounts) to some more appropriate place, in that way your model layer will be cleaner and easily testable.
I am currently developing a REST webservice using Jersey and Guice as a DI-container.
For handling the requests I am relying on a GuiceServletContextListener which is configured similar to the following:
bind(UserResource.class);
//Some other root-level resources for REST
serve("/rest/*").with(GuiceContainer.class);
As I have to deal with hierarchical data (One user should have their own items and it should be possible to access items of other users in the form of /rest/user/[Username]/item). For this, I am using Jersey's support for subresources.
For example, my UserResource contains the following method (ItemResource.Factory is a factory interface whose implementation is automatically provided by Guice's FactoryModuleBuilder):
#Inject
private ItemResource.Factory _itemResourceFactory;
#Path("/{username}/item")
public ItemResource getItems(#PathParam("username") String username) {
User user = //...
return this._itemResourceFactory.create(user);
}
ItemResource (the subresource) then again is implemented as a normal Jersey class based on the User passed in in the constructor.
However, my subresources need access to #Context fields (like UriInfo or HttpServletRequest), too. According to the Jersey documentation, #Context fields are not injected for subresources as their lifecycle is unknown (and the documentation seems to be true).
This is very unfortuante for me: I really need access to those values.
As a workaround, I am currently passing those values as additional constructor parameters to my subresources which I perceive as everything but comfortable.
Is there any possibility to tell Jersey to inject them anyway?
Nevertheless, even better would be if Guice itself was able to inject the #Context fields.
Simply swapping the #Context for #Inject, however, doesn't work as Guice has no registrations for types like UriInfo or HttpServletRequest.
Can I somehow create those mappings?
The problem is, that I don't know how to access the request specific values inside a Guice Provider implementation.
Are there maybe any helper methods to get access to the current instances of those Jersey objects so I can write the necessary providers?
Or are those implementations maybe already available somewhere out there?
I am not sure I understood your problem. Can you post the code related to "passing those values as additional constructor parameters"?
You can inject the Context like this:
#Path("/{username}/item")
public ItemResource getItems(#Context HttpServletRequest request, #PathParam("username") String username) {
Maybe you could inject fields programmatically? Guice provides this through the Injector class:
Injector injector = Guice.createInjector(...);
injector.injectMembers(someObjectToInject);
See http://code.google.com/p/google-guice/wiki/Injections for more information on this topic.