Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 162c350eba6f88bd3328e5ed7dd4557b16990cac (plain) (blame)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package org.eclipse.jst.jsf.designtime.resolver;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.jst.jsf.context.IModelContext;
import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext;
import org.eclipse.jst.jsf.context.symbol.IMethodSymbol;
import org.eclipse.jst.jsf.context.symbol.IObjectSymbol;
import org.eclipse.jst.jsf.context.symbol.ISymbol;
import org.eclipse.jst.jsf.context.symbol.SymbolFactory;

/**
 * A symbol resolver that delegates to the default SymbolContextResolver, but
 * caches the results and returns those on subsequent calls.
 * 
 * WARNING: this resolver is suitable *only* in situations where the state
 * of dependent symbol sources won't change between calls.  This resolver makes
 * no attempt to ensure that cached data is in sync with changes to symbols
 * such addition, modification or removal of Java class underlying beans.
 * 
 * NOTE: this resolver is experimental and should NOT be considered API
 * 
 * Clients should not use this resolver directly.  Access it through the factory instead
 * @author cbateman
 *
 */
public final class CachingSymbolContextResolver extends AbstractSymbolContextResolver
{
    private final static ISymbol SYMBOL_NOT_FOUND = SymbolFactory.eINSTANCE.createIComponentSymbol();
    private final static IMethodSymbol METHOD_SYMBOL_NOT_FOUND =
        SymbolFactory.eINSTANCE.createIMethodSymbol();
    
    private final SymbolContextResolver     _delegate;

    private final Map<String, ISymbol>  _variablesByName = new HashMap<String, ISymbol>();
    private ISymbol[]                   _allVariables;

    private final Map<ISymbol, Map<Object, ISymbol>>    _propertiesByOwner =
        new HashMap<ISymbol, Map<Object,ISymbol>>();
    private ISymbol[]                   _allProperties;

    private final Map<IObjectSymbol, Map<Object, IMethodSymbol>> _methodsByOwner =
        new HashMap<IObjectSymbol, Map<Object,IMethodSymbol>>();
    private ISymbol[]             _allMethods;
    
    /**
     * @param context
     */
    public CachingSymbolContextResolver(final IStructuredDocumentContext context)
    {
        _delegate = new SymbolContextResolver(context);
    }

    @Override
    public boolean canResolveContext(final IModelContext modelContext)
    {
        return _delegate.canResolveContext(modelContext);
    }

    @Override
    public ISymbol[] getAllVariables()
    {
        if (_allVariables == null)
        {
            _allVariables = _delegate.getAllVariables();
        }
        return _allVariables;
    }

    @Override
    public IMethodSymbol getMethod(final IObjectSymbol base, final Object methodName)
    {
        Map<Object, IMethodSymbol> methods = _methodsByOwner.get(base);
        
        if (methods == null)
        {
            methods = new HashMap<Object, IMethodSymbol>();
            _methodsByOwner.put(base, methods);
        }

        IMethodSymbol method = methods.get(methodName);

        if (method == SYMBOL_NOT_FOUND)
        {
            method = null;
        }
        else
        {
            if (method == null)
            {
                method = _delegate.getMethod(base, methodName);
                
                if (method == null)
                {
                    // if the delegate couldn't find the property,
                    // then mark this in case it is requested again
                    methods.put(methodName, METHOD_SYMBOL_NOT_FOUND);
                }
                else
                {
                    methods.put(methodName, method);
                }
            }
        }
        return method;
    }

    @Override
    public ISymbol[] getMethods(final IObjectSymbol base)
    {
        if (_allMethods == null)
        {
            _allMethods = _delegate.getMethods(base);
        }
        return _allMethods;
    }

    @Override
    public ISymbol[] getProperties(final ISymbol symbol)
    {
        if (_allProperties == null)
        {
            _allProperties = _delegate.getProperties(symbol);
        }
        return _allProperties;
    }

    @Override
    public ISymbol getProperty(final ISymbol symbol, final Object propertyName)
    {
        Map<Object, ISymbol> properties = _propertiesByOwner.get(symbol);
        
        if (properties == null)
        {
            properties = new HashMap<Object, ISymbol>();
            _propertiesByOwner.put(symbol, properties);
        }

        ISymbol property = properties.get(propertyName);

        if (property == SYMBOL_NOT_FOUND)
        {
            property = null;
        }
        else
        {
            if (property == null)
            {
                property = _delegate.getProperty(symbol, propertyName);
                
                if (property == null)
                {
                    // if the delegate couldn't find the property,
                    // then mark this in case it is requested again
                    properties.put(propertyName, SYMBOL_NOT_FOUND);
                }
                else
                {
                    properties.put(propertyName, property);
                }
            }
        }
        return property;
    }

    @Override
    public ISymbol getVariable(final String name)
    {
        ISymbol variable = _variablesByName.get(name);

        // if the symbol was not found, return null but avoid calling the
        // delegate again
        if (variable == SYMBOL_NOT_FOUND)
        {
            variable = null;
        }
        else
        {
            if (variable == null)
            {
                variable = _delegate.getVariable(name);
                
                if (variable == null)
                {
                    // if the delegate couldn't find the variable,
                    // then mark this in case it is requested again
                    _variablesByName.put(name, SYMBOL_NOT_FOUND);
                }
                else
                {
                    _variablesByName.put(name, variable);
                }
            }
        }
        return variable;
    }

    @Override
    public boolean hasSameResolution(IModelContext modelContext)
    {
        return _delegate.hasSameResolution(modelContext);
    }
}

Back to the top