Get the current Play session() in Java - java

I Have this class:
package ds;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import play.mvc.Http;
public class MyRoutingDataSource extends AbstractRoutingDataSource {
#Override
protected String determineCurrentLookupKey() {
return Http.Context.current().session().get("currentDB");
}
}
But when I want to access into the Play session I have this error:
Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:34) ~[play_2.10-2.3.10.jar:2.3.10]
at play.mvc.Controller.session(Controller.java:72) ~[play_2.10-2.3.10.jar:2.3.10]
I also tried with HttpExecution.defaultContext() and his HttpExecutionContext but it cannot be cast to the Http.Context that is what I need.
I was thinking about get the request header but certainly I don't know how to handle it from my class and determine the session from the request

You can't access the Play Context in that tier cause is out of scope. In the documentation of the AbstractRoutingDatasource:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.html
The main description of the class says:
Abstract DataSource implementation that routes getConnection() calls
to one of various target DataSources based on a lookup key. The latter
is usually (but not necessarily) determined through some
thread-bound transaction context.
So this class is suggesting that a way to get information of the current context should be using a Thread-Bound Transaction Context.
Now, Is PlayFramework Thread Context Safe? Reading Play documentation:
https://www.playframework.com/documentation/2.3.x/ThreadPools#Java-thread-locals
Java code in Play uses a thread local to find out about contextual
information such as the current HTTP request. Scala code doesn’t need
to use thread locals because it can use implicit parameters to pass
context instead. Threads locals are used in Java so that Java code can
access contextual information without needing to pass context
parameters everywhere.
So, if you are using a Java implementation, you can use ThreadLocals as context channel between components. Be careful if you create your own thread pools because there's a warning in the same documentation:
The default objects wrap the default user thread pool. If you want to
do your own threading then you should use the HttpExecution class’s
helper methods to get an ExecutionContextExecutor object yourself.
But that won't be a problem if you are not using custom thread pool in your app.
Said that, what you have to do is:
Define a ThreadLocalContext for the object that you want to use as router.
Put in the context. (You can do it in the controller, in the security controller if you are using an authorization framework like Deadbolt or even implementing a new request filter.)
Reading in the AbstractRoutingDataSource the ThreadLocal context.
Important! Don't forget to clean the Thread-Local or you can face a memory Leak.
Step 1:
public class RequestContext {
private static final ThreadLocal<String> contextHolder =
new ThreadLocal<String>();
public static void setRoutingKey(String key) {
contextHolder.set(key);
}
public static String getRoutingKey() {
return (String) contextHolder.get();
}
public static void clearRoutingKey() {
contextHolder.remove();
}
}
Step 2:
//Demostrative code, not tested, not even compiled
public static void myController() {
RoutingContext.setRoutingKey(Play.Context.request());
return bla;
}
Step 3:
#Override
protected Object determineCurrentLookupKey() {
String datasource = RoutingContext.getRoutingKey();
RoutingContext.clearRoutingKey();
return datasource;
}
Regards!

Related

How to access object without passing it as parameter?

