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 }