From adf91f40a12733d6ea3275ab686ab3d9c79580b4 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sun, 6 Mar 2022 21:50:30 +0100 Subject: [PATCH] #663 - migrator: initial setup --- BudgetMasterDatabaseMigrator/pom.xml | 39 +++++++++ .../databasemigrator/BatchConfiguration.java | 60 +++++++++++++ .../DatabaseMigratorMain.java | 13 +++ .../databasemigrator/SchedulerConfig.java | 50 +++++++++++ .../DestinationDatabaseConfiguration.java | 50 +++++++++++ .../category/DestinationCategory.java | 85 +++++++++++++++++++ .../DestinationCategoryRepository.java | 7 ++ .../source/SourceDatabaseConfiguration.java | 53 ++++++++++++ .../source/category/CategoryType.java | 6 ++ .../source/category/SourceCategory.java | 82 ++++++++++++++++++ .../category/SourceCategoryRepository.java | 7 ++ .../steps/category/CategoryChunkListener.java | 36 ++++++++ .../steps/category/CategoryProcessor.java | 26 ++++++ .../steps/category/CategoryReader.java | 50 +++++++++++ .../steps/category/CategoryStepListener.java | 27 ++++++ .../steps/category/CategoryWriter.java | 35 ++++++++ .../src/main/resources/application.properties | 19 +++++ BudgetMasterServer/pom.xml | 7 -- pom.xml | 1 + 19 files changed, 646 insertions(+), 7 deletions(-) create mode 100644 BudgetMasterDatabaseMigrator/pom.xml create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/BatchConfiguration.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/DatabaseMigratorMain.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/SchedulerConfig.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/DestinationDatabaseConfiguration.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategory.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategoryRepository.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/SourceDatabaseConfiguration.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/CategoryType.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategory.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategoryRepository.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryChunkListener.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryProcessor.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryReader.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryStepListener.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryWriter.java create mode 100644 BudgetMasterDatabaseMigrator/src/main/resources/application.properties diff --git a/BudgetMasterDatabaseMigrator/pom.xml b/BudgetMasterDatabaseMigrator/pom.xml new file mode 100644 index 000000000..9e084b805 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/pom.xml @@ -0,0 +1,39 @@ +<?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"> + <parent> + <artifactId>BudgetMaster</artifactId> + <groupId>de.deadlocker8</groupId> + <version>2.10.0</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>BudgetMasterDatabaseMigrator</artifactId> + + <properties> + <h2database.version>1.4.199</h2database.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-batch</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>${h2database.version}</version> + </dependency> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/BatchConfiguration.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/BatchConfiguration.java new file mode 100644 index 000000000..81ec491cc --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/BatchConfiguration.java @@ -0,0 +1,60 @@ +package de.deadlocker8.budgetmaster.databasemigrator; + +import de.deadlocker8.budgetmaster.databasemigrator.destination.category.DestinationCategory; +import de.deadlocker8.budgetmaster.databasemigrator.source.category.SourceCategory; +import de.deadlocker8.budgetmaster.databasemigrator.steps.category.*; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableBatchProcessing +public class BatchConfiguration +{ + final JobBuilderFactory jobBuilderFactory; + final StepBuilderFactory stepBuilderFactory; + final JobExplorer jobExplorer; + + final CategoryReader categoryReader; + final CategoryWriter categoryWriter; + final CategoryProcessor categoryProcessor; + + public BatchConfiguration(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, JobExplorer jobExplorer, CategoryReader categoryReader, CategoryWriter categoryWriter, CategoryProcessor categoryProcessor) + { + this.jobBuilderFactory = jobBuilderFactory; + this.stepBuilderFactory = stepBuilderFactory; + this.jobExplorer = jobExplorer; + this.categoryReader = categoryReader; + this.categoryWriter = categoryWriter; + this.categoryProcessor = categoryProcessor; + } + + @Bean + public Job createJob() + { + return jobBuilderFactory.get("Migrate from h2 to postgresql") + .incrementer(new RunIdIncrementer()) + .flow(createStepForCategoryMigration()) + .end() + .build(); + } + + @Bean + public Step createStepForCategoryMigration() + { + return stepBuilderFactory.get("Migrate categories") + .<SourceCategory, DestinationCategory>chunk(1) + .reader(categoryReader) + .processor(categoryProcessor) + .writer(categoryWriter) + .listener(new CategoryChunkListener()) + .listener(new CategoryStepListener()) + .build(); + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/DatabaseMigratorMain.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/DatabaseMigratorMain.java new file mode 100644 index 000000000..f176618ca --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/DatabaseMigratorMain.java @@ -0,0 +1,13 @@ +package de.deadlocker8.budgetmaster.databasemigrator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DatabaseMigratorMain +{ + public static void main(String[] args) + { + SpringApplication.run(DatabaseMigratorMain.class, args); + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/SchedulerConfig.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/SchedulerConfig.java new file mode 100644 index 000000000..c40ba71b3 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/SchedulerConfig.java @@ -0,0 +1,50 @@ +package de.deadlocker8.budgetmaster.databasemigrator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.*; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.JobOperator; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRestartException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Configuration +@EnableScheduling +public class SchedulerConfig +{ + private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerConfig.class); + + final JobLauncher jobLauncher; + final JobOperator jobOperator; + final Job job; + + @Autowired + public SchedulerConfig(JobLauncher jobLauncher, JobOperator jobOperator, Job job) + { + this.jobLauncher = jobLauncher; + this.jobOperator = jobOperator; + this.job = job; + } + + @Scheduled(fixedDelay = Long.MAX_VALUE, initialDelay = 2000) + public void scheduleByFixedRate() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException + { + LOGGER.info("Starting migration..."); + final JobParameters jobParameters = new JobParametersBuilder() + .addString("time", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) + .toJobParameters(); + final JobExecution execution = jobLauncher.run(job, jobParameters); + + LOGGER.info("Migration DONE"); + + System.exit(0); + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/DestinationDatabaseConfiguration.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/DestinationDatabaseConfiguration.java new file mode 100644 index 000000000..877baddad --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/DestinationDatabaseConfiguration.java @@ -0,0 +1,50 @@ +package de.deadlocker8.budgetmaster.databasemigrator.destination; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "secondaryEntityManagerFactory", + transactionManagerRef = "secondaryTransactionManager", + basePackages = {"de.deadlocker8.budgetmaster.databasemigrator.destination"} +) +public class DestinationDatabaseConfiguration +{ + @Bean(name = "secondaryDataSource") + @ConfigurationProperties(prefix = "spring.seconddatasource") + public DataSource secondaryDataSource() + { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "secondaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder, + @Qualifier("secondaryDataSource") DataSource secondaryDataSource) + { + return builder + .dataSource(secondaryDataSource) + .packages("de.deadlocker8.budgetmaster.databasemigrator.destination") + .build(); + } + + @Bean(name = "secondaryTransactionManager") + public PlatformTransactionManager secondaryTransactionManager( + @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) + { + return new JpaTransactionManager(secondaryEntityManagerFactory); + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategory.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategory.java new file mode 100644 index 000000000..5fbe5932b --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategory.java @@ -0,0 +1,85 @@ +package de.deadlocker8.budgetmaster.databasemigrator.destination.category; + + + +import de.deadlocker8.budgetmaster.databasemigrator.source.category.CategoryType; + +import javax.persistence.*; + +@Entity +@Table(name = "category") +public class DestinationCategory +{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer ID; + + private String name; + + private String color; + + private CategoryType type; + + public DestinationCategory() + { + } + + public DestinationCategory(Integer ID, String name, String color, CategoryType type) + { + this.ID = ID; + this.name = name; + this.color = color; + this.type = type; + } + + public Integer getID() + { + return ID; + } + + public void setID(Integer ID) + { + this.ID = ID; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getColor() + { + return color; + } + + public void setColor(String color) + { + this.color = color; + } + + public CategoryType getType() + { + return type; + } + + public void setType(CategoryType type) + { + this.type = type; + } + + @Override + public String toString() + { + return "SourceCategory{" + + "ID=" + ID + + ", name='" + name + '\'' + + ", color='" + color + '\'' + + ", type=" + type + + '}'; + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategoryRepository.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategoryRepository.java new file mode 100644 index 000000000..378d2b28f --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/destination/category/DestinationCategoryRepository.java @@ -0,0 +1,7 @@ +package de.deadlocker8.budgetmaster.databasemigrator.destination.category; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DestinationCategoryRepository extends JpaRepository<DestinationCategory, Integer> +{ +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/SourceDatabaseConfiguration.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/SourceDatabaseConfiguration.java new file mode 100644 index 000000000..0e21a5a8d --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/SourceDatabaseConfiguration.java @@ -0,0 +1,53 @@ +package de.deadlocker8.budgetmaster.databasemigrator.source; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories( + entityManagerFactoryRef = "primaryEntityManagerFactory", + transactionManagerRef = "primaryTransactionManager", + basePackages = {"de.deadlocker8.budgetmaster.databasemigrator.source"} +) +public class SourceDatabaseConfiguration +{ + @Bean(name = "primaryDataSource") + @Primary + @ConfigurationProperties(prefix = "spring.datasource") + public DataSource primaryDataSource() + { + return DataSourceBuilder.create().build(); + } + + @Primary + @Bean(name = "primaryEntityManagerFactory") + public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder, + @Qualifier("primaryDataSource") DataSource primaryDataSource) + { + return builder + .dataSource(primaryDataSource) + .packages("de.deadlocker8.budgetmaster.databasemigrator.source") + .build(); + } + + @Bean(name = "primaryTransactionManager") + public PlatformTransactionManager primaryTransactionManager( + @Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) + { + return new JpaTransactionManager(primaryEntityManagerFactory); + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/CategoryType.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/CategoryType.java new file mode 100644 index 000000000..32072d0ca --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/CategoryType.java @@ -0,0 +1,6 @@ +package de.deadlocker8.budgetmaster.databasemigrator.source.category; + +public enum CategoryType +{ + NONE, REST, CUSTOM +} \ No newline at end of file diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategory.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategory.java new file mode 100644 index 000000000..d3d14ae35 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategory.java @@ -0,0 +1,82 @@ +package de.deadlocker8.budgetmaster.databasemigrator.source.category; + + +import javax.persistence.*; + +@Entity +@Table(name = "category") +public class SourceCategory +{ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer ID; + + private String name; + + private String color; + + private CategoryType type; + + public SourceCategory() + { + } + + public SourceCategory(Integer ID, String name, String color, CategoryType type) + { + this.ID = ID; + this.name = name; + this.color = color; + this.type = type; + } + + public Integer getID() + { + return ID; + } + + public void setID(Integer ID) + { + this.ID = ID; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getColor() + { + return color; + } + + public void setColor(String color) + { + this.color = color; + } + + public CategoryType getType() + { + return type; + } + + public void setType(CategoryType type) + { + this.type = type; + } + + @Override + public String toString() + { + return "SourceCategory{" + + "ID=" + ID + + ", name='" + name + '\'' + + ", color='" + color + '\'' + + ", type=" + type + + '}'; + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategoryRepository.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategoryRepository.java new file mode 100644 index 000000000..395092110 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/source/category/SourceCategoryRepository.java @@ -0,0 +1,7 @@ +package de.deadlocker8.budgetmaster.databasemigrator.source.category; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SourceCategoryRepository extends JpaRepository<SourceCategory, Integer> +{ +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryChunkListener.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryChunkListener.java new file mode 100644 index 000000000..af670c2fe --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryChunkListener.java @@ -0,0 +1,36 @@ +package de.deadlocker8.budgetmaster.databasemigrator.steps.category; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.ChunkListener; +import org.springframework.batch.core.scope.context.ChunkContext; + +public class CategoryChunkListener implements ChunkListener +{ + private static final Logger LOGGER = LoggerFactory.getLogger(CategoryChunkListener.class); + + private int numberOfProcessedItems = 0; + + @Override + public void beforeChunk(ChunkContext context) + { + // nothing to do + } + + @Override + public void afterChunk(ChunkContext context) + { + final int count = context.getStepContext().getStepExecution().getReadCount(); + if(count > numberOfProcessedItems) + { + numberOfProcessedItems++; + LOGGER.info("Migrating category {}", count); + } + } + + @Override + public void afterChunkError(ChunkContext context) + { + // nothing to do + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryProcessor.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryProcessor.java new file mode 100644 index 000000000..0ecc2fd5d --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryProcessor.java @@ -0,0 +1,26 @@ +package de.deadlocker8.budgetmaster.databasemigrator.steps.category; + +import de.deadlocker8.budgetmaster.databasemigrator.destination.category.DestinationCategory; +import de.deadlocker8.budgetmaster.databasemigrator.source.category.SourceCategory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.stereotype.Component; + +@Component +public class CategoryProcessor implements ItemProcessor<SourceCategory, DestinationCategory> +{ + private static final Logger LOGGER = LoggerFactory.getLogger(CategoryProcessor.class); + + @Override + public DestinationCategory process(SourceCategory category) + { + LOGGER.debug("CategoryProcessor: Processing category: {}", category); + + final DestinationCategory destinationCategory = new DestinationCategory(); + destinationCategory.setName(category.getName()); + destinationCategory.setColor(category.getColor()); + destinationCategory.setType(category.getType()); + return destinationCategory; + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryReader.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryReader.java new file mode 100644 index 000000000..d66fce1a6 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryReader.java @@ -0,0 +1,50 @@ +package de.deadlocker8.budgetmaster.databasemigrator.steps.category; + +import de.deadlocker8.budgetmaster.databasemigrator.source.category.CategoryType; +import de.deadlocker8.budgetmaster.databasemigrator.source.category.SourceCategory; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.database.JdbcCursorItemReader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.MessageFormat; + +@Component +public class CategoryReader extends JdbcCursorItemReader<SourceCategory> implements ItemReader<SourceCategory> +{ + private static final String TABLE_NAME = "category"; + + private static class DatabaseColumns + { + public static final String ID = "ID"; + public static final String NAME = "NAME"; + public static final String COLOR = "COLOR"; + public static final String TYPE = "TYPE"; + } + + public CategoryReader(@Autowired DataSource primaryDataSource) + { + setDataSource(primaryDataSource); + setSql(MessageFormat.format("SELECT * FROM {0}", TABLE_NAME)); + setFetchSize(100); + setRowMapper(new CategoryRowMapper()); + } + + public static class CategoryRowMapper implements RowMapper<SourceCategory> + { + @Override + public SourceCategory mapRow(ResultSet rs, int rowNum) throws SQLException + { + final SourceCategory category = new SourceCategory(); + category.setID(rs.getInt(DatabaseColumns.ID)); + category.setName(rs.getString(DatabaseColumns.NAME)); + category.setColor(rs.getString(DatabaseColumns.COLOR)); + category.setType(CategoryType.values()[rs.getInt(DatabaseColumns.TYPE)]); + return category; + } + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryStepListener.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryStepListener.java new file mode 100644 index 000000000..cbf684459 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryStepListener.java @@ -0,0 +1,27 @@ +package de.deadlocker8.budgetmaster.databasemigrator.steps.category; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.StepExecutionListener; + +public class CategoryStepListener implements StepExecutionListener +{ + private static final Logger LOGGER = LoggerFactory.getLogger(CategoryStepListener.class); + + @Override + public void beforeStep(StepExecution stepExecution) + { + LOGGER.info("\n"); + LOGGER.info(">>> Migrate categories..."); + } + + @Override + public ExitStatus afterStep(StepExecution stepExecution) + { + final int count = stepExecution.getReadCount(); + LOGGER.info(">>> Successfully migrated {} categories\n", count); + return null; + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryWriter.java b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryWriter.java new file mode 100644 index 000000000..2ac67a699 --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/java/de/deadlocker8/budgetmaster/databasemigrator/steps/category/CategoryWriter.java @@ -0,0 +1,35 @@ +package de.deadlocker8.budgetmaster.databasemigrator.steps.category; + +import de.deadlocker8.budgetmaster.databasemigrator.destination.category.DestinationCategory; +import de.deadlocker8.budgetmaster.databasemigrator.destination.category.DestinationCategoryRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.item.ItemWriter; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +@Component +public class CategoryWriter implements ItemWriter<DestinationCategory> +{ + private static final Logger LOGGER = LoggerFactory.getLogger(CategoryWriter.class); + + final DestinationCategoryRepository destinationCategoryRepository; + + public CategoryWriter(DestinationCategoryRepository destinationCategoryRepository) + { + this.destinationCategoryRepository = destinationCategoryRepository; + } + + @Override + public void write(List<? extends DestinationCategory> list) throws Exception + { + for(DestinationCategory data : list) + { + LOGGER.debug("CategoryWriter: Writing category: {}", data); + destinationCategoryRepository.save(data); + } + } +} diff --git a/BudgetMasterDatabaseMigrator/src/main/resources/application.properties b/BudgetMasterDatabaseMigrator/src/main/resources/application.properties new file mode 100644 index 000000000..eee50fdfc --- /dev/null +++ b/BudgetMasterDatabaseMigrator/src/main/resources/application.properties @@ -0,0 +1,19 @@ +spring.datasource.jdbc-url=jdbc:h2:/C:/Users/RobertG/AppData/Roaming/Deadlocker/BudgetMaster/debug/budgetmaster +spring.datasource.username=sa +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver + +spring.seconddatasource.jdbc-url=jdbc:postgresql://localhost:5432/budgetmaster +spring.seconddatasource.username=budgetmaster +spring.seconddatasource.password=BudgetMaster +spring.seconddatasource.driver-class-name=org.postgresql.Driver + +spring.jpa.database=default +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update + +spring.batch.jdbc.initialize-schema=always +spring.batch.job.enabled=false + +logging.level.root=INFO +logging.level.de.deadlocker8=DEBUG \ No newline at end of file diff --git a/BudgetMasterServer/pom.xml b/BudgetMasterServer/pom.xml index 0c6715f2f..42eb9c36d 100644 --- a/BudgetMasterServer/pom.xml +++ b/BudgetMasterServer/pom.xml @@ -37,7 +37,6 @@ <assertj-core.version>3.22.0</assertj-core.version> <jgit.version>6.0.0.202111291000-r</jgit.version> <natorder.version>1.1.2</natorder.version> - <h2database.version>1.4.199</h2database.version> <itextpdf.version>5.5.13.2</itextpdf.version> <vanilla-picker.version>2.12.1</vanilla-picker.version> <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version> @@ -112,12 +111,6 @@ </exclusions> </dependency> - <dependency> - <groupId>com.h2database</groupId> - <artifactId>h2</artifactId> - <version>${h2database.version}</version> - </dependency> - <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> diff --git a/pom.xml b/pom.xml index 3b2e278b3..109be0af2 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ <modules> <module>BudgetMasterServer</module> + <module>BudgetMasterDatabaseMigrator</module> </modules> <repositories> -- GitLab