Move HSQLDB checkpoint/shutdown to a bean specific to the legacy profile

master
François-Xavier Thomas 5 years ago
parent b88bdb37c9
commit 76e8abd219
  1. 6
      airsonic-main/src/main/java/org/airsonic/player/Application.java
  2. 4
      airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java
  3. 35
      airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java
  4. 60
      airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java
  5. 55
      airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java
  6. 10
      airsonic-main/src/main/resources/applicationContext-db-legacy.xml
  7. 14
      airsonic-main/src/main/resources/applicationContext-db.xml

@ -2,7 +2,6 @@ package org.airsonic.player;
import net.sf.ehcache.constructs.web.ShutdownListener;
import org.airsonic.player.filter.*;
import org.airsonic.player.spring.TerminateBean;
import org.directwebremoting.servlet.DwrServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -57,11 +56,6 @@ public class Application extends SpringBootServletInitializer implements Embedde
return servlet;
}
@Bean
public TerminateBean terminateBean() {
return new TerminateBean();
}
@Bean
public ServletRegistrationBean cxfServletBean() {
return new ServletRegistrationBean(new org.apache.cxf.transport.servlet.CXFServlet(), "/ws/*");

@ -53,7 +53,7 @@ public interface DaoHelper {
* Database checkpoints will make sure that the database is written on the disk
* and optimize on-disk storage.
*
* @return true if the checkpoint succeeded
* @return true if the checkpoint succeeded, false otherwise
*/
public boolean checkpoint();
public default boolean checkpoint() { return false; }
}

@ -4,13 +4,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
public class GenericDaoHelper implements DaoHelper {
private static final Logger LOG = LoggerFactory.getLogger(GenericDaoHelper.class);
@ -43,35 +39,4 @@ public class GenericDaoHelper implements DaoHelper {
public DataSource getDataSource() {
return dataSource;
}
@Override
public boolean checkpoint() {
try {
Connection conn = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource());
DatabaseMetaData meta = conn.getMetaData();
String productName = meta.getDatabaseProductName();
int productVersion = meta.getDatabaseMajorVersion();
// HSQLDB (at least version 1) does not handle automatic checkpoints very well by default.
// This makes sure the temporary log is actually written to more persistent storage.
if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) {
LOG.info("Performing database checkpoint");
getJdbcTemplate().execute("CHECKPOINT DEFRAG");
return true;
} else {
LOG.debug("Database checkpoint not implemented for '" + productName + "'");
return false;
}
}
// Since this method is a best-effort operation, we don't want to show
// a message if the checkpoint failed ; just assume the operation is
// unsupported.
catch(java.sql.SQLException e) {
LOG.debug("An exception occurred during database checkpoint: " + e.toString());
}
return false;
}
}

@ -0,0 +1,60 @@
package org.airsonic.player.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Special Dao Helper with additional features for managing the legacy embedded HSQL database.
*/
public class LegacyHsqlDaoHelper extends GenericDaoHelper {
private static final Logger LOG = LoggerFactory.getLogger(LegacyHsqlDaoHelper.class);
public LegacyHsqlDaoHelper(DataSource dataSource) {
super(dataSource);
}
@Override
public boolean checkpoint() {
// HSQLDB (at least version 1) does not handle automatic checkpoints very well by default.
// This makes sure the temporary log is actually written to more persistent storage.
LOG.info("Database checkpoint in progress...");
getJdbcTemplate().execute("CHECKPOINT DEFRAG");
LOG.info("Database checkpoint complete.");
return true;
}
@PreDestroy
public void onDestroy() {
Connection conn = null;
try {
// Properly shutdown the embedded HSQLDB database.
LOG.info("Database shutdown in progress...");
JdbcTemplate jdbcTemplate = getJdbcTemplate();
conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
conn.setAutoCommit(true);
jdbcTemplate.execute("SHUTDOWN");
LOG.info("Database shutdown complete.");
} catch (SQLException e) {
LOG.error("Database shutdown failed: " + e);
e.printStackTrace();
} finally {
try {
if(conn != null)
conn.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}

@ -1,55 +0,0 @@
package org.airsonic.player.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.annotation.PreDestroy;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
public class TerminateBean {
private static final Logger LOG = LoggerFactory.getLogger(TerminateBean.class);
@Autowired
private ApplicationContext context;
@PreDestroy
public void onDestroy() {
Connection conn = null;
try {
// Connect to the database and retrieve the db name and version
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.context.getBean(DataSource.class));
conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
DatabaseMetaData meta = conn.getMetaData();
String productName = meta.getDatabaseProductName();
int productVersion = meta.getDatabaseMajorVersion();
// Properly shutdown HSQLDB databases
if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) {
LOG.info("Database shutdown in progress...");
conn.setAutoCommit(true);
jdbcTemplate.execute("SHUTDOWN");
LOG.info("Database shutdown complete.");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(conn != null)
conn.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
}

@ -6,11 +6,17 @@
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="#{T(org.airsonic.player.service.SettingsService).defaultJDBCUrl}" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
</beans>
<!-- Overwrite the GenericDaoHelper bean defined in applicationContext-db.xml -->
<!-- This bean is specific to the legacy embedded HSQLDB database -->
<bean id="daoHelper" class="org.airsonic.player.dao.LegacyHsqlDaoHelper">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
</beans>

@ -3,12 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="applicationContext-db-jndi.xml" />
<import resource="applicationContext-db-embed.xml" />
<import resource="applicationContext-db-legacy.xml" />
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
@ -17,6 +11,12 @@
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<import resource="applicationContext-db-jndi.xml" />
<import resource="applicationContext-db-embed.xml" />
<import resource="applicationContext-db-legacy.xml" />
<tx:annotation-driven/>
<bean id="rollbackFile" class="java.io.File">
<constructor-arg type="java.io.File" index="0" value="#{T(org.airsonic.player.service.SettingsService).airsonicHome}" />
<constructor-arg type="java.lang.String" index="1" value="rollback.sql" />
@ -38,4 +38,4 @@
</map>
</property>
</bean>
</beans>
</beans>

Loading…
Cancel
Save