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 */
020 package org.sonar.server.platform;
021
022 import org.apache.commons.configuration.BaseConfiguration;
023 import org.slf4j.LoggerFactory;
024 import org.sonar.api.Plugins;
025 import org.sonar.api.platform.ComponentContainer;
026 import org.sonar.api.platform.Server;
027 import org.sonar.api.profiles.AnnotationProfileParser;
028 import org.sonar.api.profiles.XMLProfileParser;
029 import org.sonar.api.profiles.XMLProfileSerializer;
030 import org.sonar.api.resources.Languages;
031 import org.sonar.api.resources.ResourceTypes;
032 import org.sonar.api.rules.AnnotationRuleParser;
033 import org.sonar.api.rules.DefaultRulesManager;
034 import org.sonar.api.rules.XMLRuleParser;
035 import org.sonar.api.utils.HttpDownloader;
036 import org.sonar.api.utils.IocContainer;
037 import org.sonar.api.utils.TimeProfiler;
038 import org.sonar.core.PicoUtils;
039 import org.sonar.core.i18n.GwtI18n;
040 import org.sonar.core.i18n.I18nManager;
041 import org.sonar.core.i18n.RuleI18nManager;
042 import org.sonar.core.metric.DefaultMetricFinder;
043 import org.sonar.core.notification.DefaultNotificationManager;
044 import org.sonar.core.persistence.*;
045 import org.sonar.core.qualitymodel.DefaultModelFinder;
046 import org.sonar.core.rule.DefaultRuleFinder;
047 import org.sonar.core.user.DefaultUserFinder;
048 import org.sonar.jpa.dao.DaoFacade;
049 import org.sonar.jpa.dao.MeasuresDao;
050 import org.sonar.jpa.dao.ProfilesDao;
051 import org.sonar.jpa.dao.RulesDao;
052 import org.sonar.jpa.session.DatabaseSessionFactory;
053 import org.sonar.jpa.session.DatabaseSessionProvider;
054 import org.sonar.jpa.session.DefaultDatabaseConnector;
055 import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
056 import org.sonar.server.charts.ChartFactory;
057 import org.sonar.server.configuration.Backup;
058 import org.sonar.server.configuration.ProfilesManager;
059 import org.sonar.server.database.EmbeddedDatabaseFactory;
060 import org.sonar.server.filters.FilterExecutor;
061 import org.sonar.server.notifications.NotificationService;
062 import org.sonar.server.notifications.reviews.ReviewsNotificationManager;
063 import org.sonar.server.plugins.*;
064 import org.sonar.server.qualitymodel.DefaultModelManager;
065 import org.sonar.server.rules.ProfilesConsole;
066 import org.sonar.server.rules.RulesConsole;
067 import org.sonar.server.startup.*;
068 import org.sonar.server.ui.CodeColorizers;
069 import org.sonar.server.ui.JRubyI18n;
070 import org.sonar.server.ui.SecurityRealmFactory;
071 import org.sonar.server.ui.Views;
072
073 import javax.servlet.ServletContext;
074
075 /**
076 * @since 2.2
077 */
078 public final class Platform {
079
080 private static final Platform INSTANCE = new Platform();
081
082 private ComponentContainer rootContainer;// level 1 : only database connectors
083 private ComponentContainer coreContainer;// level 2 : level 1 + core components
084 private ComponentContainer servicesContainer;// level 3 : level 2 + plugin extensions + core components that depend on plugin extensions
085
086 private boolean connected = false;
087 private boolean started = false;
088
089 public static Platform getInstance() {
090 return INSTANCE;
091 }
092
093 private Platform() {
094 }
095
096 public void init(ServletContext servletContext) {
097 if (!connected) {
098 try {
099 startDatabaseConnectors(servletContext);
100 connected = true;
101
102 } catch (RuntimeException e) {
103 // full stacktrace is lost by jruby. It must be logged now.
104 Throwable initialException = PicoUtils.sanitize(e);
105 LoggerFactory.getLogger(getClass()).error(initialException.getMessage(), initialException);
106 PicoUtils.propagateStartupException(initialException);
107 }
108 }
109 }
110
111 public void start() {
112 if (!started && getDatabaseStatus() == DatabaseVersion.Status.UP_TO_DATE) {
113 try {
114 TimeProfiler profiler = new TimeProfiler().start("Start components");
115 startCoreComponents();
116 startServiceComponents();
117 executeStartupTasks();
118 started = true;
119 profiler.stop();
120 } catch (RuntimeException e) {
121 // full stacktrace is lost by jruby. It must be logged now.
122 Throwable initialException = PicoUtils.sanitize(e);
123 LoggerFactory.getLogger(getClass()).error(initialException.getMessage(), initialException);
124 PicoUtils.propagateStartupException(initialException);
125 }
126 }
127 }
128
129 private void startDatabaseConnectors(ServletContext servletContext) {
130 rootContainer = new ComponentContainer();
131 rootContainer.addSingleton(servletContext);
132 rootContainer.addSingleton(IocContainer.class); // for backward compatibility
133 rootContainer.addSingleton(new BaseConfiguration());
134 rootContainer.addSingleton(ServerSettings.class);
135 rootContainer.addSingleton(ServerImpl.class);
136 rootContainer.addSingleton(EmbeddedDatabaseFactory.class);
137 rootContainer.addSingleton(DefaultDatabase.class);
138 rootContainer.addSingleton(MyBatis.class);
139 rootContainer.addSingleton(DefaultServerUpgradeStatus.class);
140 rootContainer.addSingleton(DatabaseServerCompatibility.class);
141 rootContainer.addSingleton(DatabaseMigrator.class);
142 rootContainer.addSingleton(DatabaseVersion.class);
143 for (Class daoClass : DaoUtils.getDaoClasses()) {
144 rootContainer.addSingleton(daoClass);
145 }
146 rootContainer.addSingleton(PluginDeployer.class);
147 rootContainer.addSingleton(DefaultServerPluginRepository.class);
148 rootContainer.addSingleton(DefaultServerFileSystem.class);
149 rootContainer.addSingleton(ApplicationDeployer.class);
150 rootContainer.startComponents();
151 }
152
153 private DatabaseVersion.Status getDatabaseStatus() {
154 DatabaseVersion version = getContainer().getComponentByType(DatabaseVersion.class);
155 return version.getStatus();
156 }
157
158 private void startCoreComponents() {
159 coreContainer = rootContainer.createChild();
160 coreContainer.addSingleton(ServerDatabaseSettingsLoader.class);
161 coreContainer.addSingleton(DefaultDatabaseConnector.class);
162 coreContainer.addSingleton(ServerExtensionInstaller.class);
163 coreContainer.addSingleton(ThreadLocalDatabaseSessionFactory.class);
164 coreContainer.addPicoAdapter(new DatabaseSessionProvider());
165 coreContainer.startComponents();
166 }
167
168 /**
169 * plugin extensions + all the components that depend on plugin extensions
170 */
171 private void startServiceComponents() {
172 servicesContainer = coreContainer.createChild();
173 ServerExtensionInstaller extensionRegistrar = servicesContainer.getComponentByType(ServerExtensionInstaller.class);
174 extensionRegistrar.registerExtensions(servicesContainer);
175
176 servicesContainer.addSingleton(GlobalSettingsUpdater.class);
177 servicesContainer.addSingleton(HttpDownloader.class);
178 servicesContainer.addSingleton(UpdateCenterClient.class);
179 servicesContainer.addSingleton(UpdateCenterMatrixFactory.class);
180 servicesContainer.addSingleton(PluginDownloader.class);
181 servicesContainer.addSingleton(ServerIdGenerator.class);
182 servicesContainer.addComponent(FilterExecutor.class, false);
183 servicesContainer.addSingleton(DefaultModelFinder.class); // depends on plugins
184 servicesContainer.addSingleton(DefaultModelManager.class);
185 servicesContainer.addSingleton(Plugins.class);
186 servicesContainer.addSingleton(ChartFactory.class);
187 servicesContainer.addSingleton(Languages.class);
188 servicesContainer.addSingleton(Views.class);
189 servicesContainer.addSingleton(CodeColorizers.class);
190 servicesContainer.addComponent(RulesDao.class, false);
191 servicesContainer.addComponent(MeasuresDao.class, false);
192 servicesContainer.addComponent(org.sonar.api.database.daos.MeasuresDao.class, false);
193 servicesContainer.addComponent(ProfilesDao.class, false);
194 servicesContainer.addComponent(DaoFacade.class, false);
195 servicesContainer.addComponent(DefaultRulesManager.class, false);
196 servicesContainer.addComponent(ProfilesManager.class, false);
197 servicesContainer.addComponent(Backup.class, false);
198 servicesContainer.addSingleton(SecurityRealmFactory.class);
199 servicesContainer.addSingleton(ServerLifecycleNotifier.class);
200 servicesContainer.addSingleton(AnnotationProfileParser.class);
201 servicesContainer.addSingleton(XMLProfileParser.class);
202 servicesContainer.addSingleton(XMLProfileSerializer.class);
203 servicesContainer.addSingleton(AnnotationRuleParser.class);
204 servicesContainer.addSingleton(XMLRuleParser.class);
205 servicesContainer.addSingleton(DefaultRuleFinder.class);
206 servicesContainer.addSingleton(DefaultMetricFinder.class);
207 servicesContainer.addSingleton(ProfilesConsole.class);
208 servicesContainer.addSingleton(RulesConsole.class);
209 servicesContainer.addSingleton(JRubyI18n.class);
210 servicesContainer.addSingleton(DefaultUserFinder.class);
211 servicesContainer.addSingleton(I18nManager.class);
212 servicesContainer.addSingleton(RuleI18nManager.class);
213 servicesContainer.addSingleton(GwtI18n.class);
214 servicesContainer.addSingleton(ResourceTypes.class);
215
216 // Notifications
217 servicesContainer.addSingleton(NotificationService.class);
218 servicesContainer.addSingleton(DefaultNotificationManager.class);
219 servicesContainer.addSingleton(ReviewsNotificationManager.class);
220
221 servicesContainer.startComponents();
222 }
223
224 private void executeStartupTasks() {
225 ComponentContainer startupContainer = servicesContainer.createChild();
226 startupContainer.addSingleton(GwtPublisher.class);
227 startupContainer.addSingleton(RegisterMetrics.class);
228 startupContainer.addSingleton(RegisterRules.class);
229 startupContainer.addSingleton(RegisterProvidedProfiles.class);
230 startupContainer.addSingleton(EnableProfiles.class);
231 startupContainer.addSingleton(ActivateDefaultProfiles.class);
232 startupContainer.addSingleton(JdbcDriverDeployer.class);
233 startupContainer.addSingleton(ServerMetadataPersister.class);
234 startupContainer.addSingleton(RegisterQualityModels.class);
235 startupContainer.addSingleton(DeleteDeprecatedMeasures.class);
236 startupContainer.addSingleton(GeneratePluginIndex.class);
237 startupContainer.addSingleton(RegisterNewDashboards.class);
238 startupContainer.startComponents();
239
240 startupContainer.getComponentByType(ServerLifecycleNotifier.class).notifyStart();
241
242 // Do not put the following statements in a finally block.
243 // It would hide the possible exception raised during startup
244 // See SONAR-3107
245 startupContainer.stopComponents();
246 servicesContainer.removeChild();
247 servicesContainer.getComponentByType(DatabaseSessionFactory.class).clear();
248 }
249
250 public void stop() {
251 if (rootContainer != null) {
252 try {
253 TimeProfiler profiler = new TimeProfiler().start("Stop sonar");
254 rootContainer.stopComponents();
255 rootContainer = null;
256 connected = false;
257 started = false;
258 profiler.stop();
259 } catch (Exception e) {
260 LoggerFactory.getLogger(getClass()).debug("Fail to stop Sonar - ignored", e);
261 }
262 }
263 }
264
265 public ComponentContainer getContainer() {
266 if (servicesContainer != null) {
267 return servicesContainer;
268 }
269 if (coreContainer != null) {
270 return coreContainer;
271 }
272 return rootContainer;
273 }
274
275 public Object getComponent(Object key) {
276 return getContainer().getComponentByKey(key);
277 }
278
279 /**
280 * shortcut for ruby code
281 */
282 public static Server getServer() {
283 return (Server) getInstance().getComponent(Server.class);
284 }
285 }