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