/*
* Copyright 2005-2016 Sixth and Red River Software, Bas Leijdekkers
*
* 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.sixrr.metrics.profile;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ExportableComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.sixrr.metrics.Metric;
import com.sixrr.metrics.MetricCategory;
import com.sixrr.metrics.MetricProvider;
import com.sixrr.metrics.PrebuiltMetricProfile;
import com.sixrr.metrics.config.MetricsReloadedConfig;
import com.sixrr.metrics.utils.MetricsCategoryNameUtil;
import com.sixrr.metrics.utils.MetricsReloadedBundle;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.*;
public final class MetricsProfileRepository implements MetricRepository, ExportableComponent {
private static final Logger LOG = Logger.getInstance("#com.sixrr.metrics.profile.MetricsProfileRepository");
@NonNls
private static final String METRIC_PROFILE_DIR = PathManager.getConfigPath() + File.separator + "metrics";
private final Map<String, MetricsProfile> profiles = new LinkedHashMap<String, MetricsProfile>(20);
private String selectedProfile = "";
private final Map<String, Metric> metrics = new HashMap();
private MetricsProfileRepository() {
initialize();
}
public static MetricsProfileRepository getInstance() {
return ServiceManager.getService(MetricsProfileRepository.class);
}
/**
* Allows for exporting metrics profiles. (<pre>File | Export settings...</pre>)
* <p>
* The metrics configuration files are located within <code>idea.config.path/metrics/...</code>
*/
@NotNull
@Override
public File[] getExportFiles() {
@NonNls final String dirName = PathManager.getConfigPath() + File.separator + "metrics";
final File metricsDirectory = new File(dirName);
final File[] files = metricsDirectory.listFiles();
final File[] out;
if (files == null) {
out = new File[1];
} else {
out = new File[files.length + 1];
System.arraycopy(files, 0, out, 1, files.length);
}
out[0] = metricsDirectory;
return out;
}
@NotNull
@Override
public String getPresentableName() {
return MetricsReloadedBundle.message("metrics.profiles.configuration.presentable.name");
}
private void initialize() {
loadMetricsFromProviders();
loadProfiles();
reconcileProfiles();
addPrebuiltProfiles();
final String previouslySelectedProfile = MetricsReloadedConfig.getInstance().getSelectedProfile();
selectedProfile = profiles.containsKey(previouslySelectedProfile)
? previouslySelectedProfile
: profiles.keySet().iterator().next();
}
private void loadMetricsFromProviders() {
final Application application = ApplicationManager.getApplication();
final MetricProvider[] metricProviders = application.getExtensions(MetricProvider.EXTENSION_POINT_NAME);
for (MetricProvider provider : metricProviders) {
final List<Metric> metrics = provider.getMetrics();
for (Metric metric : metrics) {
this.metrics.put(metric.getClass().getName(), metric);
}
}
}
private void reconcile(MetricsProfile profile) {
for (final Metric metric : metrics.values()) {
if (profile.getMetricInstance(metric) == null) {
profile.addMetricInstance(new MetricInstanceImpl(metric));
}
}
}
private MetricsProfile buildProfile(String name) {
final List<MetricInstance> result = new ArrayList<MetricInstance>(metrics.size());
for (final Metric metric : metrics.values()) {
result.add(new MetricInstanceImpl(metric));
}
return new MetricsProfileImpl(name, result);
}
private void addPrebuiltProfiles() {
final Application application = ApplicationManager.getApplication();
final MetricProvider[] metricProviders = application.getExtensions(MetricProvider.EXTENSION_POINT_NAME);
for (MetricProvider provider : metricProviders) {
final List<PrebuiltMetricProfile> prebuiltProfiles = provider.getPrebuiltProfiles();
for (PrebuiltMetricProfile prebuiltProfile : prebuiltProfiles) {
addPrebuiltProfile(prebuiltProfile);
}
}
}
private void addPrebuiltProfile(PrebuiltMetricProfile builtInProfile) {
final String name = builtInProfile.getProfileName();
final MetricsProfile existingProfile = profiles.get(name);
final MetricsProfile profile = (existingProfile != null) ? existingProfile : buildProfile(name);
final Set<String> metricIDs = builtInProfile.getMetricIDs();
for (String metricID : metricIDs) {
final MetricInstance instance = profile.getMetricInstance(metricID);
assert instance != null : "no instance found for " + metricID;
instance.setEnabled(true);
final Double lowerThreshold = builtInProfile.getLowerThresholdForMetric(metricID);
final Double upperThreshold = builtInProfile.getUpperThresholdForMetric(metricID);
if (lowerThreshold != null) {
instance.setLowerThresholdEnabled(true);
instance.setLowerThreshold(lowerThreshold.doubleValue());
}
if (upperThreshold != null) {
instance.setUpperThresholdEnabled(true);
instance.setUpperThreshold(upperThreshold.doubleValue());
}
}
profile.setBuiltIn(true);
profiles.put(name, profile);
}
public String generateNewProfileName() {
final String baseName =
(selectedProfile == null || selectedProfile.isEmpty()) ? "Metrics" : selectedProfile;
return generateNewProfileName(baseName);
}
public String generateNewProfileName(@NotNull String baseName) {
int index = 1;
String newName = baseName;
while (profiles.containsKey(newName)) {
index++;
newName = baseName + " (" + index + ")";
}
return newName;
}
private void loadProfiles() {
final File metricsDir = new File(METRIC_PROFILE_DIR);
if (!metricsDir.exists()) {
return;
}
final File[] files = metricsDir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
final MetricsProfile profile = MetricsProfileImpl.loadFromFile(file, this);
if (profile != null) {
final String profileName = profile.getName();
profiles.put(profileName, profile);
}
}
}
private void reconcileProfiles() {
final Collection<MetricsProfile> existingProfiles = profiles.values();
for (final MetricsProfile profile : existingProfiles) {
reconcile(profile);
}
}
@Override
@Nullable
public Metric getMetric(String fqName) {
return metrics.get(fqName);
}
public String[] getProfileNames() {
final Set<String> keys = profiles.keySet();
final int numKeys = keys.size();
final String[] names = keys.toArray(new String[numKeys]);
Arrays.sort(names);
return names;
}
@Nullable
public MetricsProfile getCurrentProfile() {
return profiles.get(selectedProfile);
}
public void setSelectedProfile(String profileName) {
selectedProfile = profileName;
MetricsReloadedConfig.getInstance().setSelectedProfile(selectedProfile);
}
public void deleteProfile(MetricsProfile profile) {
final String profileName = profile.getName();
profiles.remove(profileName);
final String randomProfileName = profiles.keySet().iterator().next();
setSelectedProfile(randomProfileName);
final File profileFile = getFileForProfile(profile);
profileFile.delete();
}
public void reloadProfileFromStorage(MetricsProfile profile) {
final File profileFile = getFileForProfile(profile);
final MetricsProfile newProfile = MetricsProfileImpl.loadFromFile(profileFile, this);
if (newProfile != null) {
profiles.put(newProfile.getName(), newProfile);
}
}
public static void persistProfile(MetricsProfile profile) {
final File profileFile = getFileForProfile(profile);
try {
profile.writeToFile(profileFile);
} catch (IOException e) {
LOG.warn(e);
}
}
@NonNls
private static File getFileForProfile(MetricsProfile profile) {
final String profileName = profile.getName();
return new File(METRIC_PROFILE_DIR, profileName + ".xml");
}
public void duplicateCurrentProfile(String newProfileName) {
final MetricsProfile currentProfile = getCurrentProfile();
assert currentProfile != null;
final MetricsProfile newProfile;
try {
newProfile = currentProfile.clone();
} catch (CloneNotSupportedException ignore) {
return;
}
newProfile.setName(newProfileName);
profiles.put(newProfileName, newProfile);
persistProfile(newProfile);
setSelectedProfile(newProfileName);
}
public void createEmptyProfile(String newProfileName) {
final MetricsProfile newProfile = buildProfile(newProfileName);
profiles.put(newProfileName, newProfile);
persistProfile(newProfile);
setSelectedProfile(newProfileName);
}
public void persistCurrentProfile() {
final MetricsProfile currentProfile = getCurrentProfile();
persistProfile(currentProfile);
}
public boolean profileExists(String profileName) {
return profiles.containsKey(profileName);
}
public MetricsProfile getProfileForName(String profileName) {
return profiles.get(profileName);
}
public void addProfile(MetricsProfile profile) {
final String newProfileName = profile.getName();
profiles.put(newProfileName, profile);
setSelectedProfile(newProfileName);
}
public void printMetricsDescriptions() {
final Collection<Metric> metrics = this.metrics.values();
System.out.println(metrics.size() + " metrics");
MetricCategory currentCategory = null;
for (final Metric metric : metrics) {
final MetricCategory category = metric.getCategory();
if (category != currentCategory) {
System.out.println(MetricsCategoryNameUtil.getLongNameForCategory(category));
currentCategory = category;
}
System.out.println(" " + metric.getDisplayName());
}
}
}