]> source.dussan.org Git - sonarqube.git/blob
d9debf0e10afddd3d4d822f3bd565ea8321d8a72
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.edition;
21
22 import com.google.common.collect.ImmutableSet;
23 import java.util.Arrays;
24 import java.util.Map;
25 import java.util.Optional;
26 import javax.annotation.Nullable;
27 import org.picocontainer.Startable;
28 import org.sonar.db.DbClient;
29 import org.sonar.db.DbSession;
30 import org.sonar.db.property.InternalPropertiesDao;
31
32 import static com.google.common.base.Preconditions.checkArgument;
33 import static com.google.common.base.Preconditions.checkState;
34 import static java.util.Objects.requireNonNull;
35 import static java.util.Optional.empty;
36 import static org.sonar.server.edition.EditionManagementState.PendingStatus.AUTOMATIC_IN_PROGRESS;
37 import static org.sonar.server.edition.EditionManagementState.PendingStatus.AUTOMATIC_READY;
38 import static org.sonar.server.edition.EditionManagementState.PendingStatus.MANUAL_IN_PROGRESS;
39 import static org.sonar.server.edition.EditionManagementState.PendingStatus.NONE;
40 import static org.sonar.server.edition.EditionManagementState.PendingStatus.UNINSTALL_IN_PROGRESS;
41
42 public class StandaloneEditionManagementStateImpl implements MutableEditionManagementState, Startable {
43   private static final String CURRENT_EDITION_KEY = "currentEditionKey";
44   private static final String PENDING_INSTALLATION_STATUS = "pendingInstallStatus";
45   private static final String PENDING_EDITION_KEY = "pendingEditionKey";
46   private static final String PENDING_LICENSE = "pendingLicense";
47   private static final String INSTALL_ERROR_MESSAGE = "installError";
48
49   private final DbClient dbClient;
50   private String currentEditionKey;
51   private PendingStatus pendingInstallationStatus;
52   private String pendingEditionKey;
53   private String pendingLicense;
54   private String installErrorMessage;
55
56   public StandaloneEditionManagementStateImpl(DbClient dbClient) {
57     this.dbClient = dbClient;
58   }
59
60   @Override
61   public void start() {
62     try (DbSession dbSession = dbClient.openSession(false)) {
63       // load current state value
64       Map<String, Optional<String>> internalPropertyValues = dbClient.internalPropertiesDao().selectByKeys(dbSession,
65         ImmutableSet.of(CURRENT_EDITION_KEY, PENDING_INSTALLATION_STATUS, PENDING_EDITION_KEY, PENDING_LICENSE, INSTALL_ERROR_MESSAGE));
66       this.currentEditionKey = internalPropertyValues.getOrDefault(CURRENT_EDITION_KEY, empty())
67         .map(StandaloneEditionManagementStateImpl::emptyToNull)
68         .orElse(null);
69       this.pendingInstallationStatus = internalPropertyValues.getOrDefault(PENDING_INSTALLATION_STATUS, empty())
70         .map(StandaloneEditionManagementStateImpl::emptyToNull)
71         .map(PendingStatus::valueOf)
72         .orElse(NONE);
73       this.pendingEditionKey = internalPropertyValues.getOrDefault(PENDING_EDITION_KEY, empty())
74         .map(StandaloneEditionManagementStateImpl::emptyToNull)
75         .orElse(null);
76       this.pendingLicense = internalPropertyValues.getOrDefault(PENDING_LICENSE, empty())
77         .map(StandaloneEditionManagementStateImpl::emptyToNull)
78         .orElse(null);
79       this.installErrorMessage = internalPropertyValues.getOrDefault(INSTALL_ERROR_MESSAGE, empty())
80         .map(StandaloneEditionManagementStateImpl::emptyToNull)
81         .orElse(null);
82     }
83   }
84
85   @Override
86   public void stop() {
87     // nothing to do
88   }
89
90   @Override
91   public Optional<String> getCurrentEditionKey() {
92     ensureStarted();
93     return Optional.ofNullable(currentEditionKey);
94   }
95
96   @Override
97   public PendingStatus getPendingInstallationStatus() {
98     ensureStarted();
99     return pendingInstallationStatus;
100   }
101
102   @Override
103   public Optional<String> getPendingEditionKey() {
104     ensureStarted();
105     return Optional.ofNullable(pendingEditionKey);
106   }
107
108   @Override
109   public Optional<String> getPendingLicense() {
110     ensureStarted();
111     return Optional.ofNullable(pendingLicense);
112   }
113
114   @Override
115   public Optional<String> getInstallErrorMessage() {
116     ensureStarted();
117     return Optional.ofNullable(installErrorMessage);
118   }
119
120   @Override
121   public synchronized PendingStatus startAutomaticInstall(License license) {
122     ensureStarted();
123     checkLicense(license);
124     changeStatusToFrom(AUTOMATIC_IN_PROGRESS, NONE);
125     this.pendingLicense = license.getContent();
126     this.pendingEditionKey = license.getEditionKey();
127     this.installErrorMessage = null;
128     persistProperties();
129     return this.pendingInstallationStatus;
130   }
131
132   @Override
133   public synchronized PendingStatus startManualInstall(License license) {
134     ensureStarted();
135     checkLicense(license);
136     changeStatusToFrom(MANUAL_IN_PROGRESS, NONE);
137     this.pendingLicense = license.getContent();
138     this.pendingEditionKey = license.getEditionKey();
139     this.pendingInstallationStatus = MANUAL_IN_PROGRESS;
140     this.installErrorMessage = null;
141     persistProperties();
142     return this.pendingInstallationStatus;
143   }
144
145   @Override
146   public synchronized PendingStatus newEditionWithoutInstall(String newEditionKey) {
147     ensureStarted();
148     requireNonNull(newEditionKey, "newEditionKey can't be null");
149     checkArgument(!newEditionKey.isEmpty(), "newEditionKey can't be empty");
150     changeStatusToFrom(NONE, NONE);
151     this.currentEditionKey = newEditionKey;
152     this.installErrorMessage = null;
153     persistProperties();
154     return this.pendingInstallationStatus;
155   }
156
157   @Override
158   public synchronized PendingStatus automaticInstallReady() {
159     ensureStarted();
160     changeStatusToFrom(AUTOMATIC_READY, AUTOMATIC_IN_PROGRESS);
161     this.installErrorMessage = null;
162     persistProperties();
163     return this.pendingInstallationStatus;
164   }
165
166   @Override
167   public synchronized PendingStatus installFailed(@Nullable String errorMessage) {
168     ensureStarted();
169     changeStatusToFrom(NONE, AUTOMATIC_IN_PROGRESS, AUTOMATIC_READY, MANUAL_IN_PROGRESS);
170     this.installErrorMessage = nullableTrimmedEmptyToNull(errorMessage);
171     this.pendingEditionKey = null;
172     this.pendingLicense = null;
173     persistProperties();
174     return this.pendingInstallationStatus;
175   }
176
177   @Override
178   public synchronized PendingStatus finalizeInstallation() {
179     ensureStarted();
180     changeStatusToFrom(NONE, AUTOMATIC_READY, MANUAL_IN_PROGRESS, UNINSTALL_IN_PROGRESS);
181
182     this.pendingInstallationStatus = NONE;
183     this.currentEditionKey = this.pendingEditionKey;
184     this.pendingEditionKey = null;
185     this.pendingLicense = null;
186     persistProperties();
187     return this.pendingInstallationStatus;
188   }
189
190   @Override
191   public synchronized PendingStatus uninstall() {
192     ensureStarted();
193     changeStatusToFrom(UNINSTALL_IN_PROGRESS, NONE);
194     checkState(currentEditionKey != null, "There is no edition currently installed");
195
196     this.pendingInstallationStatus = UNINSTALL_IN_PROGRESS;
197     this.pendingEditionKey = null;
198     this.pendingLicense = null;
199     this.currentEditionKey = null;
200     persistProperties();
201     return this.pendingInstallationStatus;
202   }
203
204   private void ensureStarted() {
205     checkState(pendingInstallationStatus != null, "%s is not started", getClass().getSimpleName());
206   }
207
208   private void changeStatusToFrom(PendingStatus newStatus, PendingStatus... validPendingStatuses) {
209     checkState(Arrays.stream(validPendingStatuses).anyMatch(s -> s == pendingInstallationStatus),
210       "Can't move to %s when status is %s (should be any of %s)",
211       newStatus, pendingInstallationStatus, Arrays.toString(validPendingStatuses));
212     this.pendingInstallationStatus = newStatus;
213   }
214
215   private void persistProperties() {
216     try (DbSession dbSession = dbClient.openSession(false)) {
217       InternalPropertiesDao internalPropertiesDao = dbClient.internalPropertiesDao();
218       saveInternalProperty(internalPropertiesDao, dbSession, PENDING_EDITION_KEY, pendingEditionKey);
219       saveInternalProperty(internalPropertiesDao, dbSession, PENDING_LICENSE, pendingLicense);
220       saveInternalProperty(internalPropertiesDao, dbSession, INSTALL_ERROR_MESSAGE, installErrorMessage);
221       saveInternalProperty(internalPropertiesDao, dbSession, CURRENT_EDITION_KEY, currentEditionKey);
222       saveInternalProperty(internalPropertiesDao, dbSession, PENDING_INSTALLATION_STATUS, pendingInstallationStatus.name());
223       dbSession.commit();
224     }
225   }
226
227   private static void saveInternalProperty(InternalPropertiesDao dao, DbSession dbSession, String key, @Nullable String value) {
228     if (value == null) {
229       dao.saveAsEmpty(dbSession, key);
230     } else {
231       dao.save(dbSession, key, value);
232     }
233   }
234
235   private static void checkLicense(License license) {
236     requireNonNull(license, "license can't be null");
237   }
238
239   private static String nullableTrimmedEmptyToNull(@Nullable String s) {
240     if (s == null) {
241       return null;
242     }
243     String v = s.trim();
244     return v.isEmpty() ? null : v;
245   }
246
247   private static String emptyToNull(String s) {
248     return s.isEmpty() ? null : s;
249   }
250 }