blob: 1348cab7373b49f5f203277f9e370071b093167d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2007 Boeing.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Boeing - initial API and implementation
*******************************************************************************/
package org.eclipse.osee.framework.branch.management.exchange;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.osee.framework.branch.management.ImportOptions;
import org.eclipse.osee.framework.branch.management.exchange.handler.BaseDbSaxHandler;
import org.eclipse.osee.framework.branch.management.exchange.handler.BranchDataSaxHandler;
import org.eclipse.osee.framework.branch.management.exchange.handler.ExportItem;
import org.eclipse.osee.framework.branch.management.exchange.handler.IExportItem;
import org.eclipse.osee.framework.branch.management.exchange.handler.ManifestSaxHandler;
import org.eclipse.osee.framework.branch.management.exchange.handler.MetaData;
import org.eclipse.osee.framework.branch.management.exchange.handler.MetaDataSaxHandler;
import org.eclipse.osee.framework.branch.management.exchange.handler.RelationalSaxHandler;
import org.eclipse.osee.framework.branch.management.exchange.transform.ExchangeDataProcessor;
import org.eclipse.osee.framework.branch.management.exchange.transform.ExchangeTransformProvider;
import org.eclipse.osee.framework.branch.management.exchange.transform.ExchangeTransformer;
import org.eclipse.osee.framework.branch.management.exchange.transform.IExchangeTransformProvider;
import org.eclipse.osee.framework.branch.management.internal.Activator;
import org.eclipse.osee.framework.core.exception.OseeArgumentException;
import org.eclipse.osee.framework.core.exception.OseeCoreException;
import org.eclipse.osee.framework.core.exception.OseeDataStoreException;
import org.eclipse.osee.framework.core.exception.OseeExceptions;
import org.eclipse.osee.framework.core.exception.OseeStateException;
import org.eclipse.osee.framework.core.operation.OperationReporter;
import org.eclipse.osee.framework.database.core.DbTransaction;
import org.eclipse.osee.framework.database.core.IOseeStatement;
import org.eclipse.osee.framework.database.core.OseeConnection;
import org.eclipse.osee.framework.jdk.core.util.Lib;
import org.eclipse.osee.framework.logging.OseeLog;
import org.eclipse.osee.framework.resource.management.Options;
/**
* @author Roberto E. Escobar
*/
public final class ImportController {
private static final String SAVE_POINT_PREFIX = "save.point.";
private static final String INSERT_INTO_IMPORT_SOURCES =
"INSERT INTO osee_import_source (import_id, db_source_guid, source_export_date, date_imported) VALUES (?, ?, ?, ?)";
private static final String INSERT_INTO_IMPORT_SAVE_POINT =
"INSERT INTO osee_import_save_point (import_id, save_point_name, status, state_error) VALUES (?, ?, ?, ?)";
private static final String QUERY_SAVE_POINTS_FROM_IMPORT_MAP =
"SELECT save_point_name from osee_import_save_point oisp, osee_import_source ois WHERE ois.import_id = oisp.import_id AND oisp.status = 1 AND ois.db_source_guid = ? AND ois.source_export_date = ?";
private final OseeServices oseeServices;
private final IOseeExchangeDataProvider exportDataProvider;
private final Options options;
private final int[] branchesToImport = null;
private final Map<String, SavePoint> savePoints;
private final OperationReporter reporter;
private ExchangeTransformer exchangeTransformer;
private ExchangeDataProcessor exchangeDataProcessor;
private TranslationManager translator;
private ManifestSaxHandler manifestHandler;
private MetaDataSaxHandler metadataHandler;
private String currentSavePoint;
ImportController(OseeServices oseeServices, IOseeExchangeDataProvider exportDataProvider, Options options, OperationReporter reporter) {
this.oseeServices = oseeServices;
this.exportDataProvider = exportDataProvider;
this.options = options;
this.savePoints = new LinkedHashMap<String, SavePoint>();
this.reporter =reporter;
}
private void checkPreconditions() throws OseeCoreException {
if (oseeServices.getDatabaseService().isProduction()) {
throw new OseeStateException("DO NOT IMPORT ON PRODUCTION");
}
}
private void setup() throws Exception {
currentSavePoint = "sourceSetup";
exchangeDataProcessor = new ExchangeDataProcessor(exportDataProvider);
IExchangeTransformProvider transformProvider = new ExchangeTransformProvider(oseeServices.getCachingService());
exchangeTransformer = new ExchangeTransformer(transformProvider, exchangeDataProcessor);
exchangeTransformer.applyTransforms(reporter);
currentSavePoint = "manifest";
manifestHandler = new ManifestSaxHandler();
exchangeDataProcessor.parse(ExportItem.EXPORT_MANIFEST, manifestHandler);
currentSavePoint = "setup";
translator = new TranslationManager(oseeServices.getDatabaseService());
translator.configure(options);
// Process database meta data
currentSavePoint = manifestHandler.getMetadataFile();
metadataHandler = new MetaDataSaxHandler(oseeServices.getDatabaseService());
exchangeDataProcessor.parse(ExportItem.EXPORT_DB_SCHEMA, metadataHandler);
metadataHandler.checkAndLoadTargetDbMetadata();
// Load Import Indexes
currentSavePoint = "load.translator";
translator.loadTranslators(manifestHandler.getSourceDatabaseId());
loadImportTrace(manifestHandler.getSourceDatabaseId(), manifestHandler.getSourceExportDate());
}
private void cleanup() throws Exception {
try {
CommitImportSavePointsTx saveImportState = new CommitImportSavePointsTx();
saveImportState.execute();
} catch (Exception ex) {
OseeLog.log(this.getClass(), Level.WARNING,
"Error during save point save - you will not be able to reimport from last source again.");
throw ex;
} finally {
exchangeDataProcessor.cleanUp();
translator = null;
manifestHandler = null;
metadataHandler = null;
exchangeTransformer = null;
savePoints.clear();
}
}
public void execute() throws Exception {
checkPreconditions();
savePoints.clear();
try {
currentSavePoint = "start";
addSavePoint(currentSavePoint);
setup();
ImportBranchesTx importBranchesTx = new ImportBranchesTx();
importBranchesTx.execute();
currentSavePoint = "init.relational.objects";
processImportFiles(manifestHandler.getImportFiles());
importBranchesTx.updateBranchParentTransactionId();
exchangeTransformer.applyFinalTransforms(reporter);
currentSavePoint = "stop";
addSavePoint(currentSavePoint);
} catch (Throwable ex) {
reportError(currentSavePoint, ex);
OseeLog.log(Activator.class, Level.SEVERE, ex);
} finally {
cleanup();
}
}
private void initializeHandler(OseeConnection connection, BaseDbSaxHandler handler, MetaData metadata) {
handler.setConnection(connection);
handler.setMetaData(metadata);
handler.setOptions(options);
handler.setTranslator(translator);
}
private void process(BaseDbSaxHandler handler, OseeConnection connection, IExportItem exportItem) throws OseeCoreException {
MetaData metadata = checkMetadata(exportItem);
initializeHandler(connection, handler, metadata);
boolean cleanDataTable = options.getBoolean(ImportOptions.CLEAN_BEFORE_IMPORT.name());
cleanDataTable &= !doesSavePointExist(currentSavePoint);
OseeLog.log(this.getClass(), Level.INFO, String.format("Importing: [%s] %s Meta: %s", exportItem.getSource(),
cleanDataTable ? "clean before import" : "", metadata.getColumnNames()));
if (cleanDataTable) {
handler.clearDataTable();
}
try {
exchangeDataProcessor.parse(exportItem, handler);
} catch (Exception ex) {
if (ex instanceof OseeCoreException) {
throw (OseeCoreException) ex;
}
OseeExceptions.wrapAndThrow(ex);
}
}
private MetaData checkMetadata(IExportItem importFile) throws OseeArgumentException {
MetaData metadata = metadataHandler.getMetadata(importFile.getSource());
if (metadata == null) {
throw new OseeArgumentException(String.format("Invalid metadata for [%s]", importFile.getSource()));
}
return metadata;
}
private void processImportFiles(Collection<IExportItem> importItems) throws Exception {
final RelationalSaxHandler handler =
RelationalSaxHandler.createWithLimitedCache(oseeServices, exportDataProvider, 50000);
handler.setSelectedBranchIds(branchesToImport);
for (final IExportItem item : importItems) {
OseeLog.log(Activator.class, Level.INFO, String.format("starting import for [%s]", item));
currentSavePoint = item.getSource();
handler.setExportItem(item);
if (!doesSavePointExist(currentSavePoint)) {
DbTransaction importTx = new DbTransaction() {
@Override
protected void handleTxWork(OseeConnection connection) throws OseeCoreException {
process(handler, connection, item);
handler.store();
handler.reset();
addSavePoint(currentSavePoint);
}
};
importTx.execute();
} else {
OseeLog.log(Activator.class, Level.INFO, String.format("Save point found for: [%s] - skipping",
item.getSource()));
}
}
}
private void loadImportTrace(String sourceDatabaseId, Date sourceExportDate) throws OseeDataStoreException {
IOseeStatement chStmt = oseeServices.getDatabaseService().getStatement();
try {
currentSavePoint = "load.save.points";
chStmt.runPreparedQuery(QUERY_SAVE_POINTS_FROM_IMPORT_MAP, sourceDatabaseId, new Timestamp(
sourceExportDate.getTime()));
while (chStmt.next()) {
String key = chStmt.getString("save_point_name");
savePoints.put(key, new SavePoint(key));
}
addSavePoint(currentSavePoint);
} finally {
chStmt.close();
}
}
private String asSavePointName(String sourceName) {
return SAVE_POINT_PREFIX + sourceName;
}
private boolean doesSavePointExist(String sourceName) {
return savePoints.containsKey(asSavePointName(sourceName));
}
private void addSavePoint(String sourceName) {
String key = asSavePointName(sourceName);
SavePoint point = savePoints.get(key);
if (point == null) {
point = new SavePoint(key);
savePoints.put(key, point);
}
}
private void reportError(String sourceName, Throwable ex) {
String key = asSavePointName(sourceName);
SavePoint point = savePoints.get(key);
if (point == null) {
point = new SavePoint(key);
savePoints.put(key, point);
}
point.addError(ex);
}
private final class ImportBranchesTx extends DbTransaction {
private final BranchDataSaxHandler branchHandler;
private int[] branchesStored;
public ImportBranchesTx() {
super();
branchHandler = BranchDataSaxHandler.createWithCacheAll(oseeServices.getDatabaseService());
branchesStored = new int[0];
}
public void updateBranchParentTransactionId() throws OseeDataStoreException {
currentSavePoint = "update branch parent transaction id";
if (!doesSavePointExist(currentSavePoint)) {
if (branchesStored.length > 0) {
branchHandler.updateParentTransactionId(branchesStored);
}
} else {
OseeLog.log(this.getClass(), Level.INFO, String.format("Save point found for: [%s] - skipping",
currentSavePoint));
}
}
@Override
protected void handleTxWork(OseeConnection connection) throws OseeCoreException {
// Import Branches
currentSavePoint = manifestHandler.getBranchFile().getSource();
process(branchHandler, connection, manifestHandler.getBranchFile());
if (!doesSavePointExist(currentSavePoint)) {
branchesStored = branchHandler.store(true, branchesToImport);
addSavePoint(currentSavePoint);
} else {
// This step has already been performed - only get branches needed for remaining operations
OseeLog.log(this.getClass(), Level.INFO, String.format("Save point found for: [%s] - skipping",
currentSavePoint));
branchesStored = branchHandler.store(false, branchesToImport);
}
}
}
private final class CommitImportSavePointsTx extends DbTransaction {
public CommitImportSavePointsTx() {
super();
}
@SuppressWarnings("unchecked")
@Override
protected void handleTxWork(OseeConnection connection) throws OseeCoreException {
if (manifestHandler != null && translator != null) {
int importIdIndex = oseeServices.getDatabaseService().getSequence().getNextImportId();
String sourceDatabaseId = manifestHandler.getSourceDatabaseId();
Timestamp importDate = new Timestamp(new Date().getTime());
Timestamp exportDate = new Timestamp(manifestHandler.getSourceExportDate().getTime());
oseeServices.getDatabaseService().runPreparedUpdate(connection, INSERT_INTO_IMPORT_SOURCES, importIdIndex,
sourceDatabaseId, exportDate, importDate);
translator.store(connection, importIdIndex);
List<Object[]> data = new ArrayList<Object[]>();
for (SavePoint savePoint : savePoints.values()) {
int status = 1;
String comment = "";
if (savePoint.hasErrors()) {
status = -1;
StringBuilder builder = new StringBuilder();
for (Throwable ex : savePoint.getErrors()) {
builder.append(Lib.exceptionToString(ex).replaceAll("\n", " "));
}
if (builder.length() < 4000) {
comment = builder.toString();
} else {
comment = builder.substring(0, 3999);
}
}
data.add(new Object[] {importIdIndex, savePoint.getName(), status, comment});
}
oseeServices.getDatabaseService().runBatchUpdate(connection, INSERT_INTO_IMPORT_SAVE_POINT, data);
} else {
throw new OseeStateException("Import didn't make it past initialization");
}
}
}
private final class SavePoint {
private final String savePointName;
private List<Throwable> errors;
public SavePoint(String name) {
this.savePointName = name;
this.errors = null;
}
public String getName() {
return savePointName;
}
public void addError(Throwable ex) {
if (errors == null) {
errors = new ArrayList<Throwable>();
}
if (!errors.contains(ex)) {
errors.add(ex);
}
}
public List<Throwable> getErrors() {
if (errors == null) {
return Collections.emptyList();
} else {
return this.errors;
}
}
public boolean hasErrors() {
return errors != null;
}
}
}