From 1c21abc100dda913dba0f4d6ad1302d87d14521e Mon Sep 17 00:00:00 2001 From: Andreas Kohlbecker Date: Wed, 5 Feb 2020 11:25:46 +0100 Subject: [PATCH] ref #8842 replacing caching in CdmServiceRequestExecutor by CachingHttpInvokerProxyFactoryBean to avoid having states --- .../CdmApplicationRemoteConfiguration.java | 27 +-- .../cdm/api/cache/CdmServiceCacher.java | 5 +- .../remoting/source/CdmServerInfo.java | 1 + .../service/CdmServiceRequestExecutor.java | 101 +--------- .../service/IRemoteInvocationTermCacher.java | 33 ++++ .../service/RemoteInvocationTermCacher.java | 56 ++++++ .../service/TermServiceRequestExecutor.java | 32 --- .../session/CdmEntitySessionManager.java | 34 ---- .../taxeditor/session/ICdmEntitySession.java | 3 + .../session/ICdmEntitySessionManager.java | 7 +- .../CachingHttpInvokerProxyFactoryBean.java | 183 ++++++++++++++++++ 11 files changed, 302 insertions(+), 180 deletions(-) create mode 100644 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/IRemoteInvocationTermCacher.java create mode 100644 eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/RemoteInvocationTermCacher.java create mode 100644 eu.etaxonomy.taxeditor.cdmlib/src/main/java/org/springframework/remoting/httpinvoker/CachingHttpInvokerProxyFactoryBean.java diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java index 7c0765ba7..bf6a876fa 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/application/CdmApplicationRemoteConfiguration.java @@ -19,8 +19,8 @@ import org.apache.log4j.Logger; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.remoting.httpinvoker.CachingHttpInvokerProxyFactoryBean; import org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor; -import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean; import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.ProviderManager; @@ -92,7 +92,7 @@ import eu.etaxonomy.taxeditor.service.CachedCommonServiceImpl; import eu.etaxonomy.taxeditor.service.CdmAuthenticatedHttpInvokerRequestExecutor; import eu.etaxonomy.taxeditor.service.CdmServiceRequestExecutor; import eu.etaxonomy.taxeditor.service.ICachedCommonService; -import eu.etaxonomy.taxeditor.service.TermServiceRequestExecutor; +import eu.etaxonomy.taxeditor.service.RemoteInvocationTermCacher; import eu.etaxonomy.taxeditor.session.CdmEntitySessionManager; import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; @@ -103,9 +103,11 @@ import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; * */ @Component -// TODO split configurations into proper @Configuration class +// TODO split into CdmRepository and proper @Configuration class public class CdmApplicationRemoteConfiguration implements ICdmRepository, ApplicationContextAware { + private static final int HTTP_READ_TIMEOUT = 0; + @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(CdmApplicationRemoteConfiguration.class); @@ -155,15 +157,18 @@ public class CdmApplicationRemoteConfiguration implements ICdmRepository, Applic } else { baseUrl = "http://" + remoteSource.getServer() + ":" + String.valueOf(remoteSource.getPort()) + "/" + remoteSource.getContextPath(); } - HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean(); - proxy.setServiceInterface(clazz); - proxy.setServiceUrl(baseUrl + serviceSuffix); + CachingHttpInvokerProxyFactoryBean proxyFactory = new CachingHttpInvokerProxyFactoryBean(); + proxyFactory.setServiceInterface(clazz); + proxyFactory.setServiceUrl(baseUrl + serviceSuffix); if(executor != null) { - executor.setReadTimeout(0); - proxy.setHttpInvokerRequestExecutor(executor); + executor.setReadTimeout(HTTP_READ_TIMEOUT); + proxyFactory.setHttpInvokerRequestExecutor(executor); + } + if(ITermService.class.isAssignableFrom(clazz)){ + proxyFactory.setRemoteInvocationTermCacher(new RemoteInvocationTermCacher()); } - proxy.afterPropertiesSet(); - return proxy.getObject(); + proxyFactory.afterPropertiesSet(); + return proxyFactory.getObject(); } // ****************************** APPLICATION CONTEXT *************************************************/ @@ -297,7 +302,7 @@ public class CdmApplicationRemoteConfiguration implements ICdmRepository, Applic @Override public ITermService getTermService(){ - return (ITermService) getService(ITermService.class, "/remoting/term.service", new TermServiceRequestExecutor()); + return (ITermService) getService(ITermService.class, "/remoting/term.service", new CdmServiceRequestExecutor()); } @Override diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java index d554e612a..559039dd1 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/cdm/api/cache/CdmServiceCacher.java @@ -15,7 +15,7 @@ import eu.etaxonomy.cdm.config.ConfigFileUtil; import eu.etaxonomy.cdm.model.common.CdmBase; import eu.etaxonomy.cdm.model.term.DefinedTermBase; import eu.etaxonomy.cdm.model.term.TermBase; -import eu.etaxonomy.taxeditor.service.TermServiceRequestExecutor; +import eu.etaxonomy.taxeditor.service.RemoteInvocationTermCacher; import eu.etaxonomy.taxeditor.session.CdmEntitySession; import eu.etaxonomy.taxeditor.session.ICdmEntitySession; import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; @@ -53,7 +53,8 @@ public class CdmServiceCacher extends CdmCacher implements ICdmEntitySessionMana DefinedTermBase.setCacher(this); CdmTransientEntityCacher.setPermanentCacher(this); - TermServiceRequestExecutor.setDefaultCacher(this); + //TermServiceRequestExecutor.setDefaultCacher(this); + RemoteInvocationTermCacher.setDefaultCacher(this); cacheLoader = new CacheLoader(this); } diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/source/CdmServerInfo.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/source/CdmServerInfo.java index e3dcb7808..066f0c93d 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/source/CdmServerInfo.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/remoting/source/CdmServerInfo.java @@ -284,6 +284,7 @@ public class CdmServerInfo { return true; } } catch (CdmSourceException e) { + logger.error(e.getMessage(), e); throw new CDMServerException(e); } diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/CdmServiceRequestExecutor.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/CdmServiceRequestExecutor.java index 5335475d6..2ed9cf696 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/CdmServiceRequestExecutor.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/CdmServiceRequestExecutor.java @@ -1,106 +1,7 @@ package eu.etaxonomy.taxeditor.service; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashSet; -import java.util.Set; - -import org.apache.http.NoHttpResponseException; -import org.apache.log4j.Logger; -import org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationResult; -import org.springframework.stereotype.Component; - -import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController; -import eu.etaxonomy.cdm.api.application.CdmApplicationState; -import eu.etaxonomy.cdm.api.service.UpdateResult; -import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; - -@Component +// @Component public class CdmServiceRequestExecutor extends CdmAuthenticatedHttpInvokerRequestExecutor { - private static final Logger logger = Logger.getLogger(CdmServiceRequestExecutor.class); - - private ICdmEntitySessionManager cdmEntitySessionManager ; - - private RemoteInvocation currentRemoteInvocation; - - protected final static Set cachableMethods = new HashSet(); - - - - public CdmServiceRequestExecutor() { - cachableMethods.add("merge"); - cachableMethods.add("save"); - cachableMethods.add("findWithUpdate"); - cachableMethods.add("loadWithUpdate"); - } - - @Override - protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException { - if(cdmEntitySessionManager == null) { - cdmEntitySessionManager = - ((CdmApplicationRemoteController)CdmApplicationState.getCurrentAppConfig()).getCdmEntitySessionManager(); - } - currentRemoteInvocation = invocation; - super.writeRemoteInvocation(invocation, os); - } - - @Override - protected RemoteInvocationResult doExecuteRequest(HttpInvokerClientConfiguration config, - java.io.ByteArrayOutputStream baos) - throws java.io.IOException, - java.lang.ClassNotFoundException, NoHttpResponseException { - RemoteInvocationResult rir = fromCache(currentRemoteInvocation); - - if(rir == null) { - - if (!(currentRemoteInvocation.getMethodName() == null) && !(config.getServiceUrl() == null)){ - // logger.info("Remote invoking : " + currentRemoteInvocation.getMethodName() + "@" + config.getServiceUrl()); - } - try{ - rir = super.doExecuteRequest(config, baos); - }catch(Exception e){ - if (e instanceof NoHttpResponseException){ - throw e; - } - } - if(rir.getValue() != null && !rir.hasException()) { - if (currentRemoteInvocation == null){ - logger.debug("return RemoteInvocationResult without caching" ); - return rir; - } - if(cachableMethods.contains(currentRemoteInvocation.getMethodName())) { - rir = new RemoteInvocationResult(cdmEntitySessionManager.load(rir.getValue(), true)); - } else if(rir.getValue() instanceof UpdateResult){ - UpdateResult result = (UpdateResult)rir.getValue(); - if(result.isOk()){ - cdmEntitySessionManager.load(result, true); - } - } else { - rir = new RemoteInvocationResult(cdmEntitySessionManager.load(rir.getValue(), false)); - } - } - cache(currentRemoteInvocation, rir); - } - currentRemoteInvocation = null; - - return rir; - } - - public void cache(RemoteInvocation ri, RemoteInvocationResult rir) { - - } - - public RemoteInvocationResult fromCache(RemoteInvocation ri) { - return null; - } - - @Override - public void setReadTimeout(int timeout) { - logger.info("Read time our set to: " + timeout + " ms"); - super.setReadTimeout(timeout); - } } diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/IRemoteInvocationTermCacher.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/IRemoteInvocationTermCacher.java new file mode 100644 index 000000000..7b4b8bd11 --- /dev/null +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/IRemoteInvocationTermCacher.java @@ -0,0 +1,33 @@ +/** +* Copyright (C) 2020 EDIT +* European Distributed Institute of Taxonomy +* http://www.e-taxonomy.eu +* +* The contents of this file are subject to the Mozilla Public License Version 1.1 +* See LICENSE.TXT at the top of this package for the full license terms. +*/ +package eu.etaxonomy.taxeditor.service; + +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +/** + * @author a.kohlbecker + * @since Feb 4, 2020 + * + */ +public interface IRemoteInvocationTermCacher { + + /** + * @param ri + * @param rir + */ + void cacheTerms(RemoteInvocation ri, RemoteInvocationResult rir); + + /** + * @param ri + * @return + */ + RemoteInvocationResult termsFromCache(RemoteInvocation ri); + +} diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/RemoteInvocationTermCacher.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/RemoteInvocationTermCacher.java new file mode 100644 index 000000000..f1d1561b4 --- /dev/null +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/RemoteInvocationTermCacher.java @@ -0,0 +1,56 @@ +package eu.etaxonomy.taxeditor.service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +import eu.etaxonomy.cdm.api.cache.CdmServiceCacher; +import eu.etaxonomy.cdm.model.term.DefinedTermBase; +import eu.etaxonomy.cdm.model.term.TermType; + + +public class RemoteInvocationTermCacher implements IRemoteInvocationTermCacher { + private static final Logger logger = Logger.getLogger(RemoteInvocationTermCacher.class); + + private static Map termTypeMap = new HashMap<>(); + + private static CdmServiceCacher cdmServiceCacher; + + public static void setDefaultCacher(CdmServiceCacher csc) { + cdmServiceCacher = csc; + } + + @Override + public void cacheTerms(RemoteInvocation ri, RemoteInvocationResult rir) { + if(cdmServiceCacher != null) { + if(ri.getMethodName().equals("listByTermType")) { + if(ri.getArguments()[1] == null) { + Set> terms = new HashSet<>(); + if(rir.getValue() != null) { + terms.addAll((List>)rir.getValue()); + + for(DefinedTermBase term : terms) { + cdmServiceCacher.load(term); + } + termTypeMap.put((TermType)ri.getArguments()[0], rir); + } + + } + } + } else { + logger.info("Default CdmServiceCacher is null. Cannot cache terms"); + } + } + + @Override + public RemoteInvocationResult termsFromCache(RemoteInvocation ri) { + return termTypeMap.get(ri.getArguments()[0]); + } + +} diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/TermServiceRequestExecutor.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/TermServiceRequestExecutor.java index 714d17d24..bce159d30 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/TermServiceRequestExecutor.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/service/TermServiceRequestExecutor.java @@ -1,17 +1,12 @@ package eu.etaxonomy.taxeditor.service; import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.log4j.Logger; -import org.springframework.remoting.support.RemoteInvocation; import org.springframework.remoting.support.RemoteInvocationResult; import eu.etaxonomy.cdm.api.cache.CdmServiceCacher; -import eu.etaxonomy.cdm.model.term.DefinedTermBase; import eu.etaxonomy.cdm.model.term.TermType; @@ -26,31 +21,4 @@ public class TermServiceRequestExecutor extends CdmServiceRequestExecutor { cdmServiceCacher = csc; } - @Override - public void cache(RemoteInvocation ri, RemoteInvocationResult rir) { - if(cdmServiceCacher != null) { - if(ri.getMethodName().equals("listByTermType")) { - if(ri.getArguments()[1] == null) { - Set> terms = new HashSet<>(); - if(rir.getValue() != null) { - terms.addAll((List>)rir.getValue()); - - for(DefinedTermBase term : terms) { - cdmServiceCacher.load(term); - } - termTypeMap.put((TermType)ri.getArguments()[0], rir); - } - - } - } - } else { - logger.info("Default CdmServiceCacher is null. Cannot cache terms"); - } - } - - @Override - public RemoteInvocationResult fromCache(RemoteInvocation ri) { - return termTypeMap.get(ri.getArguments()[0]); - } - } diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java index 5494552ef..8f10670ab 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/CdmEntitySessionManager.java @@ -86,19 +86,11 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { notifyObservers(); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#getSessions() - */ @Override public Collection getSessions() { return ownerSessionMap.values(); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#bind(eu.etaxonomy.taxeditor.session.ISessionEventListener) - */ @Override public void bind(ICdmEntitySessionEnabled sessionOwner) { if(sessionOwner == null) { @@ -119,10 +111,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { return ownerSessionMap.containsKey(sessionOwner); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#load(T) - */ @Override public T load(T obj, boolean update) { if(tlActiveSession.get() == null) { @@ -132,7 +120,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { } } - @Override public void update() { if(tlActiveSession.get() != null) { @@ -140,9 +127,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { } } - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#load(T) - */ @Override public T load(T cdmBase, boolean update) { if(tlActiveSession.get() == null) { @@ -151,10 +135,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { return tlActiveSession.get().load(cdmBase, update); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#load(eu.etaxonomy.cdm.api.service.UpdateResult, boolean) - */ @Override public UpdateResult load(UpdateResult updateResult, boolean update) { if(tlActiveSession.get() == null) { @@ -163,10 +143,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { return tlActiveSession.get().load(updateResult, update); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#load(eu.etaxonomy.cdm.persistence.dto.MergeResult, boolean) - */ @Override public MergeResult load(MergeResult mergeResult, boolean update) { if(tlActiveSession.get() == null) { @@ -175,10 +151,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { return tlActiveSession.get().load(mergeResult, update); } - - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#load(java.util.Collection) - */ @Override public Collection load(Collection cdmBaseList, boolean update) { if(tlActiveSession.get() == null) { @@ -236,9 +208,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { notifyObservers(); } - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#addSessionListener() - */ @Override public void addSessionObserver(ICdmEntitySessionManagerObserver sessionObserver) { sessionObservers.add(sessionObserver); @@ -250,9 +219,6 @@ public class CdmEntitySessionManager implements ICdmEntitySessionManager { } } - /* (non-Javadoc) - * @see eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager#isRemoting() - */ @Override public boolean isRemoting() { // FIXME:Remoting stupid method to check whether we are in remoting diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySession.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySession.java index 92d4d5cd0..d424a557b 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySession.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySession.java @@ -19,6 +19,9 @@ public interface ICdmEntitySession { public O load(O obj, boolean update); + /** + * @see eu.etaxonomy.cdm.cache.CdmTransientEntityCacher#load(Collection, boolean) + */ public T load(T cdmBase, boolean update); public UpdateResult load(UpdateResult updateResult, boolean update); diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySessionManager.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySessionManager.java index 2b890d239..a865a5379 100644 --- a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySessionManager.java +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/eu/etaxonomy/taxeditor/session/ICdmEntitySessionManager.java @@ -20,9 +20,14 @@ public interface ICdmEntitySessionManager { public abstract void bind(ICdmEntitySessionEnabled sessionOwner); + /** + * @see eu.etaxonomy.cdm.cache.CdmTransientEntityCacher#load(Collection, boolean) + */ public abstract T load(T obj, boolean update); - + /** + * @see eu.etaxonomy.cdm.cache.CdmTransientEntityCacher#load(Collection, boolean) + */ public abstract T load(T cdmBase, boolean update); diff --git a/eu.etaxonomy.taxeditor.cdmlib/src/main/java/org/springframework/remoting/httpinvoker/CachingHttpInvokerProxyFactoryBean.java b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/org/springframework/remoting/httpinvoker/CachingHttpInvokerProxyFactoryBean.java new file mode 100644 index 000000000..3f49d3db6 --- /dev/null +++ b/eu.etaxonomy.taxeditor.cdmlib/src/main/java/org/springframework/remoting/httpinvoker/CachingHttpInvokerProxyFactoryBean.java @@ -0,0 +1,183 @@ +/** +* Copyright (C) 2020 EDIT +* European Distributed Institute of Taxonomy +* http://www.e-taxonomy.eu +* +* The contents of this file are subject to the Mozilla Public License Version 1.1 +* See LICENSE.TXT at the top of this package for the full license terms. +*/ +package org.springframework.remoting.httpinvoker; + +import java.util.HashSet; +import java.util.Set; + +import org.aopalliance.intercept.MethodInvocation; +import org.apache.log4j.Logger; +import org.springframework.remoting.support.RemoteInvocation; +import org.springframework.remoting.support.RemoteInvocationResult; + +import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController; +import eu.etaxonomy.cdm.api.application.CdmApplicationState; +import eu.etaxonomy.cdm.api.service.ITermService; +import eu.etaxonomy.cdm.api.service.UpdateResult; +import eu.etaxonomy.taxeditor.service.IRemoteInvocationTermCacher; +import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager; + +/** + * Extension of the HttpInvokerProxyFactoryBean to support caching of general CDM entities and terms. + *

