Java tutorial
/* Copyright (c) 2008 Pyxis Technologies inc. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: * http://www.fsf.org. */ package info.novatec.testit.livingdoc.confluence; import java.io.File; import java.util.Properties; import org.hibernate.dialect.HSQLDialect; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import com.atlassian.bandana.BandanaContext; import com.atlassian.bandana.BandanaManager; import com.atlassian.confluence.event.events.plugin.PluginDisableEvent; import com.atlassian.confluence.event.events.plugin.PluginEnableEvent; import com.atlassian.confluence.event.events.plugin.PluginFrameworkStartedEvent; import com.atlassian.confluence.event.events.plugin.PluginInstallEvent; import com.atlassian.confluence.event.events.plugin.PluginUninstallEvent; import com.atlassian.confluence.setup.BootstrapManager; import com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext; import com.atlassian.event.api.EventListener; import com.atlassian.event.api.EventPublisher; import com.google.gson.Gson; import info.novatec.testit.livingdoc.confluence.utils.osgi.BundleFileLocatorHelper; import info.novatec.testit.livingdoc.server.LivingDocServer; import info.novatec.testit.livingdoc.server.LivingDocServerErrorKey; import info.novatec.testit.livingdoc.server.LivingDocServerException; import info.novatec.testit.livingdoc.server.LivingDocServerServiceImpl; import info.novatec.testit.livingdoc.server.configuration.DefaultServerProperties; import info.novatec.testit.livingdoc.server.database.SessionService; import info.novatec.testit.livingdoc.server.database.hibernate.BootstrapData; import info.novatec.testit.livingdoc.server.database.hibernate.HibernateSessionService; import info.novatec.testit.livingdoc.server.domain.dao.DocumentDao; import info.novatec.testit.livingdoc.server.domain.dao.ProjectDao; import info.novatec.testit.livingdoc.server.domain.dao.RepositoryDao; import info.novatec.testit.livingdoc.server.domain.dao.SystemUnderTestDao; import info.novatec.testit.livingdoc.server.domain.dao.hibernate.HibernateDocumentDao; import info.novatec.testit.livingdoc.server.domain.dao.hibernate.HibernateProjectDao; import info.novatec.testit.livingdoc.server.domain.dao.hibernate.HibernateRepositoryDao; import info.novatec.testit.livingdoc.server.domain.dao.hibernate.HibernateSystemUnderTestDao; import info.novatec.testit.livingdoc.server.rpc.xmlrpc.LivingDocXmlRpcServer; /** * This component is responsible to bootstrap the LivingDoc database * and manage it's state and configuration data. * * Note: The {@link BandanaManager} has some problems storing classes * (ClassCastException during a re installation), so you should store objects * only as string (e.g. using Gson). */ public class LivingDocServerConfigurationActivator implements InitializingBean, DisposableBean { private static final Logger log = LoggerFactory.getLogger(LivingDocServerConfigurationActivator.class); private static final String EXECUTION_TIMEOUT_DEFAULT = "60"; private final BandanaContext bandanaContext = new ConfluenceBandanaContext("_LIVINGDOC"); private LivingDocServerConfiguration configuration; private HibernateSessionService hibernateSessionService; private boolean isPluginEnabled = false; /** * If you want to check if the database has been created before use the * {@code LivingDocServerConfiguration#isSetupComplete()} method of * {@link #getConfiguration()} */ private boolean isDatabaseInitialized = false; private final BandanaManager bandanaManager; private final BootstrapManager bootstrapManager; private final LivingDocServerServiceImpl service; private final LivingDocXmlRpcServer xmlRpcServer; private final EventPublisher eventPublisher; private Gson gson; public LivingDocServerConfigurationActivator(BootstrapManager bootstrapManager, BandanaManager bandanaManager, LivingDocServerServiceImpl service, LivingDocXmlRpcServer xmlRpcServer, EventPublisher eventPublisher) { this.bootstrapManager = bootstrapManager; this.bandanaManager = bandanaManager; this.service = service; this.xmlRpcServer = xmlRpcServer; this.eventPublisher = eventPublisher; } @Override public void afterPropertiesSet() throws Exception { this.gson = new Gson(); this.eventPublisher.register(this); } public boolean isReady() { return isPluginEnabled && isDatabaseInitialized; } /** * Note that you should check if the configuration setup was already * completed before using this method. * * @throws LivingDocServerException */ public void setupDatabaseFromStoredConfiguration() throws LivingDocServerException { LivingDocServerConfiguration storedConfiguration = getConfiguration(); setupDatabaseFromConfiguration(storedConfiguration); } private void setupDatabaseFromConfiguration(LivingDocServerConfiguration customConfiguration) throws LivingDocServerException { if (!isPluginEnabled) return; try { isDatabaseInitialized = false; closeSession(); Properties properties = customConfiguration.getProperties(); properties.setProperty("confluence.home", getConfluenceHome()); if (properties.getProperty("executionTimeout") == null) { properties.setProperty("executionTimeout", EXECUTION_TIMEOUT_DEFAULT); } HibernateSessionService sessionService = new HibernateSessionService(properties); // Do we really need to bootstrap the data again and again? initializeBootstrapData(sessionService, properties); initializeXmlRpcServerFromSession(sessionService); hibernateSessionService = sessionService; customConfiguration.setSetupComplete(true); // Override the current configuration. this.configuration = customConfiguration; storeConfiguration(customConfiguration); isDatabaseInitialized = true; } catch (Exception ex) { log.error("Failed to initialize LivingDoc database.", ex); throw new LivingDocServerException(LivingDocServerErrorKey.GENERAL_ERROR, ex); } } private void initializeBootstrapData(SessionService customSessionService, Properties properties) throws Exception { // Since we're in a OSGI context, our plugin isn't stored in the // WEB-INF folder any more. Therefore we had to implement a // new way to detect the livingdoc jar (which is needed as // classpath element for the demo runner). String currentBundleFilePath = getLivingDocBundleFilePath(); log.debug("Boostrapping datas"); properties.setProperty("livingdoc.path", currentBundleFilePath); new BootstrapData(customSessionService, properties).execute(); } private void initializeXmlRpcServerFromSession(HibernateSessionService customSessionService) { ProjectDao projectDao = new HibernateProjectDao(customSessionService); RepositoryDao repositoryDao = new HibernateRepositoryDao(customSessionService); SystemUnderTestDao sutDao = new HibernateSystemUnderTestDao(customSessionService); DocumentDao documentDao = new HibernateDocumentDao(customSessionService); service.setDocumentDao(documentDao); service.setProjectDao(projectDao); service.setRepositoryDao(repositoryDao); service.setSessionService(customSessionService); service.setSutDao(sutDao); service.setSessionService(customSessionService); xmlRpcServer.setService(service); } private String getLivingDocBundleFilePath() throws Exception { Bundle bundle = FrameworkUtil.getBundle(getClass()); BundleFileLocatorHelper helper = StaticAccessor.getBundleFileLocatorHelper(); File location = helper.getBundleInstallLocation(bundle); String pathToBundle = location.getAbsolutePath(); return pathToBundle; } private void closeSession() { if (hibernateSessionService != null) { hibernateSessionService.close(); } hibernateSessionService = null; isDatabaseInitialized = false; } /** * Returns the stored configuration or creates a new one if none exists. * * @return */ public LivingDocServerConfiguration getConfiguration() { if (configuration == null) { configuration = getConfigurationFromBandana(); } return configuration; } public void storeConfiguration(LivingDocServerConfiguration configuration) { // @todo : sanity check over the previous configuration storeConfigurationToBandana(configuration); } private LivingDocServerConfiguration getConfigurationFromBandana() { LivingDocServerConfiguration configuration = getValue(LivingDocServerConfiguration.class); if (configuration == null) { configuration = new LivingDocServerConfiguration(); storeConfigurationToBandana(configuration); } return configuration; } private void storeConfigurationToBandana(LivingDocServerConfiguration configuration) { setValue(LivingDocServerConfiguration.class, configuration); } private <T> T getValue(Class<T> classKey) { String storedJsonObject = (String) bandanaManager.getValue(bandanaContext, classKey.getName()); T castedObject = gson.fromJson(storedJsonObject, classKey); return castedObject; } private void setValue(Class<?> classKey, Object value) { String jsobObject = gson.toJson(value); bandanaManager.setValue(bandanaContext, classKey.getName(), jsobObject); } private void removeValue(Class<?> classKey) { bandanaManager.removeValue(bandanaContext, classKey.getName()); } public String getConfigJnriUrl() { return (String) getConfiguration().getProperties().get("config$hibernate.connection.datasource"); } public String getConfigDialect() { return (String) getConfiguration().getProperties().get("config$hibernate.dialect"); } public void initQuickInstallConfiguration() throws LivingDocServerException { LivingDocServerConfiguration customConfiguration = getConfiguration(); Properties properties = new DefaultServerProperties(); properties.put("hibernate.c3p0.acquire_increment", "1"); properties.put("hibernate.c3p0.idle_test_period", "100"); properties.put("hibernate.c3p0.max_size", "15"); properties.put("hibernate.c3p0.max_statements", "0"); properties.put("hibernate.c3p0.min_size", "0"); properties.put("hibernate.c3p0.timeout", "30"); properties.remove("hibernate.connection.datasource"); // direct jdbc properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); properties.put("hibernate.connection.url", "jdbc:hsqldb:" + getConfluenceHome() + "/database/ldsdb"); properties.put("hibernate.connection.username", "sa"); properties.put("hibernate.connection.password", ""); properties.put("hibernate.dialect", HSQLDialect.class.getName()); configuration.setProperties(properties); setupDatabaseFromConfiguration(customConfiguration); } public void initCustomInstallConfiguration(String hibernateDialect, String jndiUrl) throws LivingDocServerException { LivingDocServerConfiguration customConfiguration = getConfiguration(); Properties properties = new DefaultServerProperties(); properties.put("hibernate.connection.datasource", jndiUrl); properties.put("config$hibernate.connection.datasource", jndiUrl); properties.put("hibernate.dialect", hibernateDialect); properties.put("config$hibernate.dialect", hibernateDialect); // properties.put("hibernate.show_sql", "true"); if (hibernateDialect.indexOf("Oracle") != -1) { // The Oracle JDBC driver doesn't like prepared statement caching // very much. properties.put("hibernate.statement_cache.size", "0"); // or baching with BLOBs very much. properties.put("hibernate.jdbc.batch_size", "0"); // http://www.jroller.com/dashorst/entry/hibernate_3_1_something_performance1 properties.put("hibernate.jdbc.wrap_result_sets", "true"); } configuration.setProperties(properties); setupDatabaseFromConfiguration(customConfiguration); } private String getConfluenceHome() { // https://developer.atlassian.com/pages/viewpage.action?pageId=2031761#HowdoIensuremyadd-onworksproperlyinacluster?-ClusterHomeDirectoryHomeDirectory return bootstrapManager.getSharedHome().getAbsolutePath(); } @EventListener public void pluginFrameworkStartedEvent(PluginFrameworkStartedEvent event) throws LivingDocServerException { log.info(getClass().getName() + "#" + event.getClass().getName()); log.info(String.format("*** Starting LivingDoc-Confluence-Plugin (v%s) ***", LivingDocServer.VERSION)); enableLivingDocPlugin(); } @EventListener public void pluginInstallEvent(PluginInstallEvent event) throws LivingDocServerException { enableLivingDocPlugin(); } @EventListener public void pluginUninstallEvent(PluginUninstallEvent event) { disableLivingDocPlugin(); // Remove the stored configuration. removeValue(LivingDocServerConfiguration.class); } @EventListener public void pluginEnableEvent(PluginEnableEvent event) throws LivingDocServerException { enableLivingDocPlugin(); } @EventListener public void pluginDisableEvent(PluginDisableEvent event) { disableLivingDocPlugin(); } private void enableLivingDocPlugin() throws LivingDocServerException { isPluginEnabled = true; if (getConfiguration().isSetupComplete()) setupDatabaseFromStoredConfiguration(); } private void disableLivingDocPlugin() { isPluginEnabled = false; closeSession(); } @Override public void destroy() throws Exception { eventPublisher.unregister(this); } }