blob: b81fbe54e9f36fac9d9376fd6bca716ee06d09d6 [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* 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.intellij.internal.statistic;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.featureStatistics.FeatureUsageTrackerImpl;
import com.intellij.internal.statistic.beans.ConvertUsagesUtil;
import com.intellij.internal.statistic.beans.GroupDescriptor;
import com.intellij.internal.statistic.beans.PatchedUsage;
import com.intellij.internal.statistic.beans.UsageDescriptor;
import com.intellij.internal.statistic.connect.RemotelyConfigurableStatisticsService;
import com.intellij.internal.statistic.connect.StatisticsConnectionService;
import com.intellij.internal.statistic.connect.StatisticsHttpClientSender;
import com.intellij.internal.statistic.connect.StatisticsService;
import com.intellij.internal.statistic.persistence.SentUsagesPersistence;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.KeyedExtensionCollector;
import com.intellij.openapi.util.Pair;
import com.intellij.util.Function;
import com.intellij.util.Time;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class StatisticsUploadAssistant {
private static final Logger LOG = Logger.getInstance("#com.intellij.internal.statistic.StatisticsUploadAssistant");
public String getData() {
return getData(Collections.<String>emptySet());
}
public static boolean showNotification() {
return UsageStatisticsPersistenceComponent.getInstance().isShowNotification() &&
(System.currentTimeMillis() - Time.DAY > ((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getFirstRunTime()) ;
}
public static boolean isTimeToSend() {
return isTimeToSend(UsageStatisticsPersistenceComponent.getInstance());
}
public static boolean isTimeToSend(UsageStatisticsPersistenceComponent settings) {
final long timeDelta = System.currentTimeMillis() - settings.getLastTimeSent();
return Math.abs(timeDelta) > settings.getPeriod().getMillis();
}
public static boolean isSendAllowed() {
return isSendAllowed(UsageStatisticsPersistenceComponent.getInstance());
}
public static boolean isSendAllowed(final SentUsagesPersistence settings) {
return settings != null && settings.isAllowed();
}
public String getData(@NotNull Set<String> disabledGroups) {
return getStringPatch(disabledGroups, ProjectManager.getInstance().getOpenProjects());
}
public static void persistSentPatch(@NotNull String patchStr) {
persistSentPatch(patchStr, UsageStatisticsPersistenceComponent.getInstance());
}
public static void persistSentPatch(@NotNull String patchStr, @NotNull SentUsagesPersistence persistenceComponent) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = mapToPatchedUsagesMap(ConvertUsagesUtil.convertString(patchStr));
if (patchedUsages.size() > 0) persistenceComponent.persistPatch(patchedUsages);
}
@NotNull
public static String getStringPatch(@NotNull Set<String> disabledGroups, Project... project) {
return getStringPatch(disabledGroups, project, UsageStatisticsPersistenceComponent.getInstance(), 0);
}
@NotNull
public static String getStringPatch(@NotNull Set<String> disabledGroups,
@NotNull Project[] projects,
@NotNull SentUsagesPersistence usagesPersistence,
int maxSize) {
final Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = getPatchedUsages(disabledGroups, projects, usagesPersistence);
return getStringPatch(patchedUsages, maxSize);
}
public static String getStringPatch(@NotNull Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages, int maxSize) {
if (patchedUsages.size() == 0) return "";
String patchStr = ConvertUsagesUtil.convertUsages(patchedUsages);
if (maxSize > 0 && patchStr.getBytes().length > maxSize) {
patchStr = ConvertUsagesUtil.cutPatchString(patchStr, maxSize);
}
return patchStr;
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull Set<String> disabledGroups,
@NotNull Project[] projects,
@NotNull SentUsagesPersistence usagesPersistence) {
Map<GroupDescriptor, Set<PatchedUsage>> usages = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
for (Project project : projects) {
final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages = getAllUsages(project, disabledGroups);
final Map<GroupDescriptor, Set<UsageDescriptor>> sentUsages = filterDisabled(disabledGroups, usagesPersistence.getSentUsages());
usages.putAll(getPatchedUsages(allUsages, sentUsages));
}
return usages;
}
@NotNull
private static Map<GroupDescriptor, Set<UsageDescriptor>> filterDisabled(@NotNull Set<String> disabledGroups, @NotNull Map<GroupDescriptor, Set<UsageDescriptor>> usages) {
Map<GroupDescriptor, Set<UsageDescriptor>> filtered = new LinkedHashMap<GroupDescriptor, Set<UsageDescriptor>>();
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> usage : usages.entrySet()) {
if (!disabledGroups.contains(usage.getKey().getId())) {
filtered.put(usage.getKey(), usage.getValue());
}
}
return filtered;
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages,
@NotNull SentUsagesPersistence usagesPersistence) {
return getPatchedUsages(allUsages, usagesPersistence.getSentUsages());
}
@NotNull
public static Map<GroupDescriptor, Set<PatchedUsage>> getPatchedUsages(@NotNull final Map<GroupDescriptor, Set<UsageDescriptor>> allUsages, final Map<GroupDescriptor, Set<UsageDescriptor>> sentUsageMap) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = mapToPatchedUsagesMap(allUsages);
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> sentUsageEntry : sentUsageMap.entrySet()) {
final GroupDescriptor sentUsageGroupDescriptor = sentUsageEntry.getKey();
final Set<UsageDescriptor> sentUsages = sentUsageEntry.getValue();
for (UsageDescriptor sentUsage : sentUsages) {
final PatchedUsage descriptor = findDescriptor(patchedUsages, Pair.create(sentUsageGroupDescriptor, sentUsage.getKey()));
if (descriptor == null) {
if (!patchedUsages.containsKey(sentUsageGroupDescriptor)) {
patchedUsages.put(sentUsageGroupDescriptor, new LinkedHashSet<PatchedUsage>());
}
patchedUsages.get(sentUsageGroupDescriptor).add(new PatchedUsage(sentUsage.getKey(), -sentUsage.getValue()));
} else {
descriptor.subValue(sentUsage.getValue());
}
}
}
return packCollection(patchedUsages, new Condition<PatchedUsage>() {
@Override
public boolean value(PatchedUsage patchedUsage) {
return patchedUsage.getDelta() != 0;
}
});
}
private static Map<GroupDescriptor, Set<PatchedUsage>> mapToPatchedUsagesMap(Map<GroupDescriptor, Set<UsageDescriptor>> allUsages) {
Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
for (Map.Entry<GroupDescriptor, Set<UsageDescriptor>> entry : allUsages.entrySet()) {
patchedUsages.put(entry.getKey(), new HashSet<PatchedUsage>(ContainerUtil.map2Set(entry.getValue(), new Function<UsageDescriptor, PatchedUsage>() {
@Override
public PatchedUsage fun(UsageDescriptor usageDescriptor) {
return new PatchedUsage(usageDescriptor);
}
})));
}
return patchedUsages;
}
@NotNull
private static Map<GroupDescriptor, Set<PatchedUsage>> packCollection(@NotNull Map<GroupDescriptor, Set<PatchedUsage>> patchedUsages, Condition<PatchedUsage> condition) {
Map<GroupDescriptor, Set<PatchedUsage>> result = new LinkedHashMap<GroupDescriptor, Set<PatchedUsage>>();
for (GroupDescriptor descriptor : patchedUsages.keySet()) {
final Set<PatchedUsage> usages = packCollection(patchedUsages.get(descriptor), condition);
if (usages.size() > 0) {
result.put(descriptor, usages);
}
}
return result;
}
@NotNull
private static <T> Set<T> packCollection(@NotNull Collection<T> set, @NotNull Condition<T> condition) {
final Set<T> result = new LinkedHashSet<T>();
for (T t : set) {
if (condition.value(t)) {
result.add(t);
}
}
return result;
}
@Nullable
public static <T extends UsageDescriptor> T findDescriptor(@NotNull Map<GroupDescriptor, Set<T>> descriptors,
@NotNull final Pair<GroupDescriptor, String> id) {
final Set<T> usages = descriptors.get(id.getFirst());
if (usages == null) return null;
return ContainerUtil.find(usages, new Condition<T>() {
@Override
public boolean value(T t) {
return id.getSecond().equals(t.getKey());
}
});
}
@NotNull
public static Map<GroupDescriptor, Set<UsageDescriptor>> getAllUsages(@Nullable Project project, @NotNull Set<String> disabledGroups) {
Map<GroupDescriptor, Set<UsageDescriptor>> usageDescriptors = new LinkedHashMap<GroupDescriptor, Set<UsageDescriptor>>();
for (UsagesCollector usagesCollector : Extensions.getExtensions(UsagesCollector.EP_NAME)) {
final GroupDescriptor groupDescriptor = usagesCollector.getGroupId();
if (!disabledGroups.contains(groupDescriptor.getId())) {
try {
final Set<UsageDescriptor> usages = usagesCollector.getUsages(project);
usageDescriptors.put(groupDescriptor, usages);
}
catch (CollectUsagesException e) {
LOG.info(e);
}
}
}
return usageDescriptors;
}
private static final KeyedExtensionCollector<StatisticsService, String> COLLECTOR;
static {
COLLECTOR = new KeyedExtensionCollector<StatisticsService, String>("com.intellij.statisticsService");
}
public static StatisticsService getStatisticsService() {
String key = ((ApplicationInfoImpl)ApplicationInfoImpl.getShadowInstance()).getStatisticsServiceKey();
StatisticsService service = key == null ? null : COLLECTOR.findSingle(key);
if (service != null) {
return service;
}
return new RemotelyConfigurableStatisticsService(new StatisticsConnectionService(),
new StatisticsHttpClientSender(),
new StatisticsUploadAssistant());
}
}