Project

General

Profile

Download (7.88 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2020 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package org.springframework.remoting.httpinvoker;
10

    
11
import java.util.HashSet;
12
import java.util.Set;
13

    
14
import org.aopalliance.intercept.MethodInvocation;
15
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
16
import org.springframework.remoting.support.RemoteInvocation;
17
import org.springframework.remoting.support.RemoteInvocationResult;
18

    
19
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteController;
20
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
21
import eu.etaxonomy.cdm.api.service.ITermService;
22
import eu.etaxonomy.cdm.api.service.UpdateResult;
23
import eu.etaxonomy.taxeditor.service.IRemoteInvocationTermCacher;
24
import eu.etaxonomy.taxeditor.session.ICdmEntitySessionManager;
25

    
26
/**
27
 * Extension of the <code>HttpInvokerProxyFactoryBean</code> to support caching of general CDM entities and terms.
28
 * <p>
29
 * <b>Performance measurement:</b></br>
30
 * Supports measuring the request processing time at the client side. Setting "{@value #PROP_KEY_MEASURE_DURATION}"
31
 * as system parameter enables the measurement. To make the measurements appear for each request in the log, the logging <code>Level</code>
32
 * for <code>HttpInvokerProxyFactoryBean</code> needs to be set to at least {@link org.apache.log4j.Level#INFO}. Otherwise the duration is
33
 * only reported in case of errors.
34
 *
35
 * @author a.kohlbecker
36
 * @since Feb 4, 2020
37
 */
38
public class CachingHttpInvokerProxyFactoryBean extends HttpInvokerProxyFactoryBean {
39

    
40
    private static final Logger logger = LogManager.getLogger(CachingHttpInvokerProxyFactoryBean.class);
41

    
42
    private static final String PROP_KEY_MEASURE_DURATION = "remoting.httpinvoker.measureDuration";
43

    
44
    private ICdmEntitySessionManager cdmEntitySessionManager;
45

    
46
    private IRemoteInvocationTermCacher remoteInvocationTermCacher;
47

    
48
    protected final static Set<String> persistingMethods = new HashSet<>();
49

    
50
    protected static boolean measureDuration = false;
51

    
52
    static {
53
        persistingMethods.add("merge");
54
        persistingMethods.add("save");
55
        persistingMethods.add("findWithUpdate");
56
        persistingMethods.add("loadWithUpdate");
57
        measureDuration = System.getProperty(PROP_KEY_MEASURE_DURATION) != null;
58
    }
59

    
60
    @Override
61
    protected RemoteInvocationResult executeRequest(
62
            RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {
63

    
64
        // logger.setLevel(Level.INFO);
65

    
66
        if (!(invocation.getMethodName() == null) && !(getServiceUrl() == null) && logger.isDebugEnabled()){
67
            logger.debug("Remote invoking : " + getServiceUrl() + "#" + invocation.getMethodName());
68
         }
69

    
70
        if(CdmApplicationState.getCurrentAppConfig() == null){
71
            logger.debug("No application context yet, no point caching!");
72
            return doExecuteRequest(invocation, originalInvocation);
73
        }
74

    
75
        // A)  if this is a term service call for term lists try to get the terms from the cache
76
        if(ITermService.class.isAssignableFrom(originalInvocation.getMethod().getDeclaringClass())){
77
            return handleTermRequest(invocation, originalInvocation);
78
        }
79
        // B) handle other service calls
80
        else  {
81
            return handleGeneralRequest(invocation, originalInvocation);
82
        }
83
    }
84

    
85
    private RemoteInvocationResult handleGeneralRequest(RemoteInvocation invocation,
86
            MethodInvocation originalInvocation) throws Exception {
87
        RemoteInvocationResult invocationResult = doExecuteRequest(invocation, originalInvocation);
88
        if(invocationResult.getValue() != null && !invocationResult.hasException()) {
89

    
90
            if(persistingMethods.contains(invocation.getMethodName())) {
91
                invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), true));
92
                logger.debug("Entity cached with updating cached data");
93
            } else if(invocationResult.getValue() instanceof UpdateResult){
94
                UpdateResult result = (UpdateResult)invocationResult.getValue();
95
                if(result.isOk()){
96
                    logger.debug("Entity from UpdateResult stored in cache with updating cached data" );
97
                    try {
98
                        cdmEntitySessionManager().load(result, true);
99
                    } catch (Exception e) {
100
                        String message = "Error when trying to add update result to session cache in TaxEditor";
101
                        throw new RuntimeException(message, e);
102
                    }
103
                }
104
            } else {
105
                invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), false));
