Is there clean way to pass context data to #Asynchronous ejb call? - java

In wildfly I execute stateless ejb method asynchronously (it is mapped with #Asynchronous annotation). In the calling method I have some context information in thread local. What is the best way to pass this data to async method? I don't want to add additional parameter to async method signature.

Essentially you have only 2 options:
Passing value as a parameter
Storing that value in some global place. Like static variable.
The first option is much cleaner and easier. Don't use the second one :)

With a bit of ugly plumbing it can be resolved as follows (wildfly 8.x.x):
if (SecurityContextAssociation.getSecurityContext()==null)
SecurityContextAssociation.setSecurityContext(new JBossSecurityContext("background-job"));
SecurityContext current = SecurityContextAssociation.getSecurityContext();
final Object cred = current.getUtil().getCredential();
final Subject s = current.getUtil().getSubject();
final Principal up = current.getUtil().getUserPrincipal();
boolean needToUpdatePrincipal=true;
if (up instanceof TenantPrincipal) {
if (t.getTenantName().equals(((TenantPrincipal) up).getAdditonalField())) {
needToUpdatePrincipal=false;
}
}
if (needToUpdatePrincipal) {
TenantPrincipal tp=new TenantPrincipal(up.getName());
tp.setAdditionalField(t.getTenantName());
current.getUtil().createSubjectInfo(
, cred, (Subject) s);
}
Basically you need to create your own Principal class and set context data in the additional field of its instance.

Related

Ways to pass additional data to Custom RevisionEntity in Hibernate Envers?

It's RESTful web app. I am using Hibernate Envers to store historical data. Along with revision number and timestamp, I also need to store other details (for example: IP address and authenticated user). Envers provides multiple ways to have a custom revision entity which is awesome. I am facing problem in setting the custom data on the revision entity.
#RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
private String ip;
//Accessors
}
public class MyCustomRevisionListener implements RevisionListener {
public void newRevision( Object revisionEntity ) {
MyCustomRevisionEntity customRevisionEntity = ( MyCustomRevisionEntity ) revisionEntity;
//Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity.
}
}
Since newRevision() method does not allow any additional arguments, I can not pass my custom data (like username and ip) to it. How can I do that?
Envers also provides another approach as:
An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision( Class revisionEntityClass, boolean persist ) method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information.
So using the above approach, I'll have to do something like this:
Change my current dao method like:
public void persist(SomeEntity entity) {
...
entityManager.persist(entity);
...
}
to
public void persist(SomeEntity entity, String userName, String ip) {
...
//Do the intended work
entityManager.persist(entity);
//Do the additional work
AuditReader reader = AuditReaderFactory.get(entityManager)
MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false);
revision.setUserName(userName);
revision.setIp(ip);
}
I don't feel very comfortable with this approach as keeping audit data seems a cross cutting concern to me. And I obtain the userName and Ip and other data through HTTP request object. So all that data will need to flow down right from entry point of application (controller) to the lowest layer (dao layer).
Is there any other way in which I can achieve this? I am using Spring.
I am imagining something like Spring keeping information about the 'stack' to which a particular method invocation belongs. So that when newRevision() in invoked, I know which particular invocation at the entry point lead to this invocation. And also, I can somehow obtain the arguments passed to first method of the call stack.
One good way to do this would be to leverage a ThreadLocal variable.
As an example, Spring Security has a filter that initializes a thread local variable stored in SecurityContextHolder and then you can access this data from that specific thread simply by doing something like:
SecurityContext ctx = SecurityContextHolder.getSecurityContext();
Authorization authorization = ctx.getAuthorization();
So imagine an additional interceptor that your web framework calls that either adds additional information to the spring security context, perhaps in a custom user details object if using spring security or create your own holder & context object to hold the information the listener needs.
Then it becomes a simple:
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setIpAddress( userContext.getIpAddress() );
mre.setUserName( userContext.getUserName() );
}
}
This feels like the cleanest approach to me.
It is worth noting that the other API getCurrentRevision(Session,boolean) was deprecated as of Hibernate 5.2 and is scheduled for removal in 6.0. While an alternative means may be introduced, the intended way to perform this type of logic is using a RevisionListener.

