-
Notifications
You must be signed in to change notification settings - Fork 3
/
CacheLookupEngine.java
161 lines (143 loc) · 4.34 KB
/
CacheLookupEngine.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*******************************************************************************
* Copyright (c) 2015, 2023 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.acceleo.query.runtime.lookup.basic;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment;
import org.eclipse.acceleo.query.runtime.IService;
import org.eclipse.acceleo.query.runtime.ServiceRegistrationResult;
import org.eclipse.acceleo.query.runtime.impl.JavaMethodService;
import org.eclipse.acceleo.query.validation.type.IType;
/**
* Lookup engine are used to retrieve services from a name and a set of arguments. This implementation cache
* service lookup result.
*
* @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
*/
public class CacheLookupEngine extends BasicLookupEngine {
/**
* No service marker.
*/
private static final IService<?> NO_SERVICE = new JavaMethodService(null, null, false);
/**
* A node of the cache forest.
*
* @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
*/
private static final class Node {
/**
* Children (parameter {@link IType} to next {@link Node}).
*/
private final Map<IType, Node> children = new HashMap<IType, Node>();
/**
* The {@link IService} if any, <code>null</code> otherwise.
*/
private IService<?> service;
}
/**
* The cache forest.
*/
private final Map<String, Node> cache = new HashMap<String, Node>();
/**
* Constructor.
*
* @param queryEnvironment
* the {@link IReadOnlyQueryEnvironment}
*/
public CacheLookupEngine(IReadOnlyQueryEnvironment queryEnvironment) {
super(queryEnvironment);
}
@Override
public ServiceRegistrationResult registerService(IService<?> service) {
cache.clear();
return super.registerService(service);
}
@Override
public IService<?> lookup(String name, IType[] argumentTypes) {
final IService<?> result;
final Node cachedNode = getNodeFromCache(name, argumentTypes);
if (cachedNode != null) {
if (cachedNode.service == NO_SERVICE) {
result = null;
} else if (cachedNode.service == null) {
result = super.lookup(name, argumentTypes);
cachedNode.service = result;
} else {
result = cachedNode.service;
}
} else {
result = super.lookup(name, argumentTypes);
cacheService(name, argumentTypes, result);
}
return result;
}
/**
* Caches the given {@link IService} for the given argument types.
*
* @param name
* the {@link IService} name
* @param argumentTypes
* argument types
* @param service
* the {@link IService} to cache
*/
private void cacheService(String name, IType[] argumentTypes, IService<?> service) {
Node currentNode = cache.get(name);
if (currentNode == null) {
currentNode = new Node();
cache.put(name, currentNode);
}
for (IType type : argumentTypes) {
Node nextNode = currentNode.children.get(type);
if (nextNode == null) {
nextNode = new Node();
currentNode.children.put(type, nextNode);
}
currentNode = nextNode;
}
if (service == null) {
currentNode.service = NO_SERVICE;
} else {
currentNode.service = service;
}
}
/**
* Gets the {@link Node} from the cache corresponding to the given name and parameter types.
*
* @param name
* the service name
* @param argumentTypes
* the argument types
* @return the {@link Node} from the cache corresponding to the given name and parameter types if any,
* <code>null</code> otherwise
*/
private Node getNodeFromCache(String name, IType[] argumentTypes) {
final Node result;
Node currentNode = cache.get(name);
if (currentNode != null) {
for (IType type : argumentTypes) {
currentNode = currentNode.children.get(type);
if (currentNode == null) {
break;
}
}
result = currentNode;
} else {
result = null;
}
return result;
}
@Override
public IService<?> removeService(IService<?> service) {
cache.clear();
return super.removeService(service);
}
}