3 * Copyright (C) 2009-2017 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.edition;
22 import com.google.common.collect.ImmutableSet;
24 import java.util.Optional;
25 import org.picocontainer.Startable;
26 import org.sonar.db.DbClient;
27 import org.sonar.db.DbSession;
28 import org.sonar.db.property.InternalPropertiesDao;
30 import static com.google.common.base.Preconditions.checkArgument;
31 import static com.google.common.base.Preconditions.checkState;
32 import static java.util.Objects.requireNonNull;
33 import static java.util.Optional.empty;
34 import static org.sonar.server.edition.EditionManagementState.PendingStatus.AUTOMATIC_IN_PROGRESS;
35 import static org.sonar.server.edition.EditionManagementState.PendingStatus.AUTOMATIC_READY;
36 import static org.sonar.server.edition.EditionManagementState.PendingStatus.MANUAL_IN_PROGRESS;
37 import static org.sonar.server.edition.EditionManagementState.PendingStatus.NONE;
39 public class StandaloneEditionManagementStateImpl implements MutableEditionManagementState, Startable {
40 private static final String CURRENT_EDITION_KEY = "sonar.editionManagement.currentEditionKey";
41 private static final String PENDING_INSTALLATION_STATUS = "sonar.editionManagement.pendingInstallationStatus";
42 private static final String PENDING_EDITION_KEY = "sonar.editionManagement.pendingEditionKey";
43 private static final String PENDING_LICENSE = "sonar.editionManagement.pendingLicense";
45 private final DbClient dbClient;
46 private String currentEditionKey;
47 private PendingStatus pendingInstallationStatus = NONE;
48 private String pendingEditionKey;
49 private String pendingLicense;
51 public StandaloneEditionManagementStateImpl(DbClient dbClient) {
52 this.dbClient = dbClient;
57 try (DbSession dbSession = dbClient.openSession(false)) {
58 // load current state value
59 Map<String, Optional<String>> internalPropertyValues = dbClient.internalPropertiesDao().selectByKeys(dbSession,
60 ImmutableSet.of(CURRENT_EDITION_KEY, PENDING_INSTALLATION_STATUS, PENDING_EDITION_KEY, PENDING_LICENSE));
61 this.currentEditionKey = internalPropertyValues.getOrDefault(CURRENT_EDITION_KEY, empty())
62 .map(StandaloneEditionManagementStateImpl::emptyToNull)
64 this.pendingInstallationStatus = internalPropertyValues.getOrDefault(PENDING_INSTALLATION_STATUS, empty())
65 .map(PendingStatus::valueOf)
67 this.pendingEditionKey = internalPropertyValues.getOrDefault(PENDING_EDITION_KEY, empty())
68 .map(StandaloneEditionManagementStateImpl::emptyToNull)
70 this.pendingLicense = internalPropertyValues.getOrDefault(PENDING_LICENSE, empty()).orElse(null);
80 public Optional<String> getCurrentEditionKey() {
81 return Optional.ofNullable(currentEditionKey);
85 public PendingStatus getPendingInstallationStatus() {
86 return pendingInstallationStatus;
90 public Optional<String> getPendingEditionKey() {
91 return Optional.ofNullable(pendingEditionKey);
95 public Optional<String> getPendingLicense() {
96 return Optional.ofNullable(pendingLicense);
100 public synchronized PendingStatus startAutomaticInstall(License license) {
101 checkLicense(license);
102 changeStatusFromTo(NONE, AUTOMATIC_IN_PROGRESS);
103 this.pendingLicense = license.getContent();
104 this.pendingEditionKey = license.getEditionKey();
106 return this.pendingInstallationStatus;
110 public synchronized PendingStatus startManualInstall(License license) {
111 checkLicense(license);
112 changeStatusFromTo(NONE, MANUAL_IN_PROGRESS);
113 this.pendingLicense = license.getContent();
114 this.pendingEditionKey = license.getEditionKey();
115 this.pendingInstallationStatus = MANUAL_IN_PROGRESS;
117 return this.pendingInstallationStatus;
121 public synchronized PendingStatus newEditionWithoutInstall(String newEditionKey) {
122 requireNonNull(newEditionKey, "newEditionKey can't be null");
123 checkArgument(!newEditionKey.isEmpty(), "newEditionKey can't be empty");
124 changeStatusFromTo(NONE, NONE);
125 this.currentEditionKey = newEditionKey;
127 return this.pendingInstallationStatus;
131 public synchronized PendingStatus automaticInstallReady() {
132 changeStatusFromTo(AUTOMATIC_IN_PROGRESS, AUTOMATIC_READY);
134 return this.pendingInstallationStatus;
138 public synchronized PendingStatus finalizeInstallation() {
139 checkState(this.pendingInstallationStatus == AUTOMATIC_READY || this.pendingInstallationStatus == MANUAL_IN_PROGRESS,
140 "Can't finalize installation when state is %s", this.pendingInstallationStatus);
142 this.pendingInstallationStatus = NONE;
143 this.currentEditionKey = this.pendingEditionKey;
144 this.pendingEditionKey = null;
145 this.pendingLicense = null;
147 return this.pendingInstallationStatus;
150 private void changeStatusFromTo(PendingStatus expectedStatus, PendingStatus newStatus) {
151 checkState(pendingInstallationStatus == expectedStatus,
152 "Can't move to {} when status is {} (should be {})",
153 newStatus, pendingInstallationStatus, expectedStatus);
154 this.pendingInstallationStatus = newStatus;
157 private void persistProperties() {
158 try (DbSession dbSession = dbClient.openSession(false)) {
159 InternalPropertiesDao internalPropertiesDao = dbClient.internalPropertiesDao();
160 if (pendingInstallationStatus == NONE) {
161 internalPropertiesDao.saveAsEmpty(dbSession, PENDING_EDITION_KEY);
162 internalPropertiesDao.saveAsEmpty(dbSession, PENDING_LICENSE);
164 internalPropertiesDao.save(dbSession, PENDING_EDITION_KEY, pendingEditionKey);
165 internalPropertiesDao.save(dbSession, PENDING_LICENSE, pendingLicense);
167 if (currentEditionKey == null) {
168 internalPropertiesDao.saveAsEmpty(dbSession, CURRENT_EDITION_KEY);
170 internalPropertiesDao.save(dbSession, CURRENT_EDITION_KEY, currentEditionKey);
172 internalPropertiesDao.save(dbSession, PENDING_INSTALLATION_STATUS, pendingInstallationStatus.name());
177 private static void checkLicense(License license) {
178 requireNonNull(license, "license can't be null");
181 private static String emptyToNull(String s) {
182 return s.isEmpty() ? null : s;