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 }