Is there a way to autowire an object that needs to be re-instantiated frequently?
I am using Netflix's DGS + spring boot framework, and basically storing the user authentication details in a custom context which is created for each request. I am trying to avoid adding context to the method signature because of the large amount of refactoring needed.
e.g.
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
// trying to avoid adding context as an extra param e.g. dataFetcherHelper(context)
dataFetcherHelper(); // this calls other helper methods from other classes
}
I was thinking of using the facade pattern but this would not be thread safe. Basically autowire the RequestContextHolder, and call setRequestContext each time a new context gets initialized.
#Component
#NoArgsConstructor
#Getter
#Setter
public class RequestContextHolder {
private RequestContext requestContext;
}
I'm not sure how your question:
Is there a way to autowire an object that needs to be re-instantiated frequently?
Is related to the use case that you've presented in the question...
From the question it looks like you can consider using ThreadLocals as a conceptual "substitution" to the global variable available all over the place in the request if you don't want to add parameters to the methods to propagate the context through the flow.
This will work only in "thread-per-request" model, it won't work for reactive systems and for the complicated cases where you maintain different thread pools and switch the threads while implementing the Business Logic on backend:
So to achieve "thread-safety" in your context holder that you have suggested you can use:
#Configuration
public class MyConfig {
#Bean
public ThreadLocal<MyCustomContext> ctxHolder() {
return new ThreadLocal<>();
}
}
Then, again, if you're working in thread-per-request model, you can:
#Component
public class DataFetcherInterceptor {
#Autowired
private ThreadLocal<MyCustomContext> ctxHolder;
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
ctxHolder.set(context);
dataFetcherHelper();
}
}
In the dataFetcherHelper or in general in any method that requires the access to the context you can:
public class SomeService {
#Autowired ThreadLocal<MyCustomContext> ctxHolder;
public void dataFetcherHelper() {
MyCustomContext ctx = ctxHolder.get();
}
Now, I see that dataFetcherHelper is just a method that you call from withing this "interceptor" class, in this case its an overkill, but I assume, you've intended that this is actually a method that belongs to another class, that might be an element in the call-chain of different classes. For these situations, this can be a working solution.

Accessing Neo4j from Async method

My web application uses Neo4j as a data storage, and it uses Spring Data Neo4j 4 framework.
As suggested in the tutorial, my neo4j session is bound to my HTTP session:
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
I have an endpoint which runs a time-consuming query, and sends the result offline. I'd like to move this method to an #Async thread, but obviously I can not access my neo4j session from that thread.
What is the best practise to access neo4j repositories outside of the HTTP session without changing the scope of the "main" session bean?
I'm not sure about best practice but can't you just create another session from the sessionFactory#openSession() method? And pass that new session to another instance of neo4jOperations (or #Override the existing bean if are not using it) thus avoiding using the proxyScoped Neo4jConfiguration#getSession() method.
like so:
// note below assumes you are extending Neo4jConfiguration
// ...
// passing in your own non proxyScoped session.
// #Override existing neo4jTemplate #Bean passing in your own session
#Bean
#Override
public Neo4jOperations neo4jTemplate() throws Exception {
return new Neo4jTemplate(getSessionFactory().openSession());
}
// or create another neo4jTemplate instance that avoids getSession() proxyScope method usage in its constructor.
#Bean("nonProxyScopedNeo4jOperations")
public Neo4jOperations nonProxyScopedNeo4jTemplate() throws Exception {
return new Neo4jTemplate(getSessionFactory().openSession());
}
// ...
and using the custom neo4jOperations bean to perform your #Async logic
see Neo4jConfiguration:
I have ended up moving my neo4jSession to a thread scope. As our application is stateless, our session is only one request. And as every request is handled in a separate thread, thread scope was the easiest way.
I'd like to thank to the developer of https://github.com/devbury/spring-boot-starter-threadscope , made my life easier. :)

Guice: How can I cache data

I am new to Guice and have a question regarding caching.
I have a WebApp which uses a provider to provide user configurations.
bind(UserConfiguration.class).toProvider(UserConfigurationProvider.class).in(ServletScopes.REQUEST);
The provider is declared as:
public class UserConfigurationProvider implements Provider<UserConfiguration>{
public UserConfiguration get() {
userConfigurationDatabase.getUserConfiguration(<some param here>);
}
}
In the get method, it calls DB and make a very expensive DB call.
I have a number of classes which get UserConfiguration injected like:
public class PriceView {
private UserConfiguration userConfiguration;
#Inject
public MyClass(UserConguration userConfiguration){
this.userConfiguration = userConfiguration;
}
.....
}
public class OrderView {
private UserConfiguration userConfiguration;
#Inject
public MyClass(UserConguration userConfiguration){
this.userConfiguration = userConfiguration;
}
........
}
The problem is that every time I switch a view, a new xxxxView object is created and hence a new UserConfiguration is injected and hence the expensive DB call is called.
I want to make calling the DB limited to once per user login. My idea is that cache the UserConfiguration somewhere when a user login and clear it after user logout or it expires.
But I want to know whehter Guice offers something more clever ways of caching about this use case?
Many thanks.
If you're using standard servlet session, then it should be enough to use ServletScopes.SESSION scope instead of ServletScopes.REQUEST. In this case the injected object should be created only once per session.
However, if you are not using standard servlet session but something custom, then you also need to create custom scope.

Static block in web service handler

I have a jax-ws web service with several handlers. I have a particular object that is performance wise costly to initiate. I need this object to process each and every request come to web service.
Is it a solution to put this object to a static block? Since static block is created at class loading time will it give a performance improvement. But still does it achieve what I need. I need same object kept in the memory and reused for all requests. But as I know in a web service each request is allocated to a thread object in the static block will not be shared by threads. it is?
Expecting a bit of explanation here guys.
Thank you
A static block is a piece of code which is run once when the class is initialized by the class loader. You might use it to set up your complex object and then keep a reference to it in a static variable like so:
public class MyClass {
private static final LanguageLookup languageLookup;
static {
languageLookup = new LanguageLookup ();
languageLookup.loadData();
}
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
}
If you do this in a multi-threaded environment like a servlet or a webservice you need to be sure that the state of LanguageLookup cannot change after its initialization. If it uses dependencies of its own for operations other than its initialization, these must also be stateless.
I think it is generally not a good idea to do it this way because you are hard-wiring your class to the LanguageLookup, making it tightly coupled and harder to unit test.
It is very easy to use a dependency injection framework like Spring to set up singletons:
When a bean is a singleton, only one shared instance of the bean will
be managed and all requests for beans with an id or ids matching that
bean definition will result in that one specific bean instance being
returned.
In the application context you would have something like:
<bean name="languageLookup" class="com.acme.foo.LanguageLookup" singleton="true" init-method="loadData"/>
And in your code:
public class MyClass {
private LanguageLookup languageLookup;
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
// called by Spring
public void setLanguageLookup(LanguageLookup languageLookup) {
this.languageLookup = languageLookup;
}
}

how to implement a service layer in servlet application

Suppose I want to create a service layer for my web application which uses servlets,How should I go about this?(I am not using a web app framework..So,please bear with me).Should I implement it as a listener?The service is meant to do database access.That is,I should be able to call from my servlet
class MyServlet{
...
doPost(...){
...
MyEntity entity = dbAccessService.getMyEntity(someId);
...
}
}
Where the dbAccessService should deal with hibernate session,transactions etc.Previously I used to do all this inside dao methods, but I was advised that was not a good idea.
Any suggestions welcome
thanks
mark
Sample code snippet is given below
class DBAccessServiceImpl{
...
private MyEntity getMyEntity(Long id){
Transaction tx = null;
MyEntity me = null;
Session session = HibernateUtil.getCurrentSession();
try{
tx = session.beginTransaction();
return entitydao.findEntityById(id);
}catch(RuntimeException e){
logger.info("problem occurred while calling findEntityById()");
throw e;
}
}
...
}
Then create a listener to instantiate DBAccessService
class MyAppListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent ctxEvent) {
ServletContext sc = ctxEvent.getServletContext();
DBAccessService dbservice = new DBAccessServiceImpl();
sc.setAttribute("dbAccessService",dbservice);
}
}
In web.xml add listener
...
<listener>
<listener-class>myapp.listeners.MyAppListener</listener-class>
</listener>
...
Assuming you do not want to introduce a framework, two options make sense (in my opinion):
define your service layer using stateless EJB session beans. You need an EJB container.
do it as always in OO languages, create an interface and a corresponding implementation:
Define an interface
public interface BusinessService {
abstract public BusinessObject performSomeOperation(SomeInput input);
}
And an implementation
public class BusinessServiceImpl implements BusinessService {
public BusinessObject performSomeOperation(SomeInput input) {
// some logic here...
}
}
You have several options for instantiating the service. If you start from scratch with a small application it may be sufficient to simply instantiate the service inside your web application:
BusinessService service = new BusinessServiceImpl();
service.performSomeOperation(...);
BTW: At a later time you may want to refactor and implement some abstractions around the Service instantiation (Factory pattern, dependency injection, etc.). Furthermore, in large systems there is a chance that you have to host the service layer on it's own infrastructure for scalability, so that your webapp communicates with the service layer via an open protocol, be it RESTful or Web Services.
However the future looks like, having a well defined interface defining your business functions in place, allows you to "easily" move forward if the application grows.
Response to your update:
I would not implement the service itself as a listener, this does not make sense. Nevertheless, your sample code seems to be reasonable, but you must distinguish between the Service (in this case DBAccessService) and the way you instantiate/retrieve it (the listener). The listener you've implemented plays in fact the role of a ServiceLocator which is capable of finding a certain services. If you store the instance of your Service in the servlet context you have to remind that the service implementation must be thread safe.
You have to be carefull to not over-engineer your design - keep it simple as long as you cannot foresee further, complex requirements. If it's not yet complex I suggest to encapsulate the implementation using a simple static factory method:
public final class ServiceFactory {
public static DBAccessService getDBAccessService() {
DBAccessService service = new DBAccessServiceImpl();
return service;
}
}
Complex alternatives are available to implement the ServiceFactory and nowadays some call it anti-pattern. But as long as you do not want to start with dependency injection (etc.) this one is still a valid solution. The service implementation DBAccessServiceImpl is accessed at one place only (the factory). As I mentioned before - keep an eye on multi-threading... hope this helps!
What you're suggesting is really no different to doing the session and transaction handling in a DAO. After all, your service class calls the DAO; to the client code, there is no difference.
Rather, i suspect that whoever told you not to put the session handling in the DAO was thinking that you should instead use Open Session In View pattern. Very simply, in its usual form, that involves writing a Filter which opens a session and starts a transaction before passing the request down the chain, and then commits the transaction (or rolls it back if necessary) and closes the session after the request completes. That means that within any one request, all access to persistent objects happens in a single transaction and a single session, which is usually the right way to do it (it's certainly the fastest way to do it).

Categories

Resources