This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 272a6198a28d643a8f5ef8e0519ee6a154caecbe
Author: Andi Huber <ahu...@apache.org>
AuthorDate: Mon Jun 4 08:36:54 2018 +0200

    ISIS-1960: Adding background error handling
    
    also init thread-pool only if required
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1960
---
 .../background/BackgroundServiceDefault.java       | 222 ++++++++++++---------
 .../background/ForkingInvocationHandler.java       |  15 +-
 2 files changed, 138 insertions(+), 99 deletions(-)

diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
index 14cf750..75d20b3 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundServiceDefault.java
@@ -16,6 +16,8 @@
  */
 package org.apache.isis.core.runtime.services.background;
 
+import static org.apache.isis.commons.internal.base._Casts.uncheckedCast;
+
 import java.lang.reflect.InvocationHandler;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -33,7 +35,6 @@ import 
org.apache.isis.applib.services.background.BackgroundService2;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.commons.internal._Constants;
-import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.core.commons.lang.ArrayExtensions;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import 
org.apache.isis.core.metamodel.services.command.CommandDtoServiceInternal;
@@ -42,92 +43,117 @@ import 
org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import 
org.apache.isis.core.metamodel.specloader.classsubstitutor.ProxyEnhanced;
 import org.apache.isis.core.plugins.codegen.ProxyFactory;
 import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Depends on an implementation of {@link 
org.apache.isis.applib.services.background.BackgroundCommandService} to
+ * For command-reification depends on an implementation of 
+ * {@link org.apache.isis.applib.services.background.BackgroundCommandService} 
to
  * be configured.
  */
 @DomainService(
-        nature = NatureOfService.DOMAIN,
-        menuOrder = "" + Integer.MAX_VALUE
-)
+               nature = NatureOfService.DOMAIN,
+               menuOrder = "" + Integer.MAX_VALUE
+               )
 public class BackgroundServiceDefault implements BackgroundService2 {
-
-       private final int threadCount = 
Runtime.getRuntime().availableProcessors();
        
-       private final ExecutorService backgroundExecutorService = 
-                       Executors.newFixedThreadPool(threadCount);
-       
-    @Programmatic
-    @PostConstruct
-    public void init(Map<String,String> props) {
-    }
-
-    @Programmatic
-    @PreDestroy
-    public void shutdown() {
-       backgroundExecutorService.shutdownNow();
-    }
-    
-    ObjectSpecification getSpecification(final Class<?> type) {
-        return specificationLoader.loadSpecification(type);
-    }
-
-    // //////////////////////////////////////
-
-    @Programmatic
-    @Override
-    public <T> T execute(final T domainObject) {
-        final Class<T> cls = _Casts.uncheckedCast(domainObject.getClass());
-        final InvocationHandler methodHandler = newMethodHandler(domainObject, 
null);
-        return newProxy(cls, null, methodHandler);
-    }
-
-    @Override
-    public <T> T executeMixin(Class<T> mixinClass, Object mixedIn) {
-        final T mixin = factoryService.mixin(mixinClass, mixedIn);
-        final InvocationHandler methodHandler = newMethodHandler(mixin, 
mixedIn);
-        return newProxy(mixinClass, mixedIn, methodHandler);
-    }
-
-    private <T> T newProxy(
-            final Class<T> cls,
-            final Object mixedInIfAny,
-            final InvocationHandler methodHandler) {
-
-       final Class<?>[] interfaces = ArrayExtensions.combine(
-                       cls.getInterfaces(), 
-                       new Class<?>[] { ProxyEnhanced.class }); 
-       
-       final boolean initialize = mixedInIfAny!=null;
-       
-       
-        final Class<?>[] constructorArgTypes = initialize ? new Class<?>[] 
{mixedInIfAny.getClass()} : _Constants.emptyClasses;
-        final Object[] constructorArgs = initialize ? new Object[] 
{mixedInIfAny} : _Constants.emptyObjects;
-        
-        final ProxyFactory<T> proxyFactory = ProxyFactory.builder(cls)
-                       .interfaces(interfaces)
-                       .constructorArgTypes(constructorArgTypes)
-                       .build();
-        
-        return initialize 
-                       ? proxyFactory.createInstance(methodHandler, 
constructorArgs)  
-                       : proxyFactory.createInstance(methodHandler, false)
-                       ;
-    }
-
-    /**
-     *
-     * @param target - the object that is proxied, either a domain object or a 
mixin around a domain object
-     * @param mixedInIfAny - if target is a mixin, then this is the domain 
object that is mixed-in to.
-     */
-    private <T> InvocationHandler newMethodHandler(final T target, final 
Object mixedInIfAny) {
-       
-       if(backgroundCommandService==null) {
-               return new ForkingInvocationHandler<T>(target, mixedInIfAny, 
backgroundExecutorService);
-       }
-       
-       return new CommandInvocationHandler<T>(
+       static final Logger LOG = 
LoggerFactory.getLogger(BackgroundServiceDefault.class);
+
+       /*
+        * For the fixed thread-pool let there be 1-4 concurrent threads,
+        * limited by the number of available (logical) processor cores.
+        * 
+        * Note: Future improvements might make these values configurable, 
+        * but for now lets try to be reasonably nice here.
+        * 
+        */
+       private final int minThreadCount = 1; // only used if there is no 
BackgroundCommandService
+       private final int maxThreadCount = 4; // only used if there is no 
BackgroundCommandService
+
+       private final int threadCount = // only used if there is no 
BackgroundCommandService
+                       Math.max(minThreadCount, 
+                                       Math.min(maxThreadCount,
+                                                       
Runtime.getRuntime().availableProcessors()));
+
+       // only used if there is no BackgroundCommandService
+       private ExecutorService backgroundExecutorService; 
+
+       @Programmatic
+       @PostConstruct
+       public void init(Map<String,String> props) {
+               if(backgroundCommandService==null) {
+                       backgroundExecutorService = 
Executors.newFixedThreadPool(threadCount);  
+               }
+       }
+
+       @Programmatic
+       @PreDestroy
+       public void shutdown() {
+               if(backgroundExecutorService!=null) {
+                       backgroundExecutorService.shutdownNow();
+                       backgroundExecutorService = null;
+               }
+       }
+
+       ObjectSpecification getSpecification(final Class<?> type) {
+               return specificationLoader.loadSpecification(type);
+       }
+
+       // //////////////////////////////////////
+
+       @Programmatic
+       @Override
+       public <T> T execute(final T domainObject) {
+               final Class<T> cls = uncheckedCast(domainObject.getClass());
+               final InvocationHandler methodHandler = 
newMethodHandler(domainObject, null);
+               return newProxy(cls, null, methodHandler);
+       }
+
+       @Override
+       public <T> T executeMixin(Class<T> mixinClass, Object mixedIn) {
+               final T mixin = factoryService.mixin(mixinClass, mixedIn);
+               final InvocationHandler methodHandler = newMethodHandler(mixin, 
mixedIn);
+               return newProxy(mixinClass, mixedIn, methodHandler);
+       }
+
+       private <T> T newProxy(
+                       final Class<T> cls,
+                       final Object mixedInIfAny,
+                       final InvocationHandler methodHandler) {
+
+               final Class<?>[] interfaces = ArrayExtensions.combine(
+                               cls.getInterfaces(), 
+                               new Class<?>[] { ProxyEnhanced.class }); 
+
+               final boolean initialize = mixedInIfAny!=null;
+
+
+               final Class<?>[] constructorArgTypes = initialize ? new 
Class<?>[] {mixedInIfAny.getClass()} : _Constants.emptyClasses;
+               final Object[] constructorArgs = initialize ? new Object[] 
{mixedInIfAny} : _Constants.emptyObjects;
+
+               final ProxyFactory<T> proxyFactory = ProxyFactory.builder(cls)
+                               .interfaces(interfaces)
+                               .constructorArgTypes(constructorArgTypes)
+                               .build();
+
+               return initialize 
+                               ? proxyFactory.createInstance(methodHandler, 
constructorArgs)  
+                                               : 
proxyFactory.createInstance(methodHandler, false)
+                                               ;
+       }
+
+       /**
+        *
+        * @param target - the object that is proxied, either a domain object 
or a mixin around a domain object
+        * @param mixedInIfAny - if target is a mixin, then this is the domain 
object that is mixed-in to.
+        */
+       private <T> InvocationHandler newMethodHandler(final T target, final 
Object mixedInIfAny) {
+
+               if(backgroundCommandService==null) {
+                       return new ForkingInvocationHandler<T>(target, 
mixedInIfAny, backgroundExecutorService);
+               }
+
+               return new CommandInvocationHandler<T>(
                                (BackgroundCommandService2) 
backgroundCommandService, 
                                target, 
                                mixedInIfAny, 
@@ -135,32 +161,32 @@ public class BackgroundServiceDefault implements 
BackgroundService2 {
                                commandDtoServiceInternal,
                                commandContext,
                                this::getAdapterManager);
-       
-    }
+
+       }
 
 
-    // //////////////////////////////////////
+       // //////////////////////////////////////
 
-    @javax.inject.Inject
-    private BackgroundCommandService backgroundCommandService;
+       @javax.inject.Inject
+       private BackgroundCommandService backgroundCommandService;
 
-    @javax.inject.Inject
-    private CommandDtoServiceInternal commandDtoServiceInternal;
+       @javax.inject.Inject
+       private CommandDtoServiceInternal commandDtoServiceInternal;
 
-    @javax.inject.Inject
-    private CommandContext commandContext;
+       @javax.inject.Inject
+       private CommandContext commandContext;
 
-    @javax.inject.Inject
-    private FactoryService factoryService;
+       @javax.inject.Inject
+       private FactoryService factoryService;
 
-    @javax.inject.Inject
-    private SpecificationLoader specificationLoader;
+       @javax.inject.Inject
+       private SpecificationLoader specificationLoader;
 
-    @javax.inject.Inject
-    private IsisSessionFactory isisSessionFactory;
+       @javax.inject.Inject
+       private IsisSessionFactory isisSessionFactory;
 
-    protected AdapterManager getAdapterManager() {
-        return isisSessionFactory.getCurrentSession().getPersistenceSession();
-    }
+       protected AdapterManager getAdapterManager() {
+               return 
isisSessionFactory.getCurrentSession().getPersistenceSession();
+       }
 
 }
diff --git 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
index 9ac2593..aa4bbc3 100644
--- 
a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
+++ 
b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
@@ -62,7 +62,20 @@ class ForkingInvocationHandler<T> implements 
InvocationHandler {
         }
         
         backgroundExecutorService.submit(()->{
-               
IsisContext.getSessionFactory().doInSession(()->proxyMethod.invoke(domainObject,
 args));
+               
+               try {
+                       
+                       IsisContext.getSessionFactory().doInSession(
+                               ()->proxyMethod.invoke(domainObject, args));
+                       
+               } catch (Exception e) {
+                       // log in caller's context                      
+                       BackgroundServiceDefault.LOG.error(
+                                       String.format("Background execution of 
action '%s' on object '%s' failed.", 
+                                                       proxyMethod.getName(),
+                                                       
domainObject.getClass().getName()),
+                                       e);
+                       }
        }); 
 
         return null;

-- 
To stop receiving notification emails like this one, please contact
ahu...@apache.org.

Reply via email to