package it.xsemantics.runtime; import it.xsemantics.runtime.caching.util.XsemanticsCacheUtils; import java.util.ArrayList; import java.util.List; import org.eclipse.xtext.util.IResourceScopeCache; import org.eclipse.xtext.xbase.lib.Functions.Function1; import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.eclipse.xtext.xbase.lib.Pair; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; /** * Default implementation of {@link XsemanticsCache}, using a * {@link IResourceScopeCache}. * * @author Lorenzo Bettini * * @since 1.8 */ @Singleton public class XsemanticsCacheDefaultImpl implements XsemanticsCache { @Inject private IResourceScopeCache cache; @Inject private XsemanticsCacheUtils cacheUtils; /** * @since 1.8 */ protected String cachedString = "cached:"; private List<XsemanticsCacheListener> listeners = new ArrayList<XsemanticsCacheListener>(); @Override public <T> T get(String methodName, RuleEnvironment environment, RuleApplicationTrace trace, XsemanticsProvider<T> provider, Object...elements) { XsemanticsCachedData<T> cached = internalGet(methodName, provider, elements); if (!provider.isCalled()) { for (XsemanticsCacheListener l : listeners) { l.cacheHit(cached); } // update the additional arguments with cached data if (environment != null && environment != cached.getEnvironment()) { environment.increment(cached.getEnvironment()); } if (trace != null && trace != cached.getTrace()) { trace.addToTrace(cachedString); if (cached.getTrace() != null) { trace.addObjectAsSubtrace(lastElementNotTrace(cached.getTrace())); } } } else { cached.setName(methodName); for (XsemanticsCacheListener l : listeners) { l.cacheMissed(cached); } } return cached.getResult(); } protected <T> T internalGet(String methodName, Provider<T> provider, Object... elements) { return cache.<T> get( Pair.<String, Object> of(methodName, cacheUtils.getKeys(elements)), cacheUtils.getResource(elements), provider); } @Override public void addListener(final XsemanticsCacheListener l) { this.listeners.add(l); } @Override public void removeListener(final XsemanticsCacheListener l) { this.listeners.remove(l); } private Object lastElementNotTrace(final RuleApplicationTrace trace) { // this is copied from TraceUtils, otherwise Sonarqube 5 reports // a dependency cycle because it uses source folders instead of // Java packages. return IterableExtensions.<Object> findLast(trace.trace, new Function1<Object, Boolean>() { @Override public Boolean apply(final Object it) { return Boolean.valueOf(!(it instanceof RuleApplicationTrace)); } }); } }