How to avoid concurrent access of controller method with the same session in java spring?

I would like to know how to make sure that some method in a service is accessed only once at a time per session.
I'll illustrate by a small example:
Assume we have a user in a state A (user.state = A). This user sends a HTTP GET request to our java spring controller to get a page, say /hello. Based on his status, he will be sent to either A or B. Before that, we will change his status to B (see code below).
Now, assume again that the call dao.doSomething(); takes a lot of time. If the user sends another GET (by refreshing his browser for instance), he will call the exact same method dao.doSomething(), resulting in 2 calls.
How can you avoid that?
What happens if you sends 2 HTTP GETs at the same time?
How can you have something consistent in your controller/service/model/database?
Note 1: here we don't issue the 2 HTTP GETs from different browser. We just make them at the same time on the same browser (I'm aware of the max concurrent session solution, but this does not solve my problem.).
Note 2: the solution should not block concurrent accesses of the controller for different users.
I've read a bit about transaction on service, but I'm not sure if this is the solution. I've also read a bit on concurrency, but I still don't understand how to use it here.
I would greatly appreciate your help! Thanks!
code example:
#Controller
public class UserController {
#RequestMapping(value='/hello')
public String viewHelloPage() {
// we get the user from a session attribute
if (user.getState() = A) {
user.setStatus(B);
return "pageA";
}
return "pageB";
}
#Service
public class UserService {
Dao dao;
#Override
public void setStatus(User user) {
dao.doSomething();
user.setStatus(B);
}
}
Although I wouldn't recommend it (as it basically blocks all other calls from the same user to). On most HandlerAdapter implementations you can set the property synchronizeOnSession by default this is false allowing for concurrent requests to come from the same client. When you set this property to true requests will be queued for that client.
How to set it depends on your configuration of the HandlerAdapter.
how to make sure that some method in a service is accessed only once
at a time per session.
Try to Lock on session object in your controller before calling service method
If dao.doSomething() is doing work that you only want to happen once, you should use an idempotent method like PUT or DELETE. There's no law forcing you to use the correct method, but worst-case it's a self-documenting way to tell the world about how your API should be used. If that isn't enough for you, most browsers will try to help you out based on the type of request. For instance, the browser will often use caching to avoid multiple GETs.
It seems like what you really want to know is how to enforce idempotency. This is very application-specific. One general approach is to generate and store a pseudo-unique id on the server side for the client to attach to their request. This way, any request with the same id after the first can be safely ignored. Obviously old ids should be evicted intelligently.
As I said, the solution is often application-specific. In your case above, it looks like you're trying to switch between 2 states, and your implementation is a server-side toggle. You can utilize the client to ensure that multiple requests will not be a problem.
#RequestMapping(value="/hello", method=RequestMethod.PUT)
public String test(#RequestParam("state") String state) {
dao.setState(user, state)
switch (state) {
case "A":
return "B";
case "B":
return "A";
default:
return "error";
}
}
If you don't mind to configure and use AOP, then the following might help you
#Aspect
#Component
public class NonConcurrentAspect implements HttpSessionListener{
private Map<HttpSession, Map<Method, Object>> mutexes = new ConcurrentHashMap<HttpSession, Map<Method, Object>>();
#Around(value = "#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object handle(ProceedingJoinPoint pjp) throws Throwable {
MethodInvocationProceedingJoinPoint methodPjp = (MethodInvocationProceedingJoinPoint) pjp;
Method method = ((MethodSignature) methodPjp.getSignature()).getMethod();
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpSession session = request.getSession(false);
Object mutex = getMutex(session, method);
synchronized (mutex) {
return pjp.proceed();
}
}
private Object getMutex(HttpSession session, Method method) {
Map<Method, Object> sessionMutexes = mutexes.get(session);
Object mutex = new Object();
Object existingMutex = sessionMutexes.putIfAbsent(method, mutex);
return existingMutex == null ? mutex : existingMutex;
}
#Override
public void sessionCreated(HttpSessionEvent se) {
mutexes.put(se.getSession(), new ConcurrentHashMap<Method, Object>());
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
mutexes.remove(se.getSession());
}
}
It synchronizes on a per-session per-method mutex. One restriction is that the methods so advised should not call each other (which is hardly a case, unless you violate MVC design pattern severely), otherwise you may face deadlocks.
This would handle all the methods tagged with #RequestMapping, but if you want just few methods be guarded against concurrent execution,
then, as one of the possible solutions, you could introduce your own annotation, e.g.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface NonConcurrent {
}
tag the specific methods with this annotation, and replace #RequestMapping in #Around annotation in the above aspect class with your own.
In highly contended environment you may think of more advanced solution than intrinsic locks.
I would, however, advise against using HandlerAdapter's synchronizeOnSession option, not only because it synchronizes all the invocations on the same mutex, but, which is less obvious, the synchronization on publicly available mutex is potentially dangerous.

