项目作者: creazydev

项目描述 :
Microservice that is tracking schedule excel file updates and parsing it to PostgresDB.
高级语言: Java
项目地址: git://github.com/creazydev/schedule-updater.git
创建时间: 2020-10-04T13:15:12Z
项目社区:https://github.com/creazydev/schedule-updater

开源协议:

下载


Schedule Updater

About / Synopsis

  • Service application dealing with updating the plan. It does a simple sequence every specified time (30 minutes). It downloads the timetable in .xls format from the HTML document and uses the Apache POI library to parse the obtained data into PostgreSQL. It uses the DDD approach to define database objects.
  • Project status: working/prototype

Table of contents

Details

Libraries

LIBRARY USAGE
jsoup fetching HTML document
apache poi parsing stylesheet
postgresql database driver

Packages

service

To automate the update job used ScheduledExecutorService in combination with the observer design pattern:

  1. private final List<Observer> observers;
  2. private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
  3. ...
  4. @Override
  5. public void notifyObservers() {
  6. for (Observer observer: this.observers) {
  7. observer.update();
  8. }
  9. }
  10. ...
  11. public void enable() {
  12. scheduler.scheduleWithFixedDelay(track, 0, 15, TimeUnit.MINUTES);
  13. }

Defined contracts within service package:

  1. public interface ScheduleUpdateHandler {
  2. Optional<Schedule> handle();
  3. }
  4. public interface EntityFactory<T, S, V> {
  5. Optional<T> create(S selfReference, V argument);
  6. }
  7. public interface EntityCollectionFactory<T, S, V> {
  8. List<T> createCollection(S selfReference, List<V> collection);
  9. }

apachepoi

The package deals with parsing stylesheet file by mentioned contracts implementations:

  1. public class ApacheScheduleUpdateHandler implements ScheduleUpdateHandler {
  2. private final EntityFactory<Schedule, ScheduleVersion, URL> scheduleFactory;
  3. ...
  4. @Override
  5. public Optional<Schedule> handle() {
  6. ...
  7. ScheduleVersion scheduleVersion = new ScheduleVersion();
  8. Optional<Schedule> schedule = scheduleFactory.create(scheduleVersion, url.get());
  9. if (schedule.isPresent()) {
  10. ...
  11. return schedule;
  12. }
  13. }
  14. return Optional.empty();
  15. }
  16. public class ScheduleFactory implements EntityFactory<Schedule, ScheduleVersion, URL> {
  17. private final EntityCollectionFactory<GroupedDailySchedule, Schedule, List<String>> factory;
  18. @Override
  19. public Optional<Schedule> create(ScheduleVersion scheduleVersion, URL url) {
  20. Optional<List<List<String>>> preparedCollections = fetchAndPrepareData(url);
  21. if (preparedCollections.isPresent()) {
  22. ...
  23. schedule.setDailySchedule(factory.createCollection(schedule, preparedCollections.get()));
  24. return Optional.of(schedule);
  25. }
  26. return Optional.empty();
  27. }

utils

The class that represents the in-memory file is noteworthy in this package

  1. public final class TemporaryFile {
  2. private TemporaryFile() {
  3. throw new AssertionError();
  4. }
  5. public static Optional<File> writeInputStreamToFile(InputStream inputStream) {
  6. if (Objects.isNull(inputStream)) {
  7. throw new NullPointerException("InputStream cannot be null value.");
  8. }
  9. File file = newTemporaryFile()
  10. .orElseThrow(IllegalStateException::new);
  11. try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
  12. byte[] buffer = new byte[1024];
  13. int lenght = 0;
  14. while ((lenght = inputStream.read(buffer)) != -1) {
  15. fileOutputStream.write(buffer, 0, lenght);
  16. }
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. return Optional.empty();
  20. }
  21. return Optional.of(file);
  22. }
  23. private static Optional<File> newTemporaryFile() {
  24. try {
  25. File file = File.createTempFile("temp", null);
  26. file.deleteOnExit();
  27. return Optional.of(file);
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. return Optional.empty();
  31. }
  32. }
  33. }

As we can se above the only way to get TemporaryFile is to call method with InputStream as param.
TemporaryFile is destroyed after calling exit method on him.