I have method which every now and then generates a string. I would like to register method as uri and produce a exchange method which will be used as input for a route.
The method is call by a different class
SampleClass sc = new SampleClass();
sc.sampleMethod("Hello");
Eg:
public class SampleClass{
#Produce(uri = "direct:consumerMethod")
ProducerTemplate producer;
public sampleMethod(Object obj){
producer.sendBody(object);
}
}
The route is defined as below:
#Override
public void configure() {
from("direct:consumerMethod").process(new GenerateD());
}
But the route doesnt call GenerateD class when i produce using the sampleMethod. Is this not feasible or am i doing something wrong?
Finally this is what worked for my use case.
Starting camelcontext as below:
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(new SampleRoute());
camelContext.start();
My routebuilder class :
class SampleRoute extends RouteBuilder {
#Override
public void configure() {
try
{
from("direct:consumerMethod").process(new DDT());
}catch(Exception e)
{
e.printStackTrace();
}
}
}
I then create a interface which has a sendMessage method.
public interface DDTConsumer {
public String sendMessage(Object object);
}
Now i implement this method to create an endpoint of this interface and send a message to the endpoint.
DDTConsumer ddt;
try {
ddt = new ProxyBuilder(camelContext).endpoint("direct:consumerMethod").build(DDTConsumer.class);
ddt.sendMessage(msg.getValue());
} catch (Exception e) {
e.printStackTrace();
}
This solved my problem and the route is working fine now. Hope it helps others as well.
In your class where you have the sampleMethod(Object) add the following field:
#Produce(uri = "direct:consumerMethod")
ProducerTemplate template;
In your sampleMethod(Object) you can use the previously added template like this:
public sampleMethod(Object obj){
template.sendBody(object);
}
And it should send a Message to the direct:consumerMethod route.
Use something like this, if you want to call somemethod
#Override
public void configure() {
from("direct:consumerMethod").log(simple("${bean:generateD?method=generateDMethod}"));
}
The above expression will call the generateDMethod of generateD object (bean) and log the methods output to console (the default log writer).
To make above expression work, you have to store generateD bean in the Registry, which will be further associated with your application's CamelContext. You can do the same as follows
#Autowired
private GenerateD generateD;
#Override
protected CamelContext createCamelContext() throws Exception {
SimpleRegistry registry = new SimpleRegistry();
registry.put("generateD", generateD); //the generateD bean,which can be used anywhere in the camelcontext
SpringCamelContext camelContext = new SpringCamelContext();
camelContext.setRegistry(registry); //add the registry
camelContext.setApplicationContext(getApplicationContext());
camelContext.start();
return camelContext;
}
This adds the bean to camelContext. Please check my answer at this link to have complete example.
I'm new to Guice and Shiro, and i'm trying to use it with my DB (h2).
I've read this : click
but as they said it's just working for the users and roles sections, which is useless for me.
My shiro.ini is working, i managed to create user, login and logout without the Guice part.
My MyShiroModule
public class MyShiroModule extends ShiroModule{
protected void configureShiro() {
try {
bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
} catch (NoSuchMethodException e) {
addError(e);
}
}
#Provides
Ini loadShiroIni() {
return Ini.fromResourcePath("classpath:shiro.ini");
}
}
and my Module :
public class Module extends AbstractModule {
#Singleton
protected void configure() {
Injector injector = Guice.createInjector(new MyShiroModule());
SecurityManager securityManager = injector.getInstance(SecurityManager.class);
SecurityUtils.setSecurityManager(securityManager);
}
}
they're as they said in the tutorial.
What do i have to add to use the [main] part of my shiro.ini?
I never got the JDBC realm to work with Guice since, as you noted, it only reads the users and groups section for whatever reason. I ended up not using Shiro.ini at all just creating the JdbcRealm myself like this:
public class ShiroAuthModule extends ShiroModule {
#Override
public void configure() {
super.configure();
// Bind your data source however you need to - I use JNDI
// but it would be easy to switch to a properties file.
bind(Context.class).to(InitialContext.class);
bind(DataSource.class).toProvider(JndiIntegration.fromJndi(DataSource.class, "java:/comp/env/jdbc/security"));
}
#Provides
#Singleton
JdbcRealm loadJdbcRealm(Ini ini, DataSource ds,
#Named("shiro.authenticationQuery") String authenticationQuery,
#Named("shiro.userRolesQuery") String roleQuery,
#Named("shiro.permissionsQuery") String permissionQuery) {
JdbcRealm realm = new JdbcRealm();
realm.setAuthenticationQuery(authenticationQuery);
realm.setUserRolesQuery(roleQuery);
realm.setPermissionsQuery(permissionQuery);
realm.setPermissionsLookupEnabled(true);
realm.setDataSource(ds);
return realm;
}
#Override
protected void configureShiro() {
// shiro.properties should be on your classpath and
// contain the named properties in loadJdbcRealm
Properties properties = Module.loadProperties(this, "shiro.properties");
Names.bindProperties(binder(), properties);
try {
bindRealm().to(JdbcRealm.class);
} catch (SecurityException e) {
addError(e);
}
}
}
In my app I have some async web services. Server accept request, return OK response and start processing request with AsyncTaskExecutor. My question is how to enable request scope here because in this processing I need to get class which is annotated by:
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
Now I get exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.requestContextImpl': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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.
because it runs in SimpleAsyncTaskExecutor and not in DispatcherServlet
my async processing of request
taskExecutor.execute(new Runnable() {
#Override
public void run() {
asyncRequest(request);
}
});
where taskExecutor is:
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
We ran into the same problem - needed to execute code in the background using #Async, so it was unable to use any Session- or RequestScope beans. We solved it the following way:
Create a custom TaskPoolExecutor that stores scoped information with the tasks
Create a special Callable (or Runnable) that uses the information to set and clear the context for the background thread
Create an override configuration to use the custom executor
Note: this will only work for Session and Request scoped beans, and not for security context (as in Spring Security). You'd have to use another method to set the security context if that is what you're after.
Note2: For brevity, only shown the Callable and submit() implementation. You can do the same for the Runnable and execute().
Here is the code:
Executor:
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
}
Callable:
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private RequestAttributes context;
public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
this.task = task;
this.context = context;
}
#Override
public T call() throws Exception {
if (context != null) {
RequestContextHolder.setRequestAttributes(context);
}
try {
return task.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
Configuration:
#Configuration
public class ExecutorConfig extends AsyncConfigurerSupport {
#Override
#Bean
public Executor getAsyncExecutor() {
return new ContextAwarePoolExecutor();
}
}
The easiest way is to use a task decorator like this:
static class ContextCopyingDecorator implements TaskDecorator {
#Nonnull
#Override
public Runnable decorate(#Nonnull Runnable runnable) {
RequestAttributes context =
RequestContextHolder.currentRequestAttributes();
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
RequestContextHolder.setRequestAttributes(context);
MDC.setContextMap(contextMap);
runnable.run();
} finally {
MDC.clear();
RequestContextHolder.resetRequestAttributes();
}
};
}
}
To add this decorator to the task executor, all you need is to add it in the configuration routine:
#Override
#Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setTaskDecorator(new ContextCopyingDecorator());
poolExecutor.initialize();
return poolExecutor;
}
There is no need for an additional holder or a custom thread-pool task executor.
A small update for 2021: Using current versions of Spring Boot, the mere existence of a bean of type TaskDecorator will suffice. Upon creating the context, the task decorator will be used to decorate the executors that Spring Boot creates.
The solutions mentioned before were not working for me.
The reason why the solution not working is, as mentioned in #Thilak's post, as soon as the original parent thread committed response to the client, the request objects may be garbage collected.
But with some tweak to the solution provided by #Armadillo I was able to get it working. I am using spring boot 2.2
Here is what I followed.
Create a custom TaskPoolExecutor that stores(after cloning) scoped
information with the tasks.
Create a special Callable (or Runnable)
that uses the cloned information to set the current context values
and clear the context for the async thread.
Executor (Same as in #Armadillo's post):
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
}
Callable:
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private final RequestAttributes requestAttributes;
public ContextAwareCallable(Callable<T> task, RequestAttributes requestAttributes) {
this.task = task;
this.requestAttributes = cloneRequestAttributes(requestAttributes);
}
#Override
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return task.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
private RequestAttributes cloneRequestAttributes(RequestAttributes requestAttributes){
RequestAttributes clonedRequestAttribute = null;
try{
clonedRequestAttribute = new ServletRequestAttributes(((ServletRequestAttributes) requestAttributes).getRequest(), ((ServletRequestAttributes) requestAttributes).getResponse());
if(requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST).length>0){
for(String name: requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST)){
clonedRequestAttribute.setAttribute(name,requestAttributes.getAttribute(name,RequestAttributes.SCOPE_REQUEST),RequestAttributes.SCOPE_REQUEST);
}
}
if(requestAttributes.getAttributeNames(RequestAttributes.SCOPE_SESSION).length>0){
for(String name: requestAttributes.getAttributeNames(RequestAttributes.SCOPE_SESSION)){
clonedRequestAttribute.setAttribute(name,requestAttributes.getAttribute(name,RequestAttributes.SCOPE_SESSION),RequestAttributes.SCOPE_SESSION);
}
}
if(requestAttributes.getAttributeNames(RequestAttributes.SCOPE_GLOBAL_SESSION).length>0){
for(String name: requestAttributes.getAttributeNames(RequestAttributes.SCOPE_GLOBAL_SESSION)){
clonedRequestAttribute.setAttribute(name,requestAttributes.getAttribute(name,RequestAttributes.SCOPE_GLOBAL_SESSION),RequestAttributes.SCOPE_GLOBAL_SESSION);
}
}
return clonedRequestAttribute;
}catch(Exception e){
return requestAttributes;
}
}
}
The change I made is to introduce cloneRequestAttributes() to copy and set the RequestAttribute, so that the values remain available even after the original parent thread commits response to the client.
Configuration:
Since there are other async configuration and I didn't want the behavior to be applicable in other async executors I've created its own task executor configuration.
#Configuration
#EnableAsync
public class TaskExecutorConfig {
#Bean(name = "contextAwareTaskExecutor")
public TaskExecutor getContextAwareTaskExecutor() {
ContextAwarePoolExecutor taskExecutor = new ConAwarePoolExecutor();
taskExecutor.setMaxPoolSize(20);
taskExecutor.setCorePoolSize(5);
taskExecutor.setQueueCapacity(100);
taskExecutor.setThreadNamePrefix("ContextAwareExecutor-");
return taskExecutor;
}
}
And finally on the async method, I use the executor name.
#Async("contextAwareTaskExecutor")
public void asyncMethod() {
}
Alternate Solution:
We ended up in this trouble by trying to reuse an existing component class. Though the solution made it look like it is convenient. Its much less hassle (cloning objects and reserving thread pool) if we could have referred the relevant request scoped values as method parameters. In our case, we are planning to refactor the code in such a way that the component class which is using the request scoped bean, and being reused from the async method, to accept the values as method parameters. Request scoped bean is removed from the reusable component and moved to the component class which invokes its method.
To put what I just described it in code:
Our current state is :
#Async("contextAwareTaskExecutor")
public void asyncMethod() {
reUsableCompoment.executeLogic() //This component uses the request scoped bean.
}
Refactored code:
#Async("taskExecutor")
public void asyncMethod(Object requestObject) {
reUsableCompoment.executeLogic(requestObject); //Request scoped bean is removed from the component and moved to the component class which invokes it menthod.
}
There is no way to get a request scoped object in an child async thread, since the original parent request processing thread may have already committed the response to the client and all the request objects are destroyed. One way to handle such scenarios is to use custom scope, like SimpleThreadScope.
one problem with SimpleThreadScope is that the child threads will not inherit parents scope variables, because it uses simple ThreadLocal internally. To overcome that implement a custom scope which is exactly similar to SimpleThreadScope but uses InheritableThreadLocal internally. For more info reg this
Spring MVC: How to use a request-scoped bean inside a spawned thread?
None of the above Solution works for me because in my case the parent thread responded for request back to the client and the request scoped object can't be referred in any worker threads.
I just made a work around to make above things work. I am using Spring Boot 2.2 and using customTaskExecutor with ContextAwareCallable just specified above.
Async Configuration:
#Bean(name = "cachedThreadPoolExecutor")
public Executor cachedThreadPoolExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ContextAwarePoolExecutor();
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
threadPoolTaskExecutor.setThreadNamePrefix("ThreadName-");
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
ContextAwarePoolExecutor:
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task,
RequestContextHolder.currentRequestAttributes()));
}
}
Created Custom Context Aware Callable:
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private CustomRequestScopeAttributes customRequestScopeAttributes;
private static final String requestScopedBean =
"scopedTarget.requestScopeBeanName";
public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
this.task = task;
if (context != null) {
//This is Custom class implements RequestAttributes class
this.customRequestScopeAttributes = new CustomRequestScopeAttributes();
//Add the request scoped bean to Custom class
customRequestScopeAttributes.setAttribute
(requestScopedBean,context.getAttribute(requestScopedBean,0),0);
//Set that in RequestContextHolder and set as Inheritable as true
//Inheritable is used for setting the attributes in diffrent ThreadLocal objects.
RequestContextHolder.setRequestAttributes
(customRequestScopeAttributes,true);
}
}
#Override
public T call() throws Exception {
try {
return task.call();
} finally {
customRequestScopeAttributes.removeAttribute(requestScopedBean,0);
}
}
}
Custom class:
public class CustomRequestScopeAttributes implements RequestAttributes {
private Map<String, Object> requestAttributeMap = new HashMap<>();
#Override
public Object getAttribute(String name, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
return this.requestAttributeMap.get(name);
}
return null;
}
#Override
public void setAttribute(String name, Object value, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST){
this.requestAttributeMap.put(name, value);
}
}
#Override
public void removeAttribute(String name, int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
this.requestAttributeMap.remove(name);
}
}
#Override
public String[] getAttributeNames(int scope) {
if(scope== RequestAttributes.SCOPE_REQUEST) {
return this.requestAttributeMap.keySet().toArray(new String[0]);
}
return new String[0];
}
//Override all methods in the RequestAttributes Interface.
}
Finally add the Async annotation in the method needed.
#Async("cachedThreadPoolExecutor")
public void asyncMethod() {
anyService.execute() //This Service execution uses request scoped bean
}
With Spring-boot-2.0.3.REALEASE / spring-web-5.0.7, I've come up with below code working for #Async
Class that holds the ThreadLocal context.
import java.util.Map;
public class ThreadContextHolder {
private ThreadContextHolder() {}
private static final ThreadLocal<Map<String, Object>> ctx = new ThreadLocal<>();
public static Map<String, Object> getContext() {
return ctx.get();
}
public static void setContext(Map<String, Object> attrs) {
ctx.set(attrs);
}
public static void removeContext() {
ctx.remove();
}
}
Async config :
#Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
...
...
executor.setTaskDecorator(
runnable -> {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); // or currentRequestAttributes() if you want to fall back to JSF context.
Map<String, Object> map =
Arrays.stream(requestAttributes.getAttributeNames(0))
.collect(Collectors.toMap(r -> r, r -> requestAttributes.getAttribute(r, 0)));
return () -> {
try {
ThreadContextHolder.setContext(map);
runnable.run();
} finally {
ThreadContextHolder.removeContext();
}
};
});
executor.initialize();
return executor;
}
And from the async method :
#Async
public void asyncMethod() {
logger.info("{}", ThreadContextHolder.getContext().get("key"));
}
#Armadillo's answer motivated me to write the implementation for Runnable.
Custom implementation for TaskExecutor:
/**
* This custom ThreadPoolExecutor stores scoped/context information with the tasks.
*/
public class ContextAwareThreadPoolExecutor extends ThreadPoolTaskExecutor {
#Override
public Future<?> submit(Runnable task) {
return super.submit(new ContextAwareRunnable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public ListenableFuture<?> submitListenable(Runnable task) {
return super.submitListenable(new ContextAwareRunnable(task, RequestContextHolder.currentRequestAttributes()));
}
}
Custom implementation for Runnable:
/**
* This custom Runnable class can use to make background threads context aware.
* It store and clear the context for the background threads.
*/
public class ContextAwareRunnable implements Runnable {
private Runnable task;
private RequestAttributes context;
public ContextAwareRunnable(Runnable task, RequestAttributes context) {
this.task = task;
// Keeps a reference to scoped/context information of parent thread.
// So original parent thread should wait for the background threads.
// Otherwise you should clone context as #Arun A's answer
this.context = context;
}
#Override
public void run() {
if (context != null) {
RequestContextHolder.setRequestAttributes(context);
}
try {
task.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
I solved this issue adding the following bean configuration
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
Update: the above solution does not clean up any objects associated with the threads as mention in spring's documentation. This alternative works for me: https://www.springbyexample.org/examples/custom-thread-scope-module.html
#Armadillo
Worked for me, many thanks.
As for Spring Security Context, there is more out-of-box solution and it worked for me either (found here How to set up Spring Security SecurityContextHolder strategy?)
In order to use SecurityContextHolder in child threads:
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
Here is a related answer for anyone who wants to use RequestScope with non blocking I/O commands in an API, as opposed to spinning up child threads that live on past the original HTTP request.
SPRING ASYNC AWAIT REQUEST SCOPE
It is possible to implement a custom scope in Spring which stores request scoped objects in the current HttpServletRequest object, so that objects can be accessed before and after 'await' statements:
Async Await Usage
HttpServletRequest based RequestScope
Full Java API Code Sample
Is it possible to use callbacks with Spring to that they are managed by application context?
My problem is when a service is used from outer by #Autowired, but within that service there is a callback defined using new operator.
The following example executes a method that is worth retrying. Spring offers a RetryCallback for this case (I know this could be acchieved differently, but just to illustrate my callback problem).
#Service
class MyService {
//main method invoked
void run(DataVO dataVO) {
//new operator not usable in spring context
RetryCallback<Object> retryCallback = new RetryCallback<Object>() {
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
};
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
Is it possible to refactor this snippet so that the callback is managed by spring/injected/autowired?
Make your service implement the callback interface :
#Service
class MyService implements RetryCallback<Object> {
//main method invoked
void run(DataVO dataVO) {
}
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
i need to invoke the method base on the cron pattern. this is my java code .where i included one method and this method i need to call.i try in google but not getting any idea how to call.
public class Schedule {
int i;
public String show()
{
return "hi"+i++;
}
public static void main(String args[])throws Exception
{
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("quartz2://myGroup/myfirstrigger?cron=0/2+*+*+*+*+?").to(new Schedule().show());
}
});
context.start();
}
}
i am not sure also this is right or not
You should look at the documentation on bean binding (Here). I think your route would be better like the following:
from("quartz2://myGroup/myfirstrigger?cron=0/2+*+*+*+*+?")
.bean(Schedule.class, "show");