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    }