/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.tools.pkam;
import static org.openbel.framework.common.BELUtilities.hasItems;
import static org.openbel.framework.common.BELUtilities.nulls;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openbel.framework.api.internal.KAMCatalogDao;
import org.openbel.framework.api.internal.KAMCatalogDao.KamInfo;
import org.openbel.framework.api.internal.KamDbObject;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.cfg.SystemConfiguration;
import org.openbel.framework.compiler.kam.KAMStoreSchemaService;
import org.openbel.framework.core.df.DBConnection;
import org.openbel.framework.core.df.DatabaseService;
import au.com.bytecode.opencsv.CSVParser;
import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
/**
* {@link DefaultPKAMSerializationService} implements service to serialize a
* KamStore KAM database into Portable KAM format.
*
* @author Anthony Bargnesi {@code <abargnesi@selventa.com>}
*/
public class DefaultPKAMSerializationService implements
PKAMSerializationService {
private final static char FIELD_SEPARATOR = '\t';
private final static Pattern TABLE_HEADER_PATTERN = Pattern
.compile("\\[(\\w+)\\]");
private final DatabaseService databaseService;
private final KAMStoreSchemaService schemaService;
/**
* Constructs the DefaultPKAMSerializationService with the
* {@link DatabaseService} dependency.
*
* @param databaseService {@link DatabaseService} dependency, which
* cannot be null
* @throws InvalidArgument Thrown if <tt>databaseService</tt> is null
*/
public DefaultPKAMSerializationService(
final DatabaseService databaseService,
final KAMStoreSchemaService schemaService) {
if (nulls(databaseService, schemaService)) {
throw new InvalidArgument("argument(s) are null");
}
this.databaseService = databaseService;
this.schemaService = schemaService;
}
/**
* {@inheritDoc}
*/
@Override
public void serializeKAM(final String kamName, String filePath)
throws PKAMSerializationFailure {
if (nulls(kamName, filePath)) {
throw new InvalidArgument("argument(s) were null");
}
final SystemConfiguration cfg =
SystemConfiguration.getSystemConfiguration();
KamInfo kamInfo = loadKAMInfo(kamName, filePath, cfg);
PKAMWriter pkw = null;
CSVWriter tabbedWriter = null;
KAMExportDAO kdao = null;
try {
pkw = new PKAMWriter(filePath);
tabbedWriter = new CSVWriter(pkw, FIELD_SEPARATOR,
CSVParser.DEFAULT_QUOTE_CHARACTER,
CSVParser.DEFAULT_ESCAPE_CHARACTER);
final DBConnection kcc = createKAMConnection(kamName, cfg);
kdao = new KAMExportDAO(kcc, kamInfo.getSchemaName());
for (KAMStoreTables1_0 kamTable : KAMStoreTables1_0.values()) {
tabbedWriter.writeNext(new String[] { "["
+ kamTable.getTableName() + "]" });
// write out column headers
// tabbedWriter.writeNext(kamTable.getOtherColumnNames());
// query all rows for the current kam table
List<String[]> allRows = kdao.getAllRowsForTable(kamTable);
// write data as tsv if there is any
if (hasItems(allRows)) {
for (String[] row : allRows) {
tabbedWriter.writeNext(row);
}
}
}
} catch (IOException e) {
throw new PKAMSerializationFailure(kamName, e.getMessage());
} catch (SQLException e) {
throw new PKAMSerializationFailure(kamName, e.getMessage());
} finally {
// close tabbed-data writer
if (tabbedWriter != null) {
try {
tabbedWriter.close();
} catch (IOException e1) {}
}
// close kam catalog connection
if (kdao != null) {
kdao.terminate();
}
}
}
private DBConnection createKAMConnection(final String kamName,
final SystemConfiguration cfg) throws PKAMSerializationFailure {
final DBConnection kcc;
try {
kcc = databaseService.dbConnection(
cfg.getKamURL(),
cfg.getKamUser(),
cfg.getKamPassword());
} catch (SQLException e) {
throw new PKAMSerializationFailure(kamName, e.getMessage());
}
return kcc;
}
/**
* {@inheritDoc}
*/
@Override
public void deserializeKAM(final String kamName, final String filePath,
final boolean noPreserve) throws PKAMSerializationFailure {
// load destination KAM
final SystemConfiguration cfg =
SystemConfiguration.getSystemConfiguration();
// parse and insert KAM data from portable KAM file
PKAMReader pkr = null;
CSVReader tabbedReader = null;
KAMImportDAO kamImportDAO = null;
try {
try {
pkr = new PKAMReader(filePath);
} catch (Exception e) {
throw new PKAMSerializationFailure(filePath,
"Unable to process KAM.");
}
tabbedReader = new CSVReader(pkr, FIELD_SEPARATOR,
CSVParser.DEFAULT_QUOTE_CHARACTER,
CSVParser.DEFAULT_ESCAPE_CHARACTER);
KAMStoreTables1_0 table;
String[] data;
while ((data = tabbedReader.readNext()) != null) {
Matcher matcher = TABLE_HEADER_PATTERN.matcher(data[0]);
if (data.length == 1 && matcher.matches()) {
table = KAMStoreTables1_0.getTableByName(matcher.group(1));
if (table == KAMStoreTables1_0.KAM_CATALOG_KAM) {
String[] kcRowData = tabbedReader.readNext();
final String newKAMSchema = createKAMSchema(cfg,
kamName, kcRowData, filePath, noPreserve);
final DBConnection kcc =
createKAMConnection(filePath, cfg);
kamImportDAO = new KAMImportDAO(kcc, newKAMSchema);
continue;
}
if (kamImportDAO == null) {
throw new IllegalStateException(
"KAMImportDAO has not been constructed");
}
// commit previous table batch, if any
kamImportDAO.commitTableBatch();
kamImportDAO.startTableBatch(table);
} else {
if (kamImportDAO == null) {
throw new IllegalStateException(
"KAMImportDAO has not been constructed");
}
kamImportDAO.importDataRow(data);
}
}
if (kamImportDAO == null) {
throw new IllegalStateException(
"KAMImportDAO has not been constructed");
}
// commit final table batch
kamImportDAO.commitTableBatch();
} catch (IOException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
} catch (SQLException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
} finally {
// close tabbed-data reader
if (tabbedReader != null) {
try {
tabbedReader.close();
} catch (IOException e) {}
}
if (kamImportDAO != null) {
kamImportDAO.terminate();
}
}
}
private String createKAMSchema(final SystemConfiguration cfg,
String kamName, final String[] rowData,
final String filePath, final boolean noPreserve)
throws PKAMSerializationFailure {
if (kamName == null) {
kamName = rowData[1];
}
final String kamDescription = rowData[2];
final long lastCompiled = Long.parseLong(rowData[3]);
// check to see if it exists
KamInfo kamInfo = loadKAMInfo(kamName, filePath, cfg);
// create a kam catalog entry if it does not exist
final KamDbObject kamDb;
if (kamInfo == null) {
kamDb = new KamDbObject(null, kamName, kamDescription,
new Date(lastCompiled), null);
} else {
if (!noPreserve) {
// FIXME Hack to throw noPreserve check error to be processed by the calling CLI
throw new IllegalStateException();
}
kamDb = new KamDbObject(kamInfo.getId(), kamName, kamDescription,
new Date(lastCompiled), kamInfo.getSchemaName());
}
final String kamSchema;
try {
// create new kam entry since it does not exist
kamSchema = schemaService.saveToKAMCatalog(kamDb);
} catch (SQLException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
}
// setup KamStore schema
DBConnection kcc = null;
try {
kcc = createKAMConnection(kamName, cfg);
schemaService.setupKAMStoreSchema(kcc, kamSchema);
} catch (SQLException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
} catch (IOException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
} finally {
if (kcc != null) {
kcc.close();
}
}
return kamSchema;
}
private KamInfo loadKAMInfo(final String kamName, final String filePath,
final SystemConfiguration cfg) throws PKAMSerializationFailure {
final DBConnection kcc = createKAMConnection(kamName, cfg);
KamInfo kamInfo;
KAMCatalogDao kcdao = null;
try {
kcdao = new KAMCatalogDao(kcc,
cfg.getKamCatalogSchema(), cfg.getKamSchemaPrefix());
kamInfo = kcdao.getKamInfoByName(kamName);
} catch (SQLException e) {
throw new PKAMSerializationFailure(filePath, e.getMessage());
} finally {
if (kcdao != null) {
kcdao.terminate();
}
}
return kamInfo;
}
}