blob: 7832e4d34a8c73b07f456cb8f7858f286318fdde [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.idea.databinding;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* A utility cache that can be used if results from multiple resource repositories are being merged into one.
* @param <T> The type of {@linkplain CachedValueProvider}
* @param <V> The type of each individual {@linkplain ResourceCacheValueProvider}
*/
abstract public class ProjectResourceCachedValueProvider<T, V> implements CachedValueProvider<T>, ModificationTracker {
private Map<AndroidFacet, CachedValue<V>> myCachedValues = Maps.newHashMap();
private final ModificationTracker[] myAdditionalTrackers;
private List<ModificationTracker> myDependencies = Lists.newArrayList();
private DataBindingProjectComponent myComponent;
private long myDependencyModificationCountOnCompute;
private long myModificationCount = 0;
@Override
public long getModificationCount() {
long newCount = calculateModificationCountFrom(myDependencies);
if (newCount != myDependencyModificationCountOnCompute) {
myModificationCount ++;
}
return myModificationCount;
}
public ProjectResourceCachedValueProvider(DataBindingProjectComponent component, ModificationTracker... additionalTrackers) {
myComponent = component;
myAdditionalTrackers = additionalTrackers;
}
@Nullable
@Override
public final Result<T> compute() {
AndroidFacet[] facets = myComponent.getDataBindingEnabledFacets();
List<V> values = Lists.newArrayList();
List<ModificationTracker> newDependencies = Lists.newArrayList();
newDependencies.add(myComponent);
Collections.addAll(newDependencies, myAdditionalTrackers);
for (AndroidFacet facet : facets) {
CachedValue<V> cachedValue = getCachedValue(facet);
// we know this for sure since it is created from createCacheProvider
if (cachedValue.getValueProvider() instanceof ModificationTracker) {
newDependencies.add((ModificationTracker)cachedValue.getValueProvider());
}
V result = cachedValue.getValue();
if (result != null) {
values.add(result);
}
}
myDependencyModificationCountOnCompute = calculateModificationCountFrom(newDependencies);
myDependencies = newDependencies;
return Result.create(merge(values), this);
}
private static long calculateModificationCountFrom(List<ModificationTracker> dependencies) {
long total = 0;
for (ModificationTracker tracker : dependencies) {
total += tracker.getModificationCount();
}
return total;
}
@NotNull
abstract protected T merge(List<V> results);
private CachedValue<V> getCachedValue(AndroidFacet facet) {
CachedValue<V> cachedValue = myCachedValues.get(facet);
if (cachedValue == null) {
ResourceCacheValueProvider<V> cacheProvider = createCacheProvider(facet);
cachedValue = CachedValuesManager.getManager(facet.getModule().getProject()).createCachedValue(cacheProvider, false);
myCachedValues.put(facet, cachedValue);
}
return cachedValue;
}
abstract ResourceCacheValueProvider<V> createCacheProvider(AndroidFacet facet);
abstract public static class MergedMapValueProvider<A, B> extends ProjectResourceCachedValueProvider<Map<A, List<B>>, Map<A, List<B>>> {
public MergedMapValueProvider(DataBindingProjectComponent component, ModificationTracker... additionalTrackers) {
super(component, additionalTrackers);
}
@NotNull
@Override
protected Map<A, List<B>> merge(List<Map<A, List<B>>> results) {
Map<A, List<B>> merged = Maps.newHashMap();
for (Map<A, List<B>> result : results) {
for (Map.Entry<A, List<B>> entry : result.entrySet()) {
List<B> bList = merged.get(entry.getKey());
if (bList == null) {
bList = Lists.newArrayList();
merged.put(entry.getKey(), bList);
}
bList.addAll(entry.getValue());
}
}
return merged;
}
}
}