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