106
                logger.debug("Entity cached without updating cached data" );
107
            }
108
        }
109
        cache(invocation, invocationResult);
110
        return  invocationResult;
111
    }
112

    
113
    public void cache(RemoteInvocation ri, RemoteInvocationResult rir) {
114

    
115
    }
116

    
117
    private RemoteInvocationResult handleTermRequest(RemoteInvocation invocation, MethodInvocation originalInvocation)
118
            throws Exception {
119
        RemoteInvocationResult invocationResult = null;
120
        if(remoteInvocationTermCacher != null){
121
            invocationResult = remoteInvocationTermCacher.termsFromCache(invocation);
122
            if(invocationResult == null) {
123
                invocationResult = doExecuteRequest(invocation, originalInvocation);
124
                try {
125
                    remoteInvocationTermCacher.cacheTerms(invocation, invocationResult);
126
                } catch (Exception e) {
127
                    String message = "Error when caching terms in TaxEditor";
128
                    throw new RuntimeException(message, e);
129
                }
130
                logger.debug("Term list loaded and cached");
131
            } else {
132
                logger.debug("Term list found in cache, not loaded");
133
            }
134
        } else {
135
            logger.warn("Term list: No IRemoteInvocationTermCacher configured");
136
            invocationResult = doExecuteRequest(invocation, originalInvocation);
137
        }
138
        return invocationResult;
139
    }
140

    
141
    private RemoteInvocationResult doExecuteRequest(RemoteInvocation invocation, MethodInvocation originalInvocation)
142
            throws Exception {
143

    
144
        double startTime = 0;
145
        if(measureDuration){
146
            startTime = System.currentTimeMillis();
147
        }
148
        try {
149
            RemoteInvocationResult result = super.executeRequest(invocation, originalInvocation);
150
            if(measureDuration){
151
                double duration = System.currentTimeMillis() - startTime;
152
                logger.info(getServiceUrl() + "#" + invocation.getMethodName() + " [" + duration + " ms]");
153
            }
154
            return result;
155
        } catch(Exception e) {
156
            if(measureDuration){
157
                double duration = System.currentTimeMillis() - startTime;
158
                logger.error("(" + e.getClass().getName() + ": \"" + e.getMessage() + "\") interrupts " + getServiceUrl() + "#" + invocation.getMethodName() + " after [" + duration + " ms]");
159
            }
160
            throw e;
161
        }
162
    }
163

    
164
    public IRemoteInvocationTermCacher getRemoteInvocationTermCacher() {
165
        return remoteInvocationTermCacher;
166
    }
167
    public void setRemoteInvocationTermCacher(IRemoteInvocationTermCacher remoteInvocationTermCacher) {
168
        this.remoteInvocationTermCacher = remoteInvocationTermCacher;
169
    }
170

    
171
    private ICdmEntitySessionManager cdmEntitySessionManager(){
172
        if(cdmEntitySessionManager == null) {
173
            cdmEntitySessionManager =
174
                    ((CdmApplicationRemoteController)CdmApplicationState.getCurrentAppConfig()).getCdmEntitySessionManager();
175
        }
176
        return cdmEntitySessionManager;
177
    }
178
}
    (1-1/1)