How do I shutdown and reconfigure an AsyncHttpClient that is using NettyAsyncHttpProvider

I'm constructing an AsyncHttpClient like this:
public AsyncHttpClient getAsyncHttpClient() {
AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()
.setProxyServer(makeProxyServer())
.setRequestTimeoutInMs((int) Duration.create(ASYNC_HTTP_REQUEST_TIMEOUT_MIN, TimeUnit.MINUTES).toMillis())
.build();
return new AsyncHttpClient(new NettyAsyncHttpProvider(config), config);
}
This gets called once at startup, and then the return value is passed around and used in various places. makeProxyServer() is my own function to take my proxy settings an return a ProxyServer object. What I need to do is be able to change the proxy server settings and then recreate the AsyncHttpClient object. But, I don't know how to shut it down cleanly. A bit of searching on leads me to believe that close() isn't gracefull. I'm worried about spinning up a whole new executor and set of threads every time the proxy settings change. This won't be often, but my application is very long-running.
I know I can use RequestBuilder.setProxyServer() for each request, but I'd like to have it set in one spot so that all callers of my asyncHttpClient instance obey the system-wide proxy settings without each developer having to remember to do it.
What's the right way to re-configure or teardown and rebuild a Netty-based AsyncHttpClient?
The problem with using AsyncHttpClient.close() is that it shuts down the thread pool executor used by the provider, then there is no way to re-use the client without re-building it, because as per documentation, the executor instance cannot be reused once ts is shutdown. So, there is no way but re-build the client if you go that way (unless you implement your own ExecutorService that would have another shutdown logic, but it is a long way to go, IMHO).
However, from looking into the implementation of NettyAsyncHttpProvider, I can see that it stores the reference to the given AsyncHttpClientConfiginstance and calls its getProxyServerSelector() to get the proxy settings for every new NettyAsyncHttpProvider.execute(Request...) invocation (i.e. for every request executed by AsyncHttpClient).
Then, if we could make the getProxyServerSelector() return the configurable instance of ProxyServerSelector, that would do the thing.
Unfortunately, AsyncHttpClientConfig is designed to be a read-only container, instantiated by AsyncHttpClientConfig.Builder.
To overcome this limitation, we would have to hack it, using, say, "wrap/delegate" approach:
Create a new class, derived from AsyncHttpClientConfig. The class should wrap the given separate AsyncHttpClientConfig instance and implement the delegation of the AsyncHttpClientConfig getters to that instance.
To be able to return the proxy selector we want at any given point of time, we make this setting mutable in a this wrapper class and expose the setter for it.
Example:
public class MyAsyncHttpClientConfig extends AsyncHttpClientConfig
{
private final AsyncHttpClientConfig config;
private ProxyServerSelector proxyServerSelector;
public MyAsyncHttpClientConfig(AsyncHttpClientConfig config)
{
this.config = config;
}
#Override
public int getMaxTotalConnections() { return config.maxTotalConnections; }
#Override
public int getMaxConnectionPerHost() { return config.maxConnectionPerHost; }
// delegate the others but getProxyServerSelector()
...
#Override
public ProxyServerSelector getProxyServerSelector()
{
return proxyServerSelector == null
? config.getProxyServerSelector()
: proxyServerSelector;
}
public void setProxyServerSelector(ProxyServerSelector proxyServerSelector)
{
this.proxyServerSelector = proxyServerSelector;
}
}
Now, in your example, wrap your AsyncHttpClient config instance with our new wrapper and use it to configure the AsyncHttpClient:
Example:
MyAsyncHttpClientConfig myConfig = new MyAsyncHttpClientConfig(config);
return new AsyncHttpClient(new NettyAsyncHttpProvider(myConfig), myConfig);
Whenever you invoke myConfig.setProxyServerSelector(newSelector), the new request executed by NettyAsyncHttpProvider instance in your client will use the new proxy server settings.
A few hints/warnings:
This approach relies on the internal implementation of NettyAsyncHttpProvider; therefore make your own judgement on maintainability, future Netty libraries versions upgrade strategy etc. You could always look at the Netty source code before upgrading to the new version. At the current point, I personally think it is unlikely to change too much to invalidate this implementation.
You could get ProxyServerSelector for ProxyServer by using com.ning.http.util.ProxyUtils.createProxyServerSelector(proxyServer) - that's exactly what AsyncHttpClientConfig.Builder does.
The given example has no synchronization logic for accessing proxyServerSelector; you may want to add some as your application logic needs.
Maybe it is a good idea to submit a feature request for AsyncHttpClient to be able to setup a "configuration factory" for the AsyncHttpProvider so all these complications would vanish :-)
You should be holding a RequestHandle instance for all your unfinished requests. When you want to shut down, you can loop through and call isFinished() on all of them until they are all done. Then you know you can safely close it and no pending requests will be killed.
Once it's closed, just build a new one. Don't try to reuse the existing one. If you have references to it around, change those to reference a Factory that will return the current one.

