This commit is contained in:
Niklas Birk 2020-02-05 18:41:37 +01:00
commit 6b23c32c6d
15 changed files with 483 additions and 0 deletions

29
pom.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>DataMigration_Selfmade</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.9</version>
</dependency>
</dependencies>
</project>

75
src/main/java/Main.java Normal file
View File

@ -0,0 +1,75 @@
import data.source.PersonSource;
import data.target.PersonTarget;
import etl.Extractor;
import etl.Loader;
import etl.Transformer;
import utils.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
public class Main
{
public static void main(final String[] args) throws SQLException
{
// mysqlDb();
// postgresqlDb();
// mariaDb();
var p = testExtract();
var pt = testTransform(p);
testLoad(pt);
}
private static List<PersonSource> testExtract() throws SQLException
{
final var dbInfo = new DatabaseInformation("localhost", "sourcedb1", "test", "test", 5435);
final var connection = new ConnectionHelper(DatabaseType.MARIADB, dbInfo).createConnection();
DataStorer<PersonSource> personSourceDataStorer = (rs) -> {
var persons = new ArrayList<PersonSource>();
while (rs.next())
{
persons.add(new PersonSource(rs.getInt("personId"),
rs.getString("name"),
rs.getBoolean("mortal")));
}
return persons;
};
var sql = "select * from person;";
return new Extractor<>(connection, personSourceDataStorer, sql).doExtract();
}
private static List<PersonTarget> testTransform(List<PersonSource> persons)
{
DataTransformer<PersonSource, PersonTarget> personTransformer = (personSource) -> {
return new PersonTarget(personSource.getPersonId(),
personSource.getName(),
personSource.isMortal());
};
return new Transformer<>(personTransformer, persons).doTransform();
}
private static void testLoad(List<PersonTarget> transformedData)
{
final var dbInfo = new DatabaseInformation("localhost", "targetdb", "test", "test", 5432);
final var connection = new ConnectionHelper(DatabaseType.POSTGRESQL, dbInfo).createConnection();
StatementPreparer<PersonTarget> statementPreparer = (preparedStatement, data) -> {
preparedStatement.setInt(1, data.getPersonId());
preparedStatement.setString(2, data.getName());
preparedStatement.setBoolean(3, data.isMortal());
};
var sql = "insert into person values (?, ?, ?)";
new Loader<>(connection, statementPreparer, transformedData, sql).doLoad();
}
}

View File

@ -0,0 +1,5 @@
package data;
public interface Dataset
{
}

View File

@ -0,0 +1,38 @@
package data.source;
import data.Dataset;
public class PersonSource implements Dataset
{
private int personId;
private String name;
private boolean mortal;
public PersonSource(int personId, String name, boolean mortal)
{
this.personId = personId;
this.name = name;
this.mortal = mortal;
}
public int getPersonId()
{
return personId;
}
public String getName()
{
return name;
}
public boolean isMortal()
{
return mortal;
}
@Override
public String toString()
{
return String.format("Person { %d, %s, %s }", this.personId, this.name, this.mortal);
}
}

View File

@ -0,0 +1,38 @@
package data.target;
import data.Dataset;
public class PersonTarget implements Dataset
{
private int personId;
private String name;
private boolean mortal;
public PersonTarget(int personId, String name, boolean mortal)
{
this.personId = personId;
this.name = name;
this.mortal = mortal;
}
public int getPersonId()
{
return personId;
}
public String getName()
{
return name;
}
public boolean isMortal()
{
return mortal;
}
@Override
public String toString()
{
return String.format("Person [ %d, %s, %s ]", this.personId, this.name, this.mortal);
}
}

View File

