Internally, Function and Async Function are both non-blocking (right?). So, why do we have AsyncFunction. Is the difference only that one returns a ListenableFuture Object and the other returns the object?
Well one of them deals with transforming an Iterable for example and one transforms (possibly asynchronously) from one ListenableFuture to another. The concepts are completely different and deal with different things.
Here is a small example of AsyncFunction, basically we asynchronously get a String and then asynchronously transform that String into a different one. This is just a sample though..
public class GuavaAsyncFunction {
public static void main(String[] args) {
ExecutorService deletegate = Executors.newFixedThreadPool(1);
ExecutorService deletegateForAsyncFunction = Executors.newFixedThreadPool(1);
ListeningExecutorService pool = MoreExecutors.listeningDecorator(deletegate);
ListeningExecutorService poolForAsyncFunction = MoreExecutors.listeningDecorator(deletegateForAsyncFunction);
ListenableFuture<String> resultFromWorker = pool.submit(new Worker());
ListenableFuture<String> finalResult = Futures.transform(resultFromWorker, new AsyncTransformation(poolForAsyncFunction));
Futures.addCallback(finalResult, new MyFutureCallback());
}
private static final class Worker implements Callable<String> {
public String call() throws Exception {
try {
System.out.println("Executing in thread="+Thread.currentThread().getName());
//simultate some work
TimeUnit.SECONDS.sleep(3);
} catch(InterruptedException ex){
ex.printStackTrace();
}
return "CALCULATED_VALUE";
}
}
/**
* Almost like Function transformation but it is asynchronous
*/
private static final class AsyncTransformation implements AsyncFunction<String, String> {
private final ListeningExecutorService poolToRunFunctionIn;
public AsyncTransformation(ListeningExecutorService poolToRunFunctionIn){
this.poolToRunFunctionIn = poolToRunFunctionIn;
}
public ListenableFuture<String> apply(String input) throws Exception {
return poolToRunFunctionIn.submit(new FunctionWorker(input));
}
/**
* 'worker' for the AsyncFunction
*/
private static final class FunctionWorker implements Callable<String> {
private final String input;
public FunctionWorker(String input){
this.input = input;
}
public String call() throws Exception {
try {
System.out.println("Executing in thread="+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(3);
} catch(InterruptedException ex){
ex.printStackTrace();
}
return input + "_TRANSFORMED";
}
}
}
/**
* what do to when the ListenableFuture has been processed
*/
private static final class MyFutureCallback implements FutureCallback<String> {
public void onSuccess(String result) {
System.out.println("Result from computation = " + result);
}
public void onFailure(Throwable t) {
t.printStackTrace();
}
}
}
Related
Using Spring MVC, I have the following setup:
An AbstractRequestLoggingFilter derived filter for logging requests.
A TaskDecorator to marshal the MDC context mapping from the web request thread to the #Async thread.
I'm attempting to collect context info using MDC (or a ThreadLocal object) for all components involved in handling the request.
I can correctly retrieve the MDC context info from the #Async thread. However, if the #Async thread were to add context info to the MDC, how can I now marshal the MDC context info to the thread that handles the response?
TaskDecorator
public class MdcTaskDecorator implements TaskDecorator {
#Override
public Runnable decorate(Runnable runnable) {
// Web thread context
// Get the logging MDC context
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
// #Async thread context
// Restore the web thread MDC context
if(contextMap != null) {
MDC.setContextMap(contextMap);
}
else {
MDC.clear();
}
// Run the new thread
runnable.run();
}
finally {
MDC.clear();
}
};
}
}
Async method
#Async
public CompletableFuture<String> doSomething_Async() {
MDC.put("doSomething", "started");
return doit();
}
Logging Filter
public class ServletLoggingFilter extends AbstractRequestLoggingFilter {
#Override
protected void beforeRequest(HttpServletRequest request, String message) {
MDC.put("webthread", Thread.currentThread().getName()); // Will be webthread-1
}
#Override
protected void afterRequest(HttpServletRequest request, String message) {
MDC.put("responsethread", Thread.currentThread().getName()); // Will be webthread-2
String s = MDC.get("doSomething"); // Will be null
// logthis();
}
}
I hope you have solved the problem, but if you did not, here comes a solution.
All you have to do can be summarized as following 2 simple steps:
Keep your class MdcTaskDecorator.
Extends AsyncConfigurerSupport for your main class and override getAsyncExecutor() to set decorator with your customized one as follows:
public class AsyncTaskDecoratorApplication extends AsyncConfigurerSupport {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new MdcTaskDecorator());
executor.initialize();
return executor;
}
public static void main(String[] args) {
SpringApplication.run(AsyncTaskdecoratorApplication.class, args);
}
}
Create a bean that will pass the MDC properties from parent thread to the successor thread.
#Configuration
#Slf4j
public class AsyncMDCConfiguration {
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(new MDCTaskDecorator());//MDCTaskDecorator i s a custom created class thet implements TaskDecorator that is reponsible for passing on the MDC properties
executor.initialize();
return executor;
}
}
#Slf4j
public class MDCTaskDecorator implements TaskDecorator {
#Override
public Runnable decorate(Runnable runnable) {
Map<String, String> contextMap = MDC.getCopyOfContextMap();
return () -> {
try {
MDC.setContextMap(contextMap);
runnable.run();
} finally {
MDC.clear();
}
};
}
}
All Good now. Happy Coding
I have some solutions that roughly divided into Callable(for #Async), AsyncExecutionInterceptor(for #Async), CallableProcessingInterceptor(for controller).
1.The Callable solution for putting context infos into #Async thread:
The key is using the ContextAwarePoolExecutor to replace the default executor of #Async:
#Configuration
public class DemoExecutorConfig {
#Bean("demoExecutor")
public Executor contextAwarePoolExecutor() {
return new ContextAwarePoolExecutor();
}
}
And the ContextAwarePoolExecutor overwriting submit and submitListenable methods with ContextAwareCallable inside:
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
private static final long serialVersionUID = 667815067287186086L;
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable<T>(task, newThreadContextContainer()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable<T>(task, newThreadContextContainer()));
}
/**
* set infos what we need
*/
private ThreadContextContainer newThreadContextContainer() {
ThreadContextContainer container = new ThreadContextContainer();
container.setRequestAttributes(RequestContextHolder.currentRequestAttributes());
container.setContextMapOfMDC(MDC.getCopyOfContextMap());
return container;
}
}
The ThreadContextContainer is just a pojo to store infos for convenience:
public class ThreadContextContainer implements Serializable {
private static final long serialVersionUID = -6809291915300091330L;
private RequestAttributes requestAttributes;
private Map<String, String> contextMapOfMDC;
public RequestAttributes getRequestAttributes() {
return requestAttributes;
}
public Map<String, String> getContextMapOfMDC() {
return contextMapOfMDC;
}
public void setRequestAttributes(RequestAttributes requestAttributes) {
this.requestAttributes = requestAttributes;
}
public void setContextMapOfMDC(Map<String, String> contextMapOfMDC) {
this.contextMapOfMDC = contextMapOfMDC;
}
}
The ContextAwareCallable(a Callable proxy for original task) overwriting the call method to storage MDC or other context infos before the original task executing its call method:
public class ContextAwareCallable<T> implements Callable<T> {
/**
* the original task
*/
private Callable<T> task;
/**
* for storing infos what we need
*/
private ThreadContextContainer threadContextContainer;
public ContextAwareCallable(Callable<T> task, ThreadContextContainer threadContextContainer) {
this.task = task;
this.threadContextContainer = threadContextContainer;
}
#Override
public T call() throws Exception {
// set infos
if (threadContextContainer != null) {
RequestAttributes requestAttributes = threadContextContainer.getRequestAttributes();
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes);
}
Map<String, String> contextMapOfMDC = threadContextContainer.getContextMapOfMDC();
if (contextMapOfMDC != null) {
MDC.setContextMap(contextMapOfMDC);
}
}
try {
// execute the original task
return task.call();
} finally {
// clear infos after task completed
RequestContextHolder.resetRequestAttributes();
try {
MDC.clear();
} finally {
}
}
}
}
In the end, using the #Async with the configured bean "demoExecutor" like this: #Async("demoExecutor")
void yourTaskMethod();
2.In regard to your question of handling the response:
Regret to tell that I don't really have a verified solution. Maybe the org.springframework.aop.interceptor.AsyncExecutionInterceptor#invoke is possible to solve that.
And I do not think it has a solution to handle the response with your ServletLoggingFilter. Because the Async method will be returned instantly. The afterRequest method executes immediately and returns before Async method doing things. You won't get what you want unless you synchronously wait for the Async method to finish executing.
But if you just want to log something, you can add those codes into my example ContextAwareCallable after the original task executing its call method:
try {
// execute the original task
return task.call();
} finally {
String something = MDC.get("doSomething"); // will not be null
// logthis(something);
// clear infos after task completed
RequestContextHolder.resetRequestAttributes();
try {
MDC.clear();
} finally {
}
}
I am new to unit test and I am trying to use robolectric to do the test for my android app, but I encountered some problems
DemoPresenterTest
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 23)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(DemoPresenterImpl_.class)
public class DemoPresenterTest {
#Rule
public MockitoRule rule = MockitoJUnit.rule();
private MockDemoNetworkService mMockDemoNetworkService;
private MockLceView mLceView;
private DemoPresenterImpl_ mPresenter;
#Before
public void setup() {
mMockDemoNetworkService = Mockito.mock(MockDemoNetworkService.class);
mLceView = Mockito.mock(MockLceView.class);
PowerMockito.mockStatic(DemoPresenterImpl_.class);
mPresenter = DemoPresenterImpl_.getInstance_(RuntimeEnvironment.application);
mPresenter.service = mMockDemoNetworkService;
mPresenter.view = mLceView;
}
#Test
public void testDownloadData() {
mPresenter.downloadData();
Mockito.verify(mLceView).onError(Mockito.anyInt());
}
}
DemoPresenterImpl
#EBean
public class DemoPresenterImpl implements DemoPresenter {
#Bean(DemoNetworkService.class)
DemoService service;
protected LceView<Demo> view;
/**
* download the data from server for the first time, data will be saved into the database
* and for the next time it will query the database instead
*/
#Override
#Background(delay = 1000)
public void downloadData() {
try {
List<Demo> result = service.getDemoList();
if (result != null) {
view.setData(result);
} // add else if the result is not return empty list but null
} catch (NetworkFailException e) {
view.onError(e.getResponse().getCode());
}
}
#Override
public void attach(LceView<Demo> view) {
this.view = view;
}
}
MockDemoNetworkService
public class MockDemoNetworkService implements DemoService {
#Override
public List<Demo> getDemoList() throws NetworkFailException {
NetworkFailResponse response = new NetworkFailResponse();
response.setCode(500);
throw new NetworkFailException(response);
}
#Override
public boolean setDemoList(List<Demo> demoList) {
return false;
}
}
When I run the test it returns "Cannot subclass final class class com.*.DemoPresenterImpl_", if I change to DemoPresenterImpl, the test can run but the mLceView never get called
Wanted but not invoked: mockLceView.onError();
-> at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:245)
Actually, there were zero interactions with this mock.
am I doing something wrong?
I think you can remove #PrepareForTest, because you are not mocking the presenter, you are actually testing it. Then you should use DemoPresenterImpl_, because it is containing the needed generated code.
I have a simple resource like:
#Path("/")
public class RootResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
assertNotNull(wc);
}
#GET
public void String method() {
return "Hello\n";
}
}
Which I am trying to use with JerseyTest (2.x, not 1.x) and the GrizzlyTestContainerFactory.
I can't work out what I need to do in terms of config to get the WebConfig object injected.
I solved this issue by creating a subclass of GrizzlyTestContainerFactory and explicitly loading the Jersey servlet. This triggers the injection of the WebConfig object. The code looks like this:
public class ExtendedGrizzlyTestContainerFactory implements TestContainerFactory {
private static class GrizzlyTestContainer implements TestContainer {
private final URI uri;
private final ApplicationHandler appHandler;
private HttpServer server;
private static final Logger LOGGER = Logger.getLogger(GrizzlyTestContainer.class.getName());
private GrizzlyTestContainer(URI uri, ApplicationHandler appHandler) {
this.appHandler = appHandler;
this.uri = uri;
}
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return uri;
}
#Override
public void start() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Starting GrizzlyTestContainer...");
}
try {
this.server = GrizzlyHttpServerFactory.createHttpServer(uri, appHandler);
// Initialize and register Jersey Servlet
WebappContext context = new WebappContext("WebappContext", "");
ServletRegistration registration = context.addServlet("ServletContainer", ServletContainer.class);
registration.setInitParameter("javax.ws.rs.Application",
appHandler.getConfiguration().getApplication().getClass().getName());
// Add an init parameter - this could be loaded from a parameter in the constructor
registration.setInitParameter("myparam", "myvalue");
registration.addMapping("/*");
context.deploy(server);
} catch (ProcessingException e) {
throw new TestContainerException(e);
}
}
#Override
public void stop() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Stopping GrizzlyTestContainer...");
}
this.server.stop();
}
}
#Override
public TestContainer create(URI baseUri, ApplicationHandler application) throws IllegalArgumentException {
return new GrizzlyTestContainer(baseUri, application);
}
Notice that the Jersey Servlet configuration is being loaded from the ApplicationHandler that is passed in as a parameter using the inner Application object's class name (ResourceConfig is a subclass of Application). Therefore, you also need to create a subclass of ResourceConfig for this approach to work. The code for this is very simple:
package com.example;
import org.glassfish.jersey.server.ResourceConfig;
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
super(MyResource.class);
}
}
This assumes the resource you are testing is MyResource. You also need to override a couple of methods in your test like this:
public class MyResourceTest extends JerseyTest {
public MyResourceTest() throws TestContainerException {
}
#Override
protected Application configure() {
return new MyResourceConfig();
}
#Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new ExtendedGrizzlyTestContainerFactory();
}
#Test
public void testCreateSimpleBean() {
final String beanList = target("test").request().get(String.class);
Assert.assertNotNull(beanList);
}
}
Finally, for completeness, here is the code for MyResource:
#Path("test")
public class MyResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
System.out.println("WebConfig: " + wc);
String url = wc.getInitParameter("myparam");
System.out.println("myparam = "+url);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Collection<TestBean> createSimpleBean() {
Collection<TestBean> res = new ArrayList<TestBean>();
res.add(new TestBean("a", 1, 1L));
res.add(new TestBean("b", 2, 2L));
return res;
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public TestBean roundTrip(TestBean s) {
return s;
}
}
The output of running the test shows that the WebConfig is loaded and the init param is now available:
WebConfig: org.glassfish.jersey.servlet.WebServletConfig#107d0f44
myparam = myvalue
The solution from #ametke worked well but wasn't picking up my ExceptionMapper classes. To solve this I simplified the start() method to:
#Override
public void start() {
try {
initParams.put("jersey.config.server.provider.packages", "my.resources;my.config");
this.server = GrizzlyWebContainerFactory.create(uri, initParams);
} catch (ProcessingException | IOException e) {
throw new TestContainerException(e);
}
}
This was based on Problems running JerseyTest when dealing with HttpServletResponse
I have built a custom component button, but somehow the action is not invoked. When debugging the getAction-Method within the component and invoking the supplied MethodeExpression the Bean-Method is called as expected. But due to some reason, the Expression is not invoked when pressing the button in the browser.
Is there some kind of additional Interface necessary to pass the action to the embedded button-component?
Any help is very appreciated since I am stuck at this issue for some days now
MyClass:
public class MyClass extends UIPanel implements SystemEventListener
{
private UIForm form;
private HtmlCommandButton buttonOk;
public MyClass()
{
FacesContext context = getFacesContext();
UIViewRoot root = context.getViewRoot();
root.subscribeToViewEvent(PostAddToViewEvent.class, this);
}
#Override
public void processEvent(SystemEvent event)
{
this.form = new UIForm();
this.buttonOk = new HtmlCommandButton();
this.buttonOk.setId("okButtonId");
this.buttonOk.setActionExpression(getAction());
this.buttonOk.setValue("OK");
this.form.getChildren().add(this.buttonOk);
getChildren().add(this.form);
}
private enum PropertyKeys
{
action, text, titel
}
public MethodExpression getAction()
{
return (MethodExpression) getStateHelper().eval(PropertyKeys.action);
}
public void setAction(MethodExpression actionExpression)
{
getStateHelper().put(PropertyKeys.action, actionExpression);
}
public String getText()
{
return (String) getStateHelper().eval(PropertyKeys.text);
}
public void setText(String text)
{
getStateHelper().put(PropertyKeys.text, text);
}
public String getTitel()
{
return (String) getStateHelper().eval(PropertyKeys.titel);
}
public void setTitel(String titel)
{
getStateHelper().put(PropertyKeys.titel, titel);
}
#Override
public void encodeAll(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
writer.startElement(HTML.DIV_ELEM, this);
writer.writeText(getText(), null);
this.form.encodeAll(context);
writer.endElement(HTML.DIV_ELEM);
}
#Override
public void encodeChildren(FacesContext context) throws IOException
{
}
#Override
public boolean isListenerForSource(Object source)
{
return (source instanceof MyClass);
}
}
MyClassHandler:
public class MyClassHandler extends ComponentHandler
{
public MyClassHandler(ComponentConfig config)
{
super(config);
}
#SuppressWarnings("rawtypes")
#Override
protected MetaRuleset createMetaRuleset(Class type)
{
return super.createMetaRuleset(type).addRule(new MethodRule("action", String.class, new Class[] { ActionEvent.class }));
}
}
myView Method:
...
public String myMethod()
{
System.err.println("myMethod");
return "/some/path/yadayada.xhtml";
}
...
MyView.xhtml
<myTag action="#{myView.myMethod}" id="id1" titel="bla" text="bleh" />
Exdending UICommand is enough, since you only want one action to be executed.
You have to provide two additional MethodExpressions via the tag-attributes and within the decode-method you can check which button has been pressed and redirect the particular MethodExpression to the standard-action provided by UICommand. This way, you dont have to worry about the legacy-interface ActionSource, or how Events are broadcasted.
public void decode(FacesContext contex)
{
Map<String,String> map = context.getExternalContext.getRequestParameterMap();
// your rendered buttons need a name you check for
final boolean okPressed = map.containsKey( getClientId + ":ok" );
final boolean cancelPressed = map.containsKey( getClientId + ":cancel" );
if(okPressed || cancelPressed)
{
MethodExpression exp = null;
if(okPressed)
{
exp = getActionOk();
}
else
{
exp = getActionCancel();
}
// redirect to standard action
setActionExpression(exp);
queueEvent(new ActionEvent(this));
}
}
In order to make use of of this you need two attributes (actionOk and actionCancel) which use Method Expressions (setter and getter). Those have to be configured by a ComponentHandler as you did for the action-attribute.
I have run into a pretty strange error that I can't get my head around.
In short: I have an ImporterBean that should read an xml file and then do stuff.
That ImporterBean is "kickstarted" by a ImporterKicker, but when I start the app
the ApplicationBean and EntityManager in the ImporterBean class are null. They are
not injected into that bean. In the KickerBean the ImporterBean and ApplicationBean are injected properly.
See code below and please tell me what I'm doing wrong(Using seam SEAM 2.2.1.CR2).
#SuppressWarnings({"UnusedDeclaration"})
#Name("importerBean")
#AutoCreate
public class ImporterBean {
private static final FilenameFilter ONLY_XML_FILES = (FilenameFilter) new SuffixFileFilter(".xml");
public static final String IN_DIR = "IN";
public static final String ERROR_DIR = "ERROR";
public static final String PROCESSED_DIR = "PROCESSED";
#In(create = true)
public ApplicationBean applicationBean;
#In
private EntityManager entityManager;
#Asynchronous
#Transactional
public void runImport(#Duration long firstStart, #IntervalDuration long startTimer) {
log.info("<118100>");
File inDir = Doing some file stuff...
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Inner class bean to kick the background tasks.
*/
#Startup
#Scope(APPLICATION)
#Name("importerKicker")
public static class ImporterKicker {
#In(create = true)
public ImporterBean importerBean;
#In(create = true)
public ApplicationBean applicationBean;
#Create
public void scheduleOptimizer() {
final int interval = applicationBean.getImporter118checkInterval();
if (interval != 0) {
importerBean.runImport(30 * MILLIS_PER_SECOND, interval * MILLIS_PER_SECOND);
} else {
}
}
}
}
This error was a symptom of this:
FullTextHibernateSessionProxy is not visible from class loader
Since you are using an Asynchronous call, you cannot use injections like that in an event scoped component.
Instead inside the Asyncrhonous method write:
#Asynchronous
#Transactional
public void runImport(#Duration long firstStart, #IntervalDuration long startTimer) {
EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
ApplicationBean applicationBean = (ApplicationBean) Component.getInstance("applicationBean",true);
log.info("<118100>");
File inDir = Doing some file stuff...
}
} catch (Exception e) {
e.printStackTrace();
}
}
}