Netty - How to pass information between handlers in the same pipeline

I would like to create a pipeline of handlers such as:
public ChannelPipeline getPipeline() throws Exception
{
return Channels.pipeline(
new ObjectEncoder(),
new ObjectDecoder(),
new AuthenticationServerHandler(),
new BusinessLogicServerHandler());
}
The key here is that I'd like the AuthenticationServerHandler to be able to pass the login information to the BusinessLogicServerHandler.
I do understand that you can use an Attachment, however that only stores the information for that handler, the other handlers in the pipeline cannot access it. I also noticed there was something called ChannelLocal which might do the trick, however I cannot find any real information on how to use it. All I've seen is people create a static instance to it, but how do you retrieve and access the info in another handler? Assuming that's the correct method.
My question is: how you do pass information between handlers in the same pipeline. In the example above, how do I pass the login credentials from the AuthenticationServerHandler to the BusinessLogicServerHandler?
ChannelLocal is the way to go atm. Just create an static instance somewhere and then access it from within your handlers by pass the Channel to the set/get method. This way you can share stuff between your channels.
I wasn't a fan of the ChannelLocal implementation with the lack of an internal static map, so what I ended up doing was putting my object on the Channel's attachment for now:
ctx.getChannel().setAttachment(myobj);
Then I make "myobj" basically a context POJO that contains all the information gathered about the request so far.
public class RequestContext {
private String foo = "";
public String getFoo(){
return foo;
}
public void setFoo(String foo){
this.foo = foo;
}
}
RequestContext reqCtx = new RequestContext();
reqCtx.setFoo("Bar");
ctx.getChannel().setAttachment(reqCtx);
reqCtx = (RequestContext)ctx.getChannel().getAttachment();
It's not elegant, but it works...
I pass information from one handler to the next ones by using dedicated instances to compose the pipeline for each channel, and by having the handlers reference each others within each pipeline.
The passing of information is made the old way, very simply, without any problem.

Configuring OSGI Services on a per use basis

I want to create a paging service that will return pages based on a SQL like query. Here is the simple interface:
public interface IPage {
public boolean hasNext();
public Object[] next();
}
When I call this service I want to be able to initialize it with a query String and a page size int.
How do I go about getting a reference to the service that has been initialized with the arguments specified above? I would prefer to use declarative services but it seems to me I would have to use ServiceTracker if I wanted to pass in arguments.
Thanks for your help.
Instead exposing IPage as a service, you might expose an IPageFactory as a service instead. The factory would then take a query and a page size, and return an initialised IPage instance.

Categories

Resources