@ -0,0 +1,43 @@
package etl;
import data.Dataset;
import utils.DataStorer;
import utils.StatementPreparer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public class Extractor<T extends Dataset>
{
private Connection sourceDatabase;
private DataStorer<T> dataStorer;
private ResultSet resultSet;
private String sql;
public Extractor(Connection sourceDatabase, DataStorer<T> dataStorer,
String sql)
{
this.sourceDatabase = sourceDatabase;
this.dataStorer = dataStorer;
this.sql = sql;
}
public List<T> doExtract()
{
try
{
var preparedStatement = this.sourceDatabase.prepareStatement(sql);
this.resultSet = preparedStatement.executeQuery();
this.sourceDatabase.close();
return this.dataStorer.doStore(this.resultSet);
}
catch (SQLException e)
{
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,44 @@
package etl;
import data.Dataset;
import utils.StatementPreparer;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class Loader<T extends Dataset>
{
private Connection targetDatabase;
private StatementPreparer<T> statementPreparer;
private List<T> transformedData;
private String sql;
public Loader(Connection targetDatabase, StatementPreparer<T> statementPreparer, List<T> transformedData,
String sql)
{
this.targetDatabase = targetDatabase;
this.statementPreparer = statementPreparer;
this.transformedData = transformedData;
this.sql = sql;
}
public void doLoad()
{
try
{
for (T transformedDatum : this.transformedData)
{
var preparedStatement = this.targetDatabase.prepareStatement(this.sql);
this.statementPreparer.doPrepare(preparedStatement, transformedDatum);
preparedStatement.executeUpdate();
}
this.targetDatabase.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,30 @@
package etl;
import data.Dataset;
import utils.DataTransformer;
import java.util.ArrayList;
import java.util.List;
public class Transformer<T extends Dataset, E extends Dataset>
{
private DataTransformer<T, E> transformer;
private List<T> datasets;
public Transformer(DataTransformer<T, E> transformer, List<T> datasets)
{
this.transformer = transformer;
this.datasets = datasets;
}
public List<E> doTransform()
{
var transformed = new ArrayList<E>();
for (T dataset : this.datasets)
{
transformed.add(this.transformer.transform(dataset));
}
return transformed;
}
}

View File

@ -0,0 +1,65 @@
package utils;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.*;
import java.util.Properties;
public class ConnectionHelper
{
private final DatabaseType databaseType;
private final String user;
private final String password;
private URI uri;
public ConnectionHelper(final DatabaseType databaseType, final DatabaseInformation databaseInformation)
{
this.databaseType = databaseType;
try
{
this.uri = new URI(this.databaseType.getScheme(),
null,
databaseInformation.getHost(),
databaseInformation.getPort(),
String.format("/%s", databaseInformation.getDatabaseName()),
null,
null);
}
catch (final URISyntaxException e)
{
e.printStackTrace();
}
this.user = databaseInformation.getUser();
this.password = databaseInformation.getPassword();
}
public Connection createConnection()
{
try
{
Class.forName(this.databaseType.getDriver());
}
catch (final ClassNotFoundException e)
{
e.printStackTrace();
}
Connection c = null;
try
{
c = DriverManager.getConnection(this.uri.toString(), this.user, this.password);
}
catch (final SQLException e)
{
System.out.println("SQLException: " + e.getMessage());
System.out.println("SQLState: " + e.getSQLState());
System.out.println("VendorError: " + e.getErrorCode());
e.printStackTrace();
}
return c;
}
}

View File

@ -0,0 +1,12 @@
package utils;
import data.Dataset;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public interface DataStorer<T extends Dataset>
{
List<T> doStore(ResultSet resultSet) throws SQLException;
}

View File

@ -0,0 +1,10 @@
package utils;
import data.Dataset;
import java.util.List;
public interface DataTransformer<T extends Dataset, E extends Dataset>
{
E transform(T dataset);
}

View File

@ -0,0 +1,5 @@
package utils;
public class DatabaseHelper
{
}

View File

@ -0,0 +1,51 @@
package utils;
import com.mysql.cj.exceptions.NumberOutOfRange;
public class DatabaseInformation
{
private final String host;
private final String databaseName;
private final String user;
private final String password;
private int port;
public DatabaseInformation(final String host, final String databaseName, final String user, final String password, final int port)
{
this.host = host;
this.databaseName = databaseName;
this.user = user;
this.password = password;
if (port < 0 || port > 65535)
throw new NumberOutOfRange("A port must be between 0 and 65535");
else
this.port = port;
}
public String getHost()
{
return host;
}
public String getDatabaseName()
{
return databaseName;
}
public String getUser()
{
return user;
}
public String getPassword()
{
return password;
}
public int getPort()
{
return port;
}
}

View File

@ -0,0 +1,27 @@
package utils;
public enum DatabaseType
{
MARIADB("org.mariadb.jdbc.Driver", "jdbc:mariadb"),
MYSQL("com.mysql.cj.jdbc.Driver", "jdbc:mysql"),
POSTGRESQL("org.postgresql.Driver", "jdbc:postgresql");
private final String driver;
private final String scheme;
DatabaseType(final String driver, final String scheme)
{
this.driver = driver;
this.scheme = scheme;
}
public String getDriver()
{
return driver;
}
public String getScheme()
{
return scheme;
}
}

View File

@ -0,0 +1,11 @@
package utils;
import data.Dataset;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public interface StatementPreparer<T extends Dataset>
{
void doPrepare(PreparedStatement preparedStatement, T data) throws SQLException;
}