+ * Performance measurement:
+ * Supports measuring the request processing time at the client side. Setting "{@value #PROP_KEY_MEASURE_DURATION}" + * as system parameter enables the measurement. To make the measurements appear in the log, the log Level + * for this class needs to be set to at least {@link org.apache.log4j.Level#INFO} + * + * + * @author a.kohlbecker + * @since Feb 4, 2020 + * + */ +public class CachingHttpInvokerProxyFactoryBean extends HttpInvokerProxyFactoryBean { + + private static final String PROP_KEY_MEASURE_DURATION = "remoting.httpinvoker.measureDuration"; + + private static final Logger logger = Logger.getLogger(CachingHttpInvokerProxyFactoryBean.class); + + private ICdmEntitySessionManager cdmEntitySessionManager; + + private IRemoteInvocationTermCacher remoteInvocationTermCacher; + + protected final static Set persistingMethods = new HashSet(); + + protected static boolean measureDuration = false; + + static { + persistingMethods.add("merge"); + persistingMethods.add("save"); + persistingMethods.add("findWithUpdate"); + persistingMethods.add("loadWithUpdate"); + measureDuration = System.getProperty(PROP_KEY_MEASURE_DURATION) != null; + } + + @Override + protected RemoteInvocationResult executeRequest( + RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception { + + // logger.setLevel(Level.INFO); + + if (!(invocation.getMethodName() == null) && !(getServiceUrl() == null) && logger.isDebugEnabled()){ + logger.debug("Remote invoking : " + getServiceUrl() + "#" + invocation.getMethodName()); + } + + if(CdmApplicationState.getCurrentAppConfig() == null){ + logger.debug("No application context yet, no point caching!"); + return doExecuteRequest(invocation, originalInvocation); + } + + // A) if this is a term service call for term lists try to get the terms from the cache + if(ITermService.class.isAssignableFrom(originalInvocation.getMethod().getDeclaringClass())){ + return handleTermRequest(invocation, originalInvocation); + } + // B) handle other service calls + else { + return handleGeneralRequest(invocation, originalInvocation); + } + } + + /** + * @param invocation + * @param originalInvocation + * @return + * @throws Exception + */ + private RemoteInvocationResult handleGeneralRequest(RemoteInvocation invocation, + MethodInvocation originalInvocation) throws Exception { + RemoteInvocationResult invocationResult = doExecuteRequest(invocation, originalInvocation); + if(invocationResult.getValue() != null && !invocationResult.hasException()) { + + if(persistingMethods.contains(invocation.getMethodName())) { + invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), true)); + logger.debug("Entity cached with updating cached data"); + } else if(invocationResult.getValue() instanceof UpdateResult){ + UpdateResult result = (UpdateResult)invocationResult.getValue(); + if(result.isOk()){ + logger.debug("Entity from UpdateResult stored in cache with updating cached data" ); + cdmEntitySessionManager().load(result.getCdmEntity(), true); + } + } else { + invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), false)); + logger.debug("Entity cached without updating cached data" ); + } + + } + return invocationResult; + } + + /** + * @param invocation + * @param originalInvocation + * @return + * @throws Exception + */ + private RemoteInvocationResult handleTermRequest(RemoteInvocation invocation, MethodInvocation originalInvocation) + throws Exception { + RemoteInvocationResult invocationResult = null; + if(remoteInvocationTermCacher != null){ + invocationResult = remoteInvocationTermCacher.termsFromCache(invocation); + if(invocationResult == null) { + invocationResult = doExecuteRequest(invocation, originalInvocation); + remoteInvocationTermCacher.cacheTerms(invocation, invocationResult); + logger.debug("Term list loaded and cached"); + } else { + logger.debug("Term list found in cache, not loaded"); + } + } else { + logger.warn("Term list: No IRemoteInvocationTermCacher configured"); + invocationResult = doExecuteRequest(invocation, originalInvocation); + } + return invocationResult; + } + + /** + * @param invocation + * @param originalInvocation + * @return + * @throws Exception + */ + private RemoteInvocationResult doExecuteRequest(RemoteInvocation invocation, MethodInvocation originalInvocation) + throws Exception { + + double startTime = 0; + if(measureDuration){ + startTime = System.currentTimeMillis(); + } + RemoteInvocationResult result = super.executeRequest(invocation, originalInvocation); + if(measureDuration){ + double duration = System.currentTimeMillis() - startTime; + logger.info(getServiceUrl() + "#" + invocation.getMethodName() + " [" + duration + " ms]"); + } + return result; + } + + /** + * @return the remoteInvocationTermCacher + */ + public IRemoteInvocationTermCacher getRemoteInvocationTermCacher() { + return remoteInvocationTermCacher; + } + + /** + * @param remoteInvocationTermCacher the remoteInvocationTermCacher to set + */ + public void setRemoteInvocationTermCacher(IRemoteInvocationTermCacher remoteInvocationTermCacher) { + this.remoteInvocationTermCacher = remoteInvocationTermCacher; + } + + private ICdmEntitySessionManager cdmEntitySessionManager(){ + if(cdmEntitySessionManager == null) { + cdmEntitySessionManager = + ((CdmApplicationRemoteController)CdmApplicationState.getCurrentAppConfig()).getCdmEntitySessionManager(); + } + return cdmEntitySessionManager; + } + +} -- 2.34.1