001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019 */
020package org.sonar.server.rules;
021
022import org.apache.commons.lang.ArrayUtils;
023import org.apache.commons.lang.StringUtils;
024import org.sonar.api.ServerComponent;
025import org.sonar.api.database.DatabaseSession;
026import org.sonar.api.profiles.*;
027import org.sonar.api.rules.ActiveRule;
028import org.sonar.api.rules.ActiveRuleParam;
029import org.sonar.api.utils.ValidationMessages;
030import org.sonar.jpa.session.DatabaseSessionFactory;
031
032import java.io.StringReader;
033import java.io.StringWriter;
034import java.io.Writer;
035import java.util.ArrayList;
036import java.util.Arrays;
037import java.util.List;
038
039public final class ProfilesConsole implements ServerComponent {
040
041  private DatabaseSessionFactory sessionFactory;
042  private XMLProfileParser xmlProfileParser;
043  private XMLProfileSerializer xmlProfileSerializer;
044  private List<ProfileExporter> exporters = new ArrayList<ProfileExporter>();
045  private List<ProfileImporter> importers = new ArrayList<ProfileImporter>();
046
047  public ProfilesConsole(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer,
048                         ProfileExporter[] exporters,
049                         ProfileImporter[] importers) {
050    this.xmlProfileParser = xmlProfileParser;
051    this.xmlProfileSerializer = xmlProfileSerializer;
052    this.sessionFactory = sessionFactory;
053    this.exporters.addAll(Arrays.asList(exporters));
054    this.importers.addAll(Arrays.asList(importers));
055  }
056
057  public String backupProfile(int profileId) {
058    DatabaseSession session = sessionFactory.getSession();
059    RulesProfile profile = loadProfile(session, profileId);
060    if (profile != null) {
061      Writer writer = new StringWriter();
062      xmlProfileSerializer.write(profile, writer);
063      return writer.toString();
064    }
065    return null;
066  }
067
068  public ValidationMessages restoreProfile(String xmlBackup, boolean deleteExisting) {
069    ValidationMessages messages = ValidationMessages.create();
070    RulesProfile profile = xmlProfileParser.parse(new StringReader(xmlBackup), messages);
071    if (profile != null && !messages.hasErrors()) {
072      DatabaseSession session = sessionFactory.getSession();
073      RulesProfile existingProfile = session.getSingleResult(RulesProfile.class, "name", profile.getName(), "language", profile.getLanguage());
074      if (existingProfile != null && !deleteExisting) {
075        messages.addErrorText("The profile " + profile + " already exists. Please delete it before restoring.");
076
077      } else {
078        if (existingProfile!=null) {
079          session.removeWithoutFlush(existingProfile);
080        }
081        session.saveWithoutFlush(profile);
082        session.commit();
083      }
084    }
085    return messages;
086  }
087
088  private RulesProfile loadProfile(DatabaseSession session, int profileId) {
089    return session.getSingleResult(RulesProfile.class, "id", profileId);
090  }
091
092  public List<ProfileExporter> getProfileExportersForLanguage(String language) {
093    List<ProfileExporter> result = new ArrayList<ProfileExporter>();
094    for (ProfileExporter exporter : exporters) {
095      if (exporter.getSupportedLanguages() == null || exporter.getSupportedLanguages().length == 0 || ArrayUtils.contains(exporter.getSupportedLanguages(), language)) {
096        result.add(exporter);
097      }
098    }
099    return result;
100  }
101
102  public List<ProfileImporter> getProfileImportersForLanguage(String language) {
103    List<ProfileImporter> result = new ArrayList<ProfileImporter>();
104    for (ProfileImporter importer : importers) {
105      if (importer.getSupportedLanguages() == null || importer.getSupportedLanguages().length == 0 || ArrayUtils.contains(importer.getSupportedLanguages(), language)) {
106        result.add(importer);
107      }
108    }
109    return result;
110  }
111
112  public String exportProfile(int profileId, String exporterKey) {
113    DatabaseSession session = sessionFactory.getSession();
114    RulesProfile profile = loadProfile(session, profileId);
115    if (profile != null) {
116      ProfileExporter exporter = getProfileExporter(exporterKey);
117      if (exporter == null) {
118        throw new IllegalArgumentException("No such exporter");
119      }
120      Writer writer = new StringWriter();
121      exporter.exportProfile(profile, writer);
122      return writer.toString();
123    }
124    return null;
125  }
126
127  /**
128   * Important : the ruby controller has already create the profile
129   */
130  public ValidationMessages importProfile(String profileName, String language, String importerKey, String profileDefinition) {
131    ValidationMessages messages = ValidationMessages.create();
132    ProfileImporter importer = getProfileImporter(importerKey);
133    RulesProfile profile = importer.importProfile(new StringReader(profileDefinition), messages);
134    if (!messages.hasErrors()) {
135      DatabaseSession session = sessionFactory.getSession();
136      RulesProfile persistedProfile = session.getSingleResult(RulesProfile.class, "name", profileName, "language", language);
137      for (ActiveRule activeRule : profile.getActiveRules()) {
138        ActiveRule persistedActiveRule = persistedProfile.activateRule(activeRule.getRule(), activeRule.getSeverity());
139        for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) {
140          persistedActiveRule.setParameter(activeRuleParam.getKey(), activeRuleParam.getValue());
141        }
142      }
143      session.saveWithoutFlush(persistedProfile);
144      session.commit();
145    }
146    return messages;
147  }
148
149  public ProfileExporter getProfileExporter(String exporterKey) {
150    for (ProfileExporter exporter : exporters) {
151      if (StringUtils.equals(exporterKey, exporter.getKey())) {
152        return exporter;
153      }
154    }
155    return null;
156  }
157
158  public ProfileImporter getProfileImporter(String exporterKey) {
159    for (ProfileImporter importer : importers) {
160      if (StringUtils.equals(exporterKey, importer.getKey())) {
161        return importer;
162      }
163    }
164    return null;
165  }
166}