I want to develop a utility class, that can be used in a static manner (static methods), for an enterprise Java system (JSP, Servlets, EJBs). It'd contain some methods that is capable to access the HttpSession object of the user and retrieves some useful info that is already stored as attributes (such as the current user id).
Some of you may wonder why do I need such thing, while I can simply passing the HttpSession object to anywhere. Actually, I am working on a legacy Java EE 5.0 system and some of the utility classes (not Servlets, JSPs, nor EJBs) have no access to the HttpSession object.
Is it possible to implement such utility class? Some constraints I/you should consider here:
The servlets/JSPs are hosted on machines that are different from what host EJBs.
The system is running on Weblogic 10.3.0.
On weblogic, there are many servers (that host servlets/JSPs) and they are under the same cluster. The same thing is with EJBs servers.
If I declare some static Collection inside the utility class, is it going to work? or maybe there will be more than one copy of it because of the multiple class loaders and multiple JVMs?
Maybe I should use a shared file or shared database to implement it? How even could I track which user invokes the utility class? Maybe tracking the thread? or maybe something related to the transaction?
Make use of ThreadLocal. You should only not store the HttpSession directly in there. The service layer should not have any dependency on javax.servlet API. Instead, extract the desired information from the HttpSession directly and store it there.
E.g. when you want to expose User attribute of the HttpSession as a thread local variable:
public class SomeContext {
private static ThreadLocal<SomeContext> instance = new ThreadLocal<SomeContext>();
private User user;
private SomeContext(User user) {
this.user = user;
}
public static SomeContext getCurrentInstance() {
return instance.get();
}
public static SomeContext newInstance(User user) {
SomeContext someContext = new SomeContext(user);
instance.set(someContext);
return someContext;
}
public void release() {
instance.remove();
}
public User getUser() {
return user;
}
}
and this in doFilter() of a servlet filter:
User user = (User) request.getSession().getAttribute("user");
SomeContext someContext = SomeContext.newInstance(user);
try {
chain.doFilter(request, response);
} finally {
// It's very important to do this in finally!
// Threads are namely pooled by the container.
someContext.release();
}
in any code which is running in the very same thread after the particular filter, including EJBs, you can get the User as follows:
User user = SomeContext.getCurrentInstance().getUser();
// ...
The HttpSession is local to a Thread.
Do you really need an HttpSession or could you just do what you want with a static ThreadLocal attribute?
See: http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html
btw, Apache Shiro uses this class to store some "Session" information.
Related
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.
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.
We're developing a SaaS solution for several consumers. This solution is based on Spring, Wicket and Hibernate. Our
database contains data from several customers. We've decided to model the database as follows:
public
Shared data between all customers, for example user accounts as we do not know which customer a user belongs to
customer_1
customer_2
...
To work with this setup we use a multi-tenancy setup with the following TenantIdentifierResolver:
public class TenantProviderImpl implements CurrentTenantIdentifierResolver {
private static final ThreadLocal<String> tenant = new ThreadLocal<>();
public static void setTenant(String tenant){
TenantProviderImpl.tenant.set(tenant);
}
#Override
public String resolveCurrentTenantIdentifier() {
return tenant.get();
}
#Override
public boolean validateExistingCurrentSessions() {
return false;
}
/**
* Initialize a tenant by storing the tenant identifier in both the HTTP session and the ThreadLocal
*
* #param String tenant Tenant identifier to be stored
*/
public static void initTenant(String tenant) {
HttpServletRequest req = ((ServletWebRequest) RequestCycle.get().getRequest()).getContainerRequest();
req.getSession().setAttribute("tenant", tenant);
TenantProviderImpl.setTenant(tenant);
}
}
The initTenant method is called by a servlet filter for every request. This filter is processed before a connection
is opened to the database.
We've also implemented a AbstractDataSourceBasedMultiTenantConnectionProviderImpl which is set as our
hibernate.multi_tenant_connection_provider. It issues a SET search_path query before every request. This works like charm for requests passing through the servlet filter described above.
And now for our real problem: We've got some entrypoints into our application which do not pass the servlet filter,
for instance some SOAP-endpoints. There are also timed jobs that are executed which do not pass the servlet filter.
This proves to be a problem.
The Job/Endpoint receives a value somehow which can be used to identify which customer should be associated with the
Job/Endpoint-request. This unique value is often mapped in our public database schema. Thus, we need to query the
database before we know which customer is associated. Spring therefore initializes a complete Hibernate session. This
session has our default tenant ID and is not mapped to a specific customer. However, after we've resolved the unique
value to a customer we want the session to change the tenant identifier. This seems to not be supported though, there
is no such thing as a HibernateSession.setTenantIdentifier(String) whereas there is a
SharedSessionContract.getTenantIdentifier().
We thought we had a solution in the following method:
org.hibernate.SessionFactory sessionFactory = getSessionFactory();
org.hibernate.Session session = null;
try
{
session = getSession();
if (session != null)
{
if(session.isDirty())
{
session.flush();
}
if(!session.getTransaction().wasCommitted())
{
session.getTransaction().commit();
}
session.disconnect();
session.close();
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
}
catch (HibernateException e)
{
// NO-OP, apparently there was no session yet
}
TenantProviderImpl.setTenant(tenant);
session = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
return session;
This method however does not seem to work in the context of a Job/Endpoint and leads to HibernateException such as
"Session is closed!" or "Transaction not succesfully started".
We're a bit lost as we've been trying to find a solution for quite a while now. Is there something we've misunderstood?
Something we've misinterpreted? How can we fix the problem above?
Recap: HibernateSession-s not created by a user request but rather by a timed job or such do not pass our servlet
filter and thus have no associated tenant identifier before the Hibernate session is started. They have unique values
which we can translate to a tenant identifier by querying the database though. How can we tell an existing Hibernate
session to alter it's tenant identifier and thus issue a new SET search_path statement?
We've never found a true solution for this problem, but chimmi linked to a Jira-ticket were others have requested such a feature: https://hibernate.atlassian.net/browse/HHH-9766
As per this ticket, the behavior we want is currently unsupported. We've found a workaround though, as the number of times we actually want to use this feature is limited it is feasible for us to run these operations in separate threads using the default java concurrency implementation.
By running the operation in a separate thread, a new session is created (as the session is threadbound). It is very important for us to set the tenant to a variable shared across threads. For this we have a static variable in the CurrentTenantIdentifierResolver.
For running an operation in a separate thread, we implement a Callable. These callables are implemented as Spring-beans with scope prototype so a new instance is created for each time it is requested (autowired). We've implemented our own abstract implementation of a Callable which finalizes the call()-method defined by the Callable interface, and the implementation starts a new HibernateSession. The code looks somewhat like this:
public abstract class OurCallable<TYPE> implements Callable<TYPE> {
private final String tenantId;
#Autowired
private SessionFactory sessionFactory;
// More fields here
public OurCallable(String tenantId) {
this.tenantId = tenantId;
}
#Override
public final TYPE call() throws Exception {
TenantProvider.setTenant(tenantId);
startSession();
try {
return callInternal();
} finally {
stopSession();
}
}
protected abstract TYPE callInternal();
private void startSession(){
// Implementation skipped for clarity
}
private void stopSession(){
// Implementation skipped for clarity
}
}
Another workaround I've found thanks to #bas-dalenoord comment regarding OpenSessionInViewFilter/OpenEntityManagerInViewInterceptor which led me to this direction, is to disable this interceptor.
This can be achieved easily by setting spring.jpa.open-in-view=false either in the application.properties or environment-variable.
OpenEntityManagerInViewInterceptor binds a JPA EntityManager to the thread for the entire processing of the request and in my case it's redundant.
Another workaround is to break the request that needs to make DB calls on behalf of 2 different tenants into 2 separate requests.
First the client ask for his associated tenant in the system, and then creates a new request with the given tenant as a parameter. IMO, until (and if) the feature will be supported, it's a relatively clean alternative.
In a Play! controller, I can create an interceptor method that will process every request before it arrives to the appropriate action.
public class Admin extends Application {
#Before
static void checkAuthentification() {
if(session.get("user") == null) login();
// otherwise,
User loggedOnUser = User.find("byUsername", session.get("user"));
}
public static void index() {
// any way to access loggedOnUser ?
List<User> users = User.findAll();
render(users);
}
…
}
Is there a way to set a value in the interceptor and access it in the action? Sort of like request.setAttribute() in servlets?
You can use renderArgs parameter from Controller (see here) or you can store the value in the Cache (we can assume that as the value was added miliseconds ago, your value will be available while in the same request).
Interceptors and actions share the same request context (request, response, session, etc). As stated above, you may elect to use renderArgs, but keep in mind that these values will be available in your views, which may not be what you want. If you want to keep the state between your interceptor and actions, just use the request.args hash instead.
I'm building an UI client that uses a service API that behind the scene uses Web services. One of the API services looks like this:
interface UserService {
List<User> findUsers(User loggedInUser, UserSearchParameters searchParameters, PagingParameters pagingParameters) throws AuthenticationFault, InvalidIndexFault;
void removeUser(User loggedInUser, User userToRemove) throws AutheticationFault;
void addUser(User loggedInUser, User newUser) throws AuthenticationFault;
}
The loggedInUser is the user on who's behalf the method is called. AuthenticationFault is a checked exception. There's like 20 of these service interfaces. What I would like to do is implement a facade that hides the loggedInUser parameters and AuthenticationFault exceptions. The facade implementation would call these methods with the user that is currently logged in the client.
I would also like to do some cleaning with the other checked exceptions too. As you can see there is a InvalidIndexFault exception that is thrown when client tries to retrieve page -1 but that is a programmer error and I don't want to have it as a checked exception.
Currently what I've done is always rethrow a RuntimeException for exceptions that I don't like, but if I later change my mind it's a lot of work changing that later. This also feels like code duplication. Other programmers have just swallowed exceptions and logged them which is totally horrible. Most of the time if there is an exception I want to bubble it up to error handler in the ui that displays an error.
There's been a few solutions that have come to my mind:
Java dynamic proxy
Code generation
I haven't gotten around to try out those solutions and figured I might as well ask here first. How do you suggest I would implement this? The environment is Java 6 and build tool is Maven 3 if that helps.
PS. If you answer this, please say more than "pick number 2" :) Any tips and other implementation details are welcome.
As a clarification retrieving the currently logged in user is not an issue so you don't have to help me with it. I currently hide it behind an interface and use IoC to inject it around. Behind the scenes it uses ThreadLocals
I guess this would be the perfect use case for
Java Dynamic Proxys
Thread locals
To elucidate:
First, create your Facade Interface :
interface UserServiceFacede {
List findUsers(UserSearchParameters searchParameters, PagingParameters pagingParameters) throws AuthenticationFault, InvalidIndexFault;
void removeUser(User userToRemove) throws AutheticationFault;
void addUser(User newUser) throws AuthenticationFault;
}
Next you implement your InvocationHandler :
public class UserHandler implements InvocationHandler{
private final UserService service;
public UserHandler(UserService service) {
this.service = service;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
....
// Based on the method argument, call the appropriate function on the actual service
// object
....
}
}
You then create the Proxy object like so :
UserServiceFacade uProxy = (UserServiceFacade)Proxy.newProxyInstance(UserHandler.class.getClassLoader(),
new Class[] { UserServiceFacade.class},
new UserHandler(userService));
The first argument is the classloader, the second is the list of interfaces the Proxy must confirm to and the third is the handler object
Now the question is how do you get a handle onto your loggedinUser. This is where ThreadLocal comes in.
Create a ThreadLocal static variable that holds the loggedin user. Then set the current user into the ThreadLocal before invoking the proxy
private static final ThreadLocal loggedinUser = ...;
...
...
loggedinUser.set(currentUser);
// Create a user Proxy object as mentioned above..
uProxy.findUser(searchParams, ..);
...
Retrieve the User from the ThreadLocal inside the invoke function of the handler. Now inside the handler, you have access to both the loggedinUser (using loggedinUser.get()) as well as the user service object (You have passed in the service object into your handler's constructor)
As far as how you handle exceptions are concerned, WHat I would do is generally keep throwing a subclass of RuntimeExceptions. Then catch these at the periphery layer of your app. By periphery layer I mean, entry point into your app/library. If you were developing a webbApp this would be your Servlet.