/*******************************************************************************
* Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com>
* This file is part of Gluster Management Gateway.
*
* Gluster Management Gateway 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 3 of the License, or (at your option) any later version.
*
* Gluster Management Gateway 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, see
* <http://www.gnu.org/licenses/>.
*******************************************************************************/
package org.gluster.storage.management.gateway.tasks;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletContext;
import org.apache.derby.tools.ij;
import org.gluster.storage.management.core.constants.CoreConstants;
import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
import org.gluster.storage.management.gateway.data.ClusterInfo;
import org.gluster.storage.management.gateway.data.PersistenceDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
* Initializes the Gluster Management Server.
*/
public class InitServerTask extends JdbcDaoSupport {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SaltSource saltSource;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private String dataVersion;
@Autowired
private PersistenceDao<ClusterInfo> clusterDao;
@Autowired
ServletContext servletContext;
private static final String SCRIPT_DIR = "data/scripts/";
public void securePasswords() {
getJdbcTemplate().query("select username, password from users", new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
UserDetails user = userDetailsService.loadUserByUsername(username);
String encodedPassword = passwordEncoder.encodePassword(password, saltSource.getSalt(user));
getJdbcTemplate().update("update users set password = ? where username = ?", encodedPassword, username);
logger.debug("Updating password for username: " + username);
}
});
}
private void executeScript(File script) {
ByteArrayOutputStream sqlOut = new ByteArrayOutputStream();
int numOfExceptions;
try {
numOfExceptions = ij.runScript(getJdbcTemplate().getDataSource().getConnection(), new FileInputStream(
script), CoreConstants.ENCODING_UTF8, sqlOut, CoreConstants.ENCODING_UTF8);
String output = sqlOut.toString();
sqlOut.close();
logger.debug("Data script [" + script.getName() + "] returned with exit status [" + numOfExceptions
+ "] and output [" + output + "]");
if (numOfExceptions != 0) {
throw new GlusterRuntimeException("Server data initialization script [ " + script.getName()
+ "] failed with [" + numOfExceptions + "] exceptions! [" + output + "]");
}
} catch (Exception ex) {
throw new GlusterRuntimeException("Server data initialization script [" + script.getName() + "] failed!",
ex);
}
}
private void initDatabase() {
logger.info("Initializing server data...");
executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + dataVersion));
securePasswords(); // encrypt the passwords
}
private File getDirFromRelativePath(String relativePath) {
String scriptDirPath = servletContext.getRealPath(relativePath);
File scriptDir = new File(scriptDirPath);
return scriptDir;
}
private void executeScriptsFrom(File scriptDir) {
if (!scriptDir.exists()) {
throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] doesn't exist!");
}
List<File> scripts = Arrays.asList(scriptDir.listFiles());
if(scripts.size() == 0) {
throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] is empty!");
}
Collections.sort(scripts);
for (File script : scripts) {
executeScript(script);
}
}
/**
* Initializes the server database, if running for the first time.
*/
public synchronized void initServer() {
try {
String currentDataVersion = getDataVersion();
if (!dataVersion.equals(currentDataVersion)) {
logger.info("Upgrading data from [" + currentDataVersion + "] to [" + dataVersion + "]...");
upgradeData(currentDataVersion, dataVersion);
}
} catch (Exception ex) {
logger.info("Data version query failed with error [" + ex.getMessage() + "]", ex);
// Database not created yet. Create it!
initDatabase();
}
}
private void upgradeData(String fromVersion, String toVersion) {
executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + fromVersion + "-" + toVersion));
}
private String getDataVersion() {
return (String) clusterDao.getSingleResultFromSQL("select version from version");
}
}