You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/06/04 06:45:21 UTC

[isis] branch master updated (5bf49c6 -> 7b0fafa)

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

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


    from 5bf49c6  ISIS-1960: Introduces a ForkingInvocationHandler that executes actions in the background
     new 272a619  ISIS-1960: Adding background error handling
     new 7b0fafa  ISIS-1961: intercepting by 'magic text' handling tomcat-9 and payara-4

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../core/webapp/content/ResourceCachingFilter.java |  29 ++-
 .../background/BackgroundServiceDefault.java       | 222 ++++++++++++---------
 .../background/ForkingInvocationHandler.java       |  15 +-
 3 files changed, 166 insertions(+), 100 deletions(-)

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

[isis] 01/02: ISIS-1960: Adding background error handling

Posted by ah...@apache.org.
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 <ah...@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
ahuber@apache.org.

[isis] 02/02: ISIS-1961: intercepting by 'magic text' handling tomcat-9 and payara-4

Posted by ah...@apache.org.
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 7b0fafa64b4208e60e76374d10d872794a198d93
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Jun 4 08:45:07 2018 +0200

    ISIS-1961: intercepting by 'magic text' handling tomcat-9 and payara-4
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1961
---
 .../core/webapp/content/ResourceCachingFilter.java | 29 +++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/webapp/content/ResourceCachingFilter.java b/core/metamodel/src/main/java/org/apache/isis/core/webapp/content/ResourceCachingFilter.java
index 1d0ed24..0d9c81d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/webapp/content/ResourceCachingFilter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/webapp/content/ResourceCachingFilter.java
@@ -226,7 +226,19 @@ public class ResourceCachingFilter implements Filter {
             httpResponse.addHeader(EXPIRES_HEADER, httpDateFormat.format(new Date(now + (this.cacheTime.longValue() * MILLISECONDS_IN_SECOND))));
         }
         httpRequest.setAttribute(REQUEST_ATTRIBUTE, true);
-        chain.doFilter(servletRequest, servletResponse);
+        
+        // try to suppress java.io.IOException of kind 'client connection abort'
+        // 1) the TCP protocol (by design) does not provide a means to check, whether a 
+        //    connection has been closed by the client
+        // 2) the exception thrown and the exception message text are specific to the 
+        //    servlet-engine implementation, so we can only guess here
+        try {
+        	chain.doFilter(servletRequest, servletResponse);
+        } catch (IOException e) {
+        	if(!isConnectionAbortException(e)) {
+        		throw e;
+        	}
+		}
     }
 
     /**
@@ -237,5 +249,20 @@ public class ResourceCachingFilter implements Filter {
     @Override
     public void destroy() {
     }
+    
+    // -- HELPER
+    
+    private boolean isConnectionAbortException(IOException e) {
+    	// tomcat 9
+    	if(e.getMessage().contains("An established connection was aborted by the software in your host machine")) {
+    		return true;
+    	}
+    	// payara 4
+    	if(e.getMessage().contains("Connection is closed")) {
+    		return true;
+    	}
+    	
+    	return false;
+    }
 
 }

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