/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2016 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.server.http.webapp.symmetricDS;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.sql.DataSource;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.stereotype.Component;
import com.google.common.io.Files;
import com.jolbox.bonecp.BoneCPDataSource;
import fr.gael.dhus.server.ScalabilityManager;
import fr.gael.dhus.server.http.webapp.WebApp;
import fr.gael.dhus.server.http.webapp.WebApplication;
import fr.gael.dhus.system.config.ConfigurationManager;
@Component
@WebApp(name = "sync", scalability="true")
public class SymmetricDSWebapp extends WebApplication implements InitializingBean
{
private static final Logger LOGGER = LogManager.getLogger(SymmetricDSWebapp.class);
@Autowired
BoneCPDataSource dataSource;
@Autowired
ScalabilityManager scalabilityManager;
@Autowired
ConfigurationManager cfgManager;
@Qualifier ("boneCPDataSource")
@Autowired
DataSource datasource;
@Override
public void configure(String dest_folder) throws IOException
{
String configurationFolder = "fr/gael/dhus/server/http/webapp/symmetricDS/web";
URL u = Thread.currentThread().getContextClassLoader()
.getResource(configurationFolder);
if (u != null && "jar".equals(u.getProtocol()))
{
extractJarFolder(u, configurationFolder, dest_folder);
}
else if (u != null)
{
File webAppFolder = new File(dest_folder);
copyFolder(new File(u.getFile()), webAppFolder);
}
String properties = "fr/gael/dhus/server/http/webapp/symmetricDS/"+
(scalabilityManager.isMaster () ? "master" : "replica")
+".properties";
u = Thread.currentThread().getContextClassLoader()
.getResource(properties);
String propFile = dest_folder+"/WEB-INF/classes/symmetric.properties";
if (u != null && "jar".equals(u.getProtocol()))
{
extractJarFile(u, properties, propFile);
}
else if (u != null)
{
File webAppFolder = new File(propFile);
Files.copy (new File(u.getFile()), webAppFolder);
}
Path path = Paths.get(propFile);
Charset charset = StandardCharsets.UTF_8;
String content = new String(java.nio.file.Files.readAllBytes(path), charset);
content = content.replaceAll("%id%", String.format("%03d", scalabilityManager.getReplicaId ()));
content = content.replaceAll("%masterUrl%", scalabilityManager.getMasterUrl ());
content = content.replaceAll("%localUrl%", scalabilityManager.getLocalUrl ());
content = content.replaceAll("%dbDriver%", dataSource.getDriverClass ());
content = content.replaceAll("%dbUrl%", dataSource.getJdbcUrl ());
content = content.replaceAll("%dbUser%", dataSource.getUsername ());
content = content.replaceAll("%dbPassword%", dataSource.getPassword ());
java.nio.file.Files.write(path, content.getBytes(charset));
}
@Override
public InputStream getWarStream()
{
return SymmetricDSWebapp.class.getClassLoader().getResourceAsStream(
"fr/gael/dhus/server/http/webapp/symmetricDS/symmetric-ds.war");
}
@Override
public boolean hasWarStream()
{
return true;
}
@Override
public void afterPropertiesSet() throws Exception
{
if (!scalabilityManager.getClearDB ())
{
return;
}
PreparedStatement ps = datasource.getConnection ().prepareStatement (
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME LIKE 'SYM_%';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery ();
while (rs.next ())
{
PreparedStatement ps2 = datasource.getConnection ().prepareStatement (
"DROP TRIGGER " +
rs.getString ("TRIGGER_NAME"));
ps2.execute ();
ps2.close ();
}
ps.close ();
ps = datasource.getConnection ().prepareStatement (
"SELECT CONSTRAINT_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME LIKE 'SYM_%';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = ps.executeQuery ();
while (rs.next ())
{
PreparedStatement ps2 = datasource.getConnection ().prepareStatement (
"ALTER TABLE "+rs.getString ("TABLE_NAME")+" DROP CONSTRAINT " +
rs.getString ("CONSTRAINT_NAME"));
ps2.execute ();
ps2.close ();
}
ps.close ();
ps = datasource.getConnection ().prepareStatement (
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'SYM_%';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = ps.executeQuery ();
while (rs.next ())
{
PreparedStatement ps2 = datasource.getConnection ().prepareStatement (
"DROP TABLE " +
rs.getString ("TABLE_NAME"));
ps2.execute ();
ps2.close ();
}
ps.close ();
}
@Override
public void checkInstallation() throws Exception
{
if (!scalabilityManager.isMaster ()) return;
// Check database is ready for SymmetricDS
PreparedStatement ps = datasource.getConnection ().prepareStatement (
"SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME='SYM_FK_TRGPLT_2_TR';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
while (!ps.executeQuery ().first ())
{
try
{
Thread.sleep (1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ps.close ();
// Check if init.sql has already been executed
ps = datasource.getConnection ().prepareStatement (
"SELECT node_group_id FROM SYM_NODE_GROUP WHERE node_group_id = 'dhus-replica-group';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
if (!ps.executeQuery ().first ())
{
// Wait for master group to be inserted
PreparedStatement ps2 = datasource.getConnection ().prepareStatement (
"SELECT * FROM SYM_NODE_GROUP WHERE node_group_id='dhus-master-group';",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
while (!ps2.executeQuery ().first ())
{
try
{
Thread.sleep (1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ps2.close ();
ScriptUtils.executeSqlScript (datasource.getConnection (),
new ClassPathResource("fr/gael/dhus/server/http/webapp/symmetricDS/init.sql"));
LOGGER.info("SymmetricDS initialization script loaded");
// Force the synchronizers to be reloaded
HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost(cfgManager.getServerConfiguration().getLocalUrl() + "/sync/api/engine/synctriggers");
httpclient.execute(httppost);
}
ps.close ();
}
}