/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.tools.sample.sql.builder;
import com.liferay.portal.freemarker.FreeMarkerUtil;
import com.liferay.portal.kernel.dao.db.DB;
import com.liferay.portal.kernel.dao.db.DBManagerUtil;
import com.liferay.portal.kernel.dao.db.DBType;
import com.liferay.portal.kernel.io.CharPipe;
import com.liferay.portal.kernel.io.OutputStreamWriter;
import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
import com.liferay.portal.kernel.io.unsync.UnsyncBufferedWriter;
import com.liferay.portal.kernel.io.unsync.UnsyncTeeWriter;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.SortedProperties;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.tools.ToolDependencies;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* @author Brian Wing Shun Chan
* @author Shuyang Zhou
*/
public class SampleSQLBuilder {
public static void main(String[] args) {
ToolDependencies.wireBasic();
Reader reader = null;
try {
Properties properties = new SortedProperties();
reader = new FileReader(args[0]);
properties.load(reader);
DataFactory dataFactory = new DataFactory(properties);
new SampleSQLBuilder(properties, dataFactory);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
public SampleSQLBuilder(Properties properties, DataFactory dataFactory)
throws Exception {
_dbType = DBType.valueOf(
StringUtil.toUpperCase(
properties.getProperty("sample.sql.db.type")));
_optimizeBufferSize = GetterUtil.getInteger(
properties.getProperty("sample.sql.optimize.buffer.size"));
_outputDir = properties.getProperty("sample.sql.output.dir");
_script = properties.getProperty("sample.sql.script");
_dataFactory = dataFactory;
// Generic
File tempDir = new File(_outputDir, "temp");
tempDir.mkdirs();
Reader reader = generateSQL();
try {
// Specific
compressSQL(reader, tempDir);
// Merge
boolean outputMerge = GetterUtil.getBoolean(
properties.getProperty("sample.sql.output.merge"));
if (outputMerge) {
File sqlFile = new File(
_outputDir, "sample-" + _dbType + ".sql");
FileUtil.delete(sqlFile);
mergeSQL(tempDir, sqlFile);
}
else {
File outputDir = new File(_outputDir, "output");
FileUtil.deltree(outputDir);
if (!tempDir.renameTo(outputDir)) {
// This will only happen when temp and output directories
// are on different file systems
FileUtil.copyDirectory(tempDir, outputDir);
}
}
}
finally {
FileUtil.deltree(tempDir);
}
StringBundler sb = new StringBundler();
for (String key : properties.stringPropertyNames()) {
if (!key.startsWith("sample.sql")) {
continue;
}
String value = properties.getProperty(key);
sb.append(key);
sb.append(StringPool.EQUAL);
sb.append(value);
sb.append(StringPool.NEW_LINE);
}
FileUtil.write(
new File(_outputDir, "benchmarks-actual.properties"),
sb.toString());
}
protected void compressSQL(
DB db, File directory, Map<String, Writer> insertSQLWriters,
Map<String, StringBundler> sqls, String insertSQL)
throws IOException {
String tableName = insertSQL.substring(0, insertSQL.indexOf(' '));
int index = insertSQL.indexOf(" values ") + 8;
StringBundler sb = sqls.get(tableName);
if ((sb == null) || (sb.index() == 0)) {
sb = new StringBundler();
sqls.put(tableName, sb);
sb.append("insert into ");
sb.append(insertSQL.substring(0, index));
sb.append("\n");
}
else {
sb.append(",\n");
}
String values = insertSQL.substring(index, insertSQL.length() - 1);
sb.append(values);
if (sb.index() >= _optimizeBufferSize) {
sb.append(";\n");
insertSQL = db.buildSQL(sb.toString());
sb.setIndex(0);
writeToInsertSQLFile(
directory, tableName, insertSQLWriters, insertSQL);
}
}
protected void compressSQL(Reader reader, File dir) throws Exception {
DB db = DBManagerUtil.getDB(_dbType, null);
if (_dbType == DBType.MYSQL) {
db = new SampleMySQLDB(db.getMajorVersion(), db.getMinorVersion());
}
Map<String, Writer> insertSQLWriters = new HashMap<>();
Map<String, StringBundler> insertSQLs = new HashMap<>();
List<String> miscSQLs = new ArrayList<>();
try (UnsyncBufferedReader unsyncBufferedReader =
new UnsyncBufferedReader(reader)) {
String s = null;
while ((_freeMarkerThrowable == null) &&
((s = unsyncBufferedReader.readLine()) != null)) {
s = s.trim();
if (s.length() > 0) {
if (s.startsWith("insert into ")) {
compressSQL(
db, dir, insertSQLWriters, insertSQLs,
s.substring(12));
}
else {
miscSQLs.add(s);
}
}
}
}
if (_freeMarkerThrowable != null) {
throw new Exception(
"Unable to process FreeMarker template ", _freeMarkerThrowable);
}
for (Map.Entry<String, StringBundler> entry : insertSQLs.entrySet()) {
String tableName = entry.getKey();
StringBundler sb = entry.getValue();
if (sb.index() > 0) {
String insertSQL = db.buildSQL(sb.toString());
writeToInsertSQLFile(
dir, tableName, insertSQLWriters, insertSQL);
}
try (Writer insertSQLWriter = insertSQLWriters.remove(tableName)) {
insertSQLWriter.write(";\n");
}
}
try (Writer miscSQLWriter = new FileWriter(new File(dir, "misc.sql"))) {
for (String miscSQL : miscSQLs) {
miscSQL = db.buildSQL(miscSQL);
miscSQLWriter.write(miscSQL);
miscSQLWriter.write(StringPool.NEW_LINE);
}
}
}
protected Writer createFileWriter(File file) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(file);
Writer writer = new OutputStreamWriter(fileOutputStream);
return createUnsyncBufferedWriter(writer);
}
protected Writer createUnsyncBufferedWriter(Writer writer) {
return new UnsyncBufferedWriter(writer, _WRITER_BUFFER_SIZE) {
@Override
public void flush() {
// Disable FreeMarker from flushing
}
};
}
protected Reader generateSQL() {
final CharPipe charPipe = new CharPipe(_PIPE_BUFFER_SIZE);
Thread thread = new Thread() {
@Override
public void run() {
Writer sampleSQLWriter = null;
try {
sampleSQLWriter = new UnsyncTeeWriter(
createUnsyncBufferedWriter(charPipe.getWriter()),
createFileWriter(new File(_outputDir, "sample.sql")));
FreeMarkerUtil.process(
_script,
Collections.singletonMap("dataFactory", _dataFactory),
sampleSQLWriter);
}
catch (Throwable t) {
_freeMarkerThrowable = t;
}
finally {
try {
_dataFactory.closeCSVWriters();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
if (sampleSQLWriter != null) {
try {
sampleSQLWriter.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
charPipe.close();
}
}
};
thread.start();
return charPipe.getReader();
}
protected Properties getProperties(String[] args) throws Exception {
Reader reader = null;
try {
Properties properties = new SortedProperties();
reader = new FileReader(args[0]);
properties.load(reader);
return properties;
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
protected void mergeSQL(File inputDir, File outputSQLFile)
throws IOException {
FileOutputStream outputSQLFileOutputStream = new FileOutputStream(
outputSQLFile);
try (FileChannel outputFileChannel =
outputSQLFileOutputStream.getChannel()) {
File miscSQLFile = null;
for (File inputFile : inputDir.listFiles()) {
String inputFileName = inputFile.getName();
if (inputFileName.equals("misc.sql")) {
miscSQLFile = inputFile;
continue;
}
mergeSQL(inputFile, outputFileChannel);
}
if (miscSQLFile != null) {
mergeSQL(miscSQLFile, outputFileChannel);
}
}
}
protected void mergeSQL(File inputFile, FileChannel outputFileChannel)
throws IOException {
FileInputStream inputFileInputStream = new FileInputStream(inputFile);
try (FileChannel inputFileChannel = inputFileInputStream.getChannel()) {
inputFileChannel.transferTo(
0, inputFileChannel.size(), outputFileChannel);
}
inputFile.delete();
}
protected void writeToInsertSQLFile(
File dir, String tableName, Map<String, Writer> insertSQLWriters,
String insertSQL)
throws IOException {
Writer insertSQLWriter = insertSQLWriters.get(tableName);
if (insertSQLWriter == null) {
File file = new File(dir, tableName + ".sql");
insertSQLWriter = createFileWriter(file);
insertSQLWriters.put(tableName, insertSQLWriter);
}
insertSQLWriter.write(insertSQL);
}
private static final int _PIPE_BUFFER_SIZE = 16 * 1024 * 1024;
private static final int _WRITER_BUFFER_SIZE = 16 * 1024;
private final DataFactory _dataFactory;
private final DBType _dbType;
private volatile Throwable _freeMarkerThrowable;
private final int _optimizeBufferSize;
private final String _outputDir;
private final String _script;
}