/*
* Copyright 2007 - 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.jailer.api;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.SQLException;
import java.util.Map;
import javax.sql.DataSource;
import org.xml.sax.SAXException;
import net.sf.jailer.ExecutionContext;
import net.sf.jailer.configuration.DBMS;
import net.sf.jailer.database.BasicDataSource;
import net.sf.jailer.database.WorkingTableScope;
import net.sf.jailer.subsetting.ScriptFormat;
import net.sf.jailer.subsetting.SubsettingEngine;
/**
* Generates a subset of a relational database that respects foreign key constraints. <br>
*
* @author Ralf Wisser
*/
public class Subsetter {
/**
* Default constructor.
*/
public Subsetter() {
executionContext = new ExecutionContext();
}
/**
* Copy constructor.
*/
public Subsetter(Subsetter other) {
this.dataSource = other.dataSource;
this.modelPoolSize = other.modelPoolSize;
this.dbms = other.dbms;
this.executionContext = new ExecutionContext(other.executionContext);
this.extractionModelURL = other.extractionModelURL;
}
/**
* Creates a new Subsetter with all mandatory attributes.
*
* @param dataSource the data-source to connect with the source database
* @param dbms the DBMS of the source database
* @param dataModel URL of the current data model (the datamodel's base folder)
* @param extractionModel URL of the extraction model
* @param scriptFormat script format
*/
public Subsetter(
DataSource dataSource,
DBMS dbms,
URL dataModel,
URL extractionModel,
ScriptFormat scriptFormat) {
executionContext = new ExecutionContext();
setDataSource(dataSource);
setDbms(dbms);
setDataModelURL(dataModel);
setExtractionModelURL(extractionModel);
setScriptFormat(scriptFormat);
}
/**
* Creates a new Subsetter with all mandatory attributes.
*
* @param dataSource the data-source to connect with the source database
* @param dbms the DBMS of the source database
* @param dataModel the current data model (the datamodel's base folder)
* @param extractionModel the extraction model
* @param scriptFormat script format
*/
public Subsetter(
DataSource dataSource,
DBMS dbms,
File dataModel,
File extractionModel,
ScriptFormat scriptFormat) {
executionContext = new ExecutionContext();
setDataSource(dataSource);
setDbms(dbms);
try {
setDataModelURL(dataModel.toURI().toURL());
setExtractionModelURL(extractionModel.toURI().toURL());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
setScriptFormat(scriptFormat);
}
/**
* Generates the export-script.
* @param whereClause if not <code>null</code>, overrides the extraction model's subject condition
*
* @param exportScriptFile the export-script file (compressed if it ends with '.zip' or '.gz')
*/
public void execute(String whereClause, File exportScriptFile) throws SQLException, IOException {
execute(whereClause, exportScriptFile, null);
}
/**
* Generates the export- and/or delete-script.
*
* @param whereClause if not <code>null</code>, overrides the extraction model's subject condition
* @param exportScriptFile the export-script file (compressed if it ends with '.zip' or '.gz'), optional
* @param deleteScriptFile the delete-script file (compressed if it ends with '.zip' or '.gz'), optional
*/
public void execute(String whereClause, File exportScriptFile, File deleteScriptFile) throws SQLException, IOException {
try {
if (getDataModelURL() == null) {
throw new IllegalStateException("missing DataModelURL");
}
if (getExtractionModelURL() == null) {
throw new IllegalStateException("missing ExtractionModelURL");
}
if (getDataSource() == null) {
throw new IllegalStateException("missing DataSource");
}
if (getScriptFormat() == null) {
throw new IllegalStateException("missing ScriptFormat");
}
DBMS sourceDBMS = getDbms();
if (sourceDBMS == null) {
if (getDataSource() instanceof BasicDataSource) {
sourceDBMS = ((BasicDataSource) getDataSource()).dbms;
} else {
throw new IllegalStateException("no DBMS set but data-source is not net.sf.jailer.database.BasicDataSource");
}
}
new SubsettingEngine(executionContext).export(
whereClause,
getExtractionModelURL(),
exportScriptFile == null? null : exportScriptFile.getAbsolutePath(),
deleteScriptFile == null? null : deleteScriptFile.getAbsolutePath(),
getDataSource(), sourceDBMS, false, getScriptFormat(), getModelPoolSize());
} catch (SAXException e) {
throw new RuntimeException(e);
}
}
/**
* Gets the data-source to connect with the database.
*
* @return the data-source to connect with the database
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Sets the data-source to connect with the database.
*
* @param dataSource the data-source to connect with the database
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Gets the DBMS of the database.
*
* @return the DBMS
*/
public DBMS getDbms() {
return dbms;
}
/**
* Sets the DBMS of the database. <br>
* Note that it's not necessary to set the DBMS if {@link BasicDataSource} is used.
*
* @param dbms the DBMS
*/
public void setDbms(DBMS dbms) {
this.dbms = dbms;
}
/**
* Gets URL of the current data model (the datamodel's base folder)
*/
public URL getDataModelURL() {
return executionContext.getDataModelURL();
}
/**
* Sets URL of the current data model (the datamodel's base folder)
*/
public void setDataModelURL(URL datamodelURL) {
executionContext.setDataModelURL(datamodelURL);
}
/**
* Sets the current data model as {@link File}
*
* @param datamodelBaseFolder represents the folder. Will be converted to an URL an set as datamodel URL
*
* @see #setDataModelURL(URL)
*/
public void setDataModelBaseFolder(File datamodelBaseFolder) {
try {
setDataModelURL(datamodelBaseFolder.toURI().toURL());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
/**
* Gets the URL of the extraction model.
*
* @return the URL of the extraction model
*/
public URL getExtractionModelURL() {
return extractionModelURL;
}
/**
* Sets the URL of the extraction model.
*
* @param extractionModelURL the URL of the extraction model
*/
public void setExtractionModelURL(URL extractionModelURL) {
this.extractionModelURL = extractionModelURL;
}
/**
* Gets the script format.
*
* @return the script format
*/
public ScriptFormat getScriptFormat() {
return executionContext.getScriptFormat();
}
/**
* Sets the script format.
*
* @return the script format
*/
public void setScriptFormat(ScriptFormat scriptFormat) {
executionContext.setScriptFormat(scriptFormat);
}
/**
* If <code>true</code>, Use uTF-8 encoding
*
* @return <code>true</code> if use UTF-8 encoding
*/
public boolean getUTF8() {
return executionContext.getUTF8();
}
/**
* If <code>true</code>, use UTF-8 encoding
*
* @param uTF8
* <code>true</code> if use UTF-8 encoding
*/
public void setUTF8(boolean uTF8) {
executionContext.setUTF8(uTF8);
}
/**
* Gets target-DBMS.
*
* @return target-DBMS
*/
public DBMS getTargetDBMS() {
return executionContext.getTargetDBMS();
}
/**
* Sets target-DBMS.
*
* @param targetDBMS target-DBMS. If it's <code>null</code>, target DBMS is assumed to be the same as {@link #getDbms()}
*/
public void setTargetDBMS(DBMS targetDBMS) {
executionContext.setTargetDBMS(targetDBMS);
}
/**
* Gets root tag of XML export file
*
* @return root tag of XML export file
*/
public String getXmlRootTag() {
return executionContext.getXmlRootTag();
}
/**
* Sets root tag of XML export file
*
* @param xmlRootTag
* root tag of XML export file
*/
public void setXmlRootTag(String xmlRootTag) {
executionContext.setXmlRootTag(xmlRootTag);
}
/**
* Gets pattern for dates in XML and LIQUIBASE_XML export file
*
* @return pattern for dates in XML and LIQUIBASE_XML export file
*/
public String getXmlDatePattern() {
return executionContext.getXmlDatePattern();
}
/**
* Sets pattern for dates in XML and LIQUIBASE_XML export file
*
* @param xmlDatePattern
* pattern for dates in XML and LIQUIBASE_XML export file
*/
public void setXmlDatePattern(String xmlDatePattern) {
executionContext.setXmlDatePattern(xmlDatePattern);
}
/**
* Gets pattern for times in XML and LIQUIBASE_XML export file
*
* @return pattern for times in XML and LIQUIBASE_XML export file
*/
public String getXmlTimePattern() {
return executionContext.getXmlTimePattern();
}
/**
* Sets pattern for times in XML and LIQUIBASE_XML export file
*
* @param xmlTimePattern
* pattern for times in XML and LIQUIBASE_XML export file
*/
public void setXmlTimePattern(String xmlTimePattern) {
executionContext.setXmlTimePattern(xmlTimePattern);
}
/**
* Gets pattern for time-stamps in XML and LIQUIBASE_XML export file
*
* @return pattern for time-stamps in XML and LIQUIBASE_XML export file
*/
public String getXmlTimeStampPattern() {
return executionContext.getXmlTimeStampPattern();
}
/**
* Sets pattern for time-stamps in XML and LIQUIBASE_XML export file
*
* @param xmlTimeStampPattern
* pattern for time-stamps in XML and LIQUIBASE_XML export file
*/
public void setXmlTimeStampPattern(String xmlTimeStampPattern) {
executionContext.setXmlTimeStampPattern(xmlTimeStampPattern);
}
/**
* Gets number of parallel threads (default is 1) to be used.
*
* @return number of threads (default is 1)
*/
public int getNumberOfThreads() {
return executionContext.getNumberOfThreads();
}
/**
* Sets number of parallel threads (default is 1) to be used
*
* @param numberOfThreads
* number of threads
*/
public void setNumberOfThreads(int numberOfThreads) {
executionContext.setNumberOfThreads(numberOfThreads);
}
/**
* Gets maximum number of entities per insert-statement (in export-file,
* default is 10)
*
* @return maximum number of entities per insert-statement (in export-file,
* default is 10)
*/
public int getNumberOfEntities() {
return executionContext.getNumberOfEntities();
}
/**
* Sets maximum number of entities per insert-statement (in export-file,
* default is 10)
*
* @param numberOfEntities
* maximum number of entities per insert-statement (in
* export-file, default is 10)
*/
public void setNumberOfEntities(int numberOfEntities) {
executionContext.setNumberOfEntities(numberOfEntities);
}
/**
* If <code>true</code>, Generate 'upsert'-statements for all entities (in
* export-file)
*
* @return <code>true</code> if Generate 'upsert'-statements for all
* entities (in export-file)
*/
public boolean getUpsertOnly() {
return executionContext.getUpsertOnly();
}
/**
* If <code>true</code>, Generate 'upsert'-statements for all entities (in
* export-file)
*
* @param upsertOnly
* <code>true</code> if Generate 'upsert'-statements for all
* entities (in export-file)
*/
public void setUpsertOnly(boolean upsertOnly) {
executionContext.setUpsertOnly(upsertOnly);
}
/**
* Gets scope of working tables, GLOBAL, SESSION_LOCAL or LOCAL_DATABASE <br>
* Default is GLOBAL.
*
* @return scope of working tables, GLOBAL, SESSION_LOCAL or LOCAL_DATABASE
*/
public WorkingTableScope getScope() {
return executionContext.getScope();
}
/**
* Sets scope of working tables, GLOBAL, SESSION_LOCAL or LOCAL_DATABASE
*
* @param scope
* scope of working tables, GLOBAL, SESSION_LOCAL or
* LOCAL_DATABASE
*/
public void setScope(WorkingTableScope scope) {
executionContext.setScope(scope);
}
/**
* Gets schema in which the working tables will be created
*
* @return schema in which the working tables will be created
*/
public String getWorkingTableSchema() {
return executionContext.getWorkingTableSchema();
}
/**
* Sets schema in which the working tables will be created
*
* @param workingTableSchema
* schema in which the working tables will be created
*/
public void setWorkingTableSchema(String workingTableSchema) {
executionContext.setWorkingTableSchema(workingTableSchema);
}
/**
* If <code>true</code>, The exported rows will not be sorted according to
* foreign key constraints
*
* @return <code>true</code> if The exported rows will not be sorted
* according to foreign key constraints
*/
public boolean getNoSorting() {
return executionContext.getNoSorting();
}
/**
* If <code>true</code>, The exported rows will not be sorted according to
* foreign key constraints
*
* @param noSorting
* <code>true</code> if The exported rows will not be sorted
* according to foreign key constraints
*/
public void setNoSorting(boolean noSorting) {
executionContext.setNoSorting(noSorting);
}
/**
* If <code>true</code>, Use primary keys to determine row identity (instead
* of rowid-column)
*
* @return <code>true</code> if Use primary keys to determine row identity
* (instead of rowid-column)
*/
public boolean getNoRowid() {
return executionContext.getNoRowid();
}
/**
* If <code>true</code>, Use primary keys to determine row identity (instead
* of rowid-column)
*
* @param noRowid
* <code>true</code> if Use primary keys to determine row
* identity (instead of rowid-column)
*/
public void setNoRowid(boolean noRowid) {
executionContext.setNoRowid(noRowid);
}
/**
* Gets schema in which the import-filter mapping tables will be created
*
* @return schema in which the import-filter mapping tables will be created
*/
public String getImportFilterMappingTableSchema() {
return executionContext.getImportFilterMappingTableSchema();
}
/**
* Sets schema in which the import-filter mapping tables will be created
*
* @param importFilterMappingTableSchema
* schema in which the import-filter mapping tables will be
* created
*/
public void setImportFilterMappingTableSchema(String importFilterMappingTableSchema) {
executionContext.setImportFilterMappingTableSchema(importFilterMappingTableSchema);
}
/**
* Gets parameters
* TODO
* @return parameters
*/
public Map<String, String> getParameters() {
return executionContext.getParameters();
}
/**
* Sets a parameter.
*
* @param name parameter name
* @param value value
*/
public void setParameter(String name, String value) {
executionContext.setParameter(name, value);
}
public Map<String, String> getSchemaMapping() {
return executionContext.getSchemaMapping();
}
/**
* Sets source schema map
* TODO
* @param rawsourceschemamapping
* source schema map
*/
public void setSchemaMapping(Map<String, String> schemaMapping) {
executionContext.setSchemaMapping(schemaMapping);
}
/**
* TODO
*
* @param sourceSchemaMapping the sourceSchemaMapping to set
*/
public void setSourceSchemaMapping(Map<String, String> sourceSchemaMapping) {
executionContext.setSourceSchemaMapping(sourceSchemaMapping);
}
public Map<String, String> getSourceSchemaMapping() {
return executionContext.getSourceSchemaMapping();
}
/**
* @return the size of extraction-model pool (default is 10)
*/
public int getModelPoolSize() {
return modelPoolSize;
}
/**
* @param modelPoolSize size of extraction-model pool (default is 10)
*/
public void setModelPoolSize(int modelPoolSize) {
this.modelPoolSize = modelPoolSize;
}
private final ExecutionContext executionContext;
private int modelPoolSize = 10;
private URL extractionModelURL;
private DataSource dataSource;
private DBMS dbms;
}