Project

General

Profile

Download (8.02 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;
16
import org.apache.logging.log4j.Logger;
17
import org.springframework.remoting.support.RemoteInvocation;
18
import org.springframework.remoting.support.RemoteInvocationResult;
19

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

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

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

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

    
45
    private ICdmEntitySessionManager cdmEntitySessionManager;
46

    
47
    private IRemoteInvocationTermCacher remoteInvocationTermCacher;
48

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

    
51
    protected static boolean measureDuration = false;
52

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

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

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

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

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

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

    
86
    private RemoteInvocationResult handleGeneralRequest(RemoteInvocation invocation,
87
            MethodInvocation originalInvocation) throws Exception {
88

    
89
        RemoteInvocationResult invocationResult = doExecuteRequest(invocation, originalInvocation);
90
        if(invocationResult.getValue() != null && !invocationResult.hasException()) {
91

    
92
            //Note AM (2022-06-15): the debug information seem to be misleading (also because cache() is not used/implemented anymore)
93
            if(persistingMethods.contains(invocation.getMethodName())) {
94
                invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), true));
95
                logger.debug("Entity cached with updating cached data");
96
            } else if(invocationResult.getValue() instanceof UpdateResult){
97
                UpdateResult result = (UpdateResult)invocationResult.getValue();
98
                if(result.isOk()){
99
                    logger.debug("Entity from UpdateResult stored in cache with updating cached data" );
100
                    try {
101
                        cdmEntitySessionManager().load(result, true);
102
                    } catch (Exception e) {
103
                        String message = "Error when trying to add update result to session cache in TaxEditor";
104
                        throw new RuntimeException(message, e);
105
                    }
106
                }
107
            } else {
108
                invocationResult = new RemoteInvocationResult(cdmEntitySessionManager().load(invocationResult.getValue(), false));
109
                logger.debug("Entity cached without updating cached data" );
110
            }
111
        }
112
        cache(invocation, invocationResult);
113
        return  invocationResult;
114
    }
115

    
116
    public void cache(RemoteInvocation ri, RemoteInvocationResult rir) {
117

    
118
    }
119

    
120
    private RemoteInvocationResult handleTermRequest(RemoteInvocation invocation, MethodInvocation originalInvocation)
121
            throws Exception {
122

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

    
145
    private RemoteInvocationResult doExecuteRequest(RemoteInvocation invocation, MethodInvocation originalInvocation)
146
            throws Exception {
147

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

    
168
    public IRemoteInvocationTermCacher getRemoteInvocationTermCacher() {
169
        return remoteInvocationTermCacher;
170
    }
171
    public void setRemoteInvocationTermCacher(IRemoteInvocationTermCacher remoteInvocationTermCacher) {
172
        this.remoteInvocationTermCacher = remoteInvocationTermCacher;
173
    }
174

    
175
    private ICdmEntitySessionManager cdmEntitySessionManager(){
176
        if(cdmEntitySessionManager == null) {
177
            cdmEntitySessionManager =
178
                    ((CdmApplicationRemoteController)CdmApplicationState.getCurrentAppConfig()).getCdmEntitySessionManager();
179
        }
180
        return cdmEntitySessionManager;
181
    }
182
}
    (1-1/1)