diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ad02a2599 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +out +target +*.iml +log \ No newline at end of file diff --git a/README.md b/README.md index ed139bed8..de162e88f 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,172 @@ -#### Написание с нуля полнофункционального многомодульного Maven проекта: -веб приложения (Tomcat, JSP, jQuery), -многопоточного почтового сервиса (JavaMail, java.util.concurrent.*) и вспомогательных модулей связанных по Веб и REST сервисам (SOAP, JAX-WS, Axis, JAX-RS) -c сохранением данных в RMDBS и динамическим конфигурирование модулей по JMX. - -## Сервис-ориентированная архитектура, Микросервисы -- JMS, альтернативы -- Варианты разворачивания сервисов. Работа с базой. Связывание сервисов. - -## Maven. Многомодульный Maven проект -- Build Lifecycle -- Dependency Mechanism -- Зависимости, профили, написание плагина -- The Reactor. Snapshots - -## Создание/тестирование веб-приложения. -- Сборка, запуск, локальный и удаленный debug проекта, способы деплоя в Tomcat -- tomcat7-maven-plugin - -### Веб-сервисы -- Веб-сервисы. SOAP. Преимущества/недостатки веб-сервисов. Расширения. -- Реализация веб-сервисов в Java. JAX-RPC, JAX-WS, CFX, Axis. Стили WSDL -- Создание API и реализации веб-сервиса MailService. -- Деплой и тестирование через SoapUI. - -## Доработка веб-сервиса. Кастомизация WSDL. -- Работа с JAXB. -- Передача по SOAP Exception -- Включение wsdl в сервис для публикации. -- Генерация java кода по WSDL - -## Реализация клиент веб-сервиса. -- Публикация веб сервиса из main(). Дабавление wsdl -- Выделение из wsdl общей части -- Создание клиента почтового сервиса. -- Тестирование с помощью JUnit 4 -- Интеграционное тестирование, maven-failsafe-plugin - -## JAX-WS Handlers -- Logical/protocol handlers. -- Логирование SOAP на стороне клиента. -- Логирование и статистика трафика опубликованного веб-сервиса. -- wsimport binding. -- SoapHandler аутентификация. -Добавляем файлы вложения. Mail-Service. - -## Создаем вложения почты -- Генерация обновленного WSDL через wsgen -- Веб-сервисы: JAX-WS attachment with MTOM -- Тестирование вложений через SoapUi. - -## Загрузка файлов. -- Стандарт MIME. Обрабатываем вложения на форме: commons-fileupload -- Загрузка файла вместе в полями формы. -- Вызов клиента с вложениями. - -## Персистентность. -- NoSQL or RDBMS. Обзор NoSQL систем. CAP -- Обзор Java persistence solution: commons-dbutils, Spring JdbcTemplate, MyBatis, JOOQ, ORM (Hibernate, TopLink, ElipseLink, EBean used in Playframework). JPA. JPA Performance Benchmark -- Работа с базой: создание базы, настройка IDEA Database. -- Работа с DB через DataSource, настройка tomcat. HikariCP -- Настройка работы с DataSource из JUnit. - -## REST веб сервис. -- JAX-RS. Интеграция с Jersey -- Поддержка Json. Jackson - -## Асинхронность. -- @OneWay vs Java Execution framework -- Добавление в клиенте асинхронных вызовов. -- Асинхронные сервлеты 3.x в Tomcat +# Многомодульный maven. Многопоточность. XML. Веб сервисы. Удаленное взаимодействие +## Регистрация +## [Программа проекта](#Программа-проекта) + +### _Разработка полнофункционального многомодульного Maven проекта_ +- веб приложение (Tomcat, Thymleaf, jQuery) +- модуль экспорта из XML (JAXB, StAX) +- многопоточный почтовый сервис (JavaMail, java.util.concurrent.*) +- связь модулей через веб-сервисы (SOAP, JAX-WS) и по REST (JAX-RS) +- сохранение данных в RMDBS (postgresql) +- библиотеки Guava, StreamEx, Lombook, Typesafe config, jDBI + +### Требование к участникам +Опыт программирования на Java. Базовые знания Maven. + +### Необходимое ПО +- JDK8 +- Git +- IntelliJ IDEA + +> Выбирать Ultimate, 30 days trial (работа с JavaScript, Tomcat, JSP). Персональный ключ к Ultimate (на 6 месяцев) выдается на первом занятии. + +# Первое занятие: многопоточность. + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Вступление. Многопоточность и параллельность. +![Concurrent vs Parallel](https://joearms.github.io/images/con_and_par.jpg) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Структура памяти Java. Ленивая инициализация. +> В видео в `LazySingleton` ошибка: должно быть как в коде проекта `instance == null` + +### Структура памяти: куча, стек, permanent/metaspace + - JVM изнутри - оптимизация и профилирование. + - Stack and Heap + - Дополнительно: + - Из каких частей состоит память java процесса. + - Permanent область памяти + - Java thread stack + - Размер Java объектов + +### Ленивая инициализация +- Реализация Singleton в JAVA +- Double checked locking +- Initialization-on-demand holder idiom +- Подводные камни Singleton + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Реализация многопоточности в Java +- Параллелизм в Java +- Монитор (синхронизация) +- Compare-and-swap +- Java Memory Model +- Синхронизация потоков +- Обзор java.util.concurrent.* +- Как работает ConcurrentHashMap +- Справочник по синхронизаторам java.util.concurrent.* +- Использование ThreadLocal переменных +- Николай Алименков — Прикладная многопоточность +- Can thread switching happen in the synchronized block? + +#### Tproger: Многопоточное программирование в Java 8 +- 1. Параллельное выполнение кода с помощью потоков +- 2. Синхронизация доступа к изменяемым объектам +- 3. Атомарные переменные и конкурентные таблицы + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Реализация многопоточной отправки писем. Execution Framework +> правка к видео: `22: completionService.submit(..)` -## Динамическое конфигурирование. JMX -- Maven Groovy cкрптинг. groovy-maven-plugin -- Настройка Tomcat на удаленное администрирование по JMX +### ![](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Все изменения в проекте будут делаться на основе патчей: скачайте [1_1_MailService.patch](https://drive.google.com/open?id=0B9Ye2auQ_NsFTE5ZV3pzWElxTWM), положите его в проект, правой мышкой на нем сделайте Apply Patch ... -## Отправка email в многопоточном приложении -- Initialization on demand holder / Double-checked locking -- java.util.concurrent.*: Executors , Synchronizers, Concurrent Collections, Lock +---------------------------- -## Проблема MemoryLeak. Поиск утечки памяти. +### Ресурсы (основы) +- Intuit, Потоки выполнения. Синхронизация +- Алексей Владыкин, Основы многопоточность в Java +- Виталий Чибриков, Java. Многопоточность +- Computer Science Center, курс Параллельное программирование +- Юрий Ткач, курс Advanced Java - Concurrency +- Головач, курс Java Multithreading + +--- +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Задание первого занятия + +Вычекать этот проект: +```git clone https://github.com/JavaOPs/masterjava.git``` + +- Применить оптимизацию к MatrixUtil.singleThreadMultiply +- Реализовать метод `MatrixUtil.concurrentMultiply`, позволяющий многопоточно перемножать квадратные матрицы N*N. +- Количество дочерних потоков ограничено `MainMatrix.THREAD_NUMBER`. +- Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной + +----- +## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW1 +- не делайте 1000 000 тасок, лучше их сделать крупнее +- у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно +- наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply3`). Мои результаты: +``` +Benchmark (matrixSize) Mode Cnt Score Error Units +MatrixBenchmark.singleThreadMultiplyOpt 1000 ss 100 837,867 ± 25,530 ms/op +MatrixBenchmark.concurrentMultiply2 1000 ss 100 394,294 ± 21,657 ms/op +MatrixBenchmark.concurrentMultiply3 1000 ss 100 186,827 ± 11,882 ms/op +``` +----- +# Программа проекта + +## Занятие 2 +- Разбор ДЗ (многопоточная реализация умножения матриц) +- Java Microbenchmark JMH (от Алексея Шипилева) +- Обзор Guava +- Формат XML. Создание схемы XSD. +- Работа с XML в Java + - JAXB, JAXP + - StAX + - XPath + - XSLT + +## Занятие 3 +- Разбор ДЗ (работа с XML) +- Обзор StreamEx (от Тагира Валеева) +- Монады. flatMap +- SOA и Микросервисы +- Многомодульный Maven проект + +## Занятие 4 +- Разбор ДЗ (реализация структуры проекта, загрузка и разбор xml) +- Thymleaf +- Maven. Поиск и разрешение конфликтов зависимостей +- Логирование +- Выбор lightweight JDBC helper library. JDBI +- Tomcat Class Loader. Memory Leaks + +## Занятие 5 +- Разбор ДЗ (реализуем модули persist, export и web) +- Конфигурирование приложения (Typesafe config) +- Lombook + +## Занятие 6 +- Разбор ДЗ (доработка модели и модуля export) +- Миграция DB +- Веб-сервисы (REST/SOAP) + - Java реализации SOAP + - Имплементируем Mail Service + +## Занятие 7 +- Разбор ДЗ (реализация MailSender, сохранение результатов отправки) +- Стили WSDL. Кастомизация WSDL +- Публикация кастомизированного WSDL. Автогенерация. +- Деплой в Tomcat +- Создание клиента почтового сервиса + +## Занятие 8 +- Разбор ДЗ (отправка почты через Executor из модуля web) +- Доступ к переменным maven в приложении +- SOAP Exception. Выделение общей части схемы +- Передача двоичных данных в веб-сервисах. MTOM + +## Занятие 9 +- Разбор ДЗ (реализация загрузки и отправки вложений по почте) +- JAX-WS Message Context +- JAX-WS Handlers (логирование SOAP) + +## Занятие 10 +- Разбор ДЗ (реализация авторизации и статистики) +- JavaEE + - CDI + - JAX-RS. Интеграция с Jersey + - EJB + - JMS + +## Занятие 11 (предварительно) +- Асинхронные сервлеты 3.x в Tomcat +- Maven Groovy cкрптинг (groovy-maven-plugin) +- AKKA +- Redis diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 000000000..33d3da8ed --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + + ru.javaops + parent + ../parent/pom.xml + 1.0-SNAPSHOT + + + common + 1.0-SNAPSHOT + jar + Common + + + + \ No newline at end of file diff --git a/common/src/main/java/ru/javaops/masterjava/ExceptionType.java b/common/src/main/java/ru/javaops/masterjava/ExceptionType.java new file mode 100644 index 000000000..8489c2f24 --- /dev/null +++ b/common/src/main/java/ru/javaops/masterjava/ExceptionType.java @@ -0,0 +1,37 @@ +package ru.javaops.masterjava; + +import javax.xml.bind.annotation.XmlType; + +@XmlType(namespace = "http://common.javaops.ru/") +public enum ExceptionType { + SYSTEM("Системная ошибка"), + DATA_BASE("Ошибка базы данных"), + STATE("Неверное состояние приложения"), + AUTHORIZATION("Ошибка авторизации"), + CONFIGURATION("Ошибка конфигурирования"), + ILLEGAL_ARGUMENT("Неверный аргумент"), + BPM("Ошибка бизнес-процесса"), + FILE("Ошибка при работе с файловой системой"), + REPORTS("Ошибка в отчете"), + EMAIL("Ошибка при отправке почты"), + TEMPLATE("Ошибка в шаблонах"), + ONE_C("Ошибка в системе 1C"), + ATTACH("Ошибка вложенного файла"), + LDAP("Ошибка соединения с LDAP"), + NETWORK("Сетевая Ошибка"); + + final private String descr; + + ExceptionType(String title) { + this.descr = title; + } + + public String getDescr() { + return descr; + } + + @Override + public String toString() { + return name() + " (" + descr + ')'; + } +} diff --git a/common/src/main/java/ru/javaops/masterjava/config/Configs.java b/common/src/main/java/ru/javaops/masterjava/config/Configs.java new file mode 100644 index 000000000..1c9b1ccd7 --- /dev/null +++ b/common/src/main/java/ru/javaops/masterjava/config/Configs.java @@ -0,0 +1,25 @@ +package ru.javaops.masterjava.config; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; + +import java.io.File; + +public class Configs { + + public static Config getConfig(String resource) { + return ConfigFactory.parseResources(resource).resolve(); + } + + public static Config getConfig(String resource, String domain) { + return getConfig(resource).getConfig(domain); + } + + public static File getConfigFile(String path) { + return new File(AppConfig.APP_CONFIG.getString("configDir"), path); + } + + private static class AppConfig { + private static final Config APP_CONFIG = getConfig("app.conf", "app"); + } +} diff --git a/common/src/main/resources/hosts.conf b/common/src/main/resources/hosts.conf new file mode 100644 index 000000000..6b0157bfe --- /dev/null +++ b/common/src/main/resources/hosts.conf @@ -0,0 +1,10 @@ +hosts { + mail { + endpoint = "http://localhost:8080" + debug.client = DEBUG + debug.server = INFO + user = "user" + password = "password" + } +} +include file("/apps/masterjava/config/hosts.conf") diff --git a/config_templates/app.conf b/config_templates/app.conf new file mode 100644 index 000000000..d2aee4c5b --- /dev/null +++ b/config_templates/app.conf @@ -0,0 +1,6 @@ +app { + groupId = ${project.groupId} + projectName = ${project.name} + version = ${project.version} + configDir = "${masterjava.config}" +} \ No newline at end of file diff --git a/config_templates/context.xml b/config_templates/context.xml new file mode 100644 index 000000000..40bb8aa0c --- /dev/null +++ b/config_templates/context.xml @@ -0,0 +1,49 @@ + + + + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + + + + + + + + diff --git a/config_templates/logback-test.xml b/config_templates/logback-test.xml new file mode 100644 index 000000000..739dd6dcf --- /dev/null +++ b/config_templates/logback-test.xml @@ -0,0 +1,21 @@ + + + + true + + + + + UTF-8 + %-5level %logger{0} [%file:%line] %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/config_templates/logback.xml b/config_templates/logback.xml new file mode 100644 index 000000000..352ee14a0 --- /dev/null +++ b/config_templates/logback.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + ${LOG_DIR}/${project.build.finalName}.log + + UTF-8 + %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{0} [%file:%line] - %msg%n + + + + ${LOG_DIR}/archived/${project.build.finalName}.%d{yyyy-MM-dd}.%i.log + + + 5MB + + + + + + + UTF-8 + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} [%file:%line] - %msg%n + + + + + + + + + + diff --git a/config_templates/version.html b/config_templates/version.html new file mode 100644 index 000000000..3cffc3842 --- /dev/null +++ b/config_templates/version.html @@ -0,0 +1,11 @@ + + + + ${project.name} + + +${project.groupId}:${project.name}:${project.version}
+configDir=${masterjava.config}
+Многопоточность. Maven. XML. Веб сервисы. + + diff --git a/config_templates/wsdl/common.xsd b/config_templates/wsdl/common.xsd new file mode 100644 index 000000000..5c47776cd --- /dev/null +++ b/config_templates/wsdl/common.xsd @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config_templates/wsdl/mailService.wsdl b/config_templates/wsdl/mailService.wsdl new file mode 100644 index 000000000..391bffc24 --- /dev/null +++ b/config_templates/wsdl/mailService.wsdl @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/parent-web/pom.xml b/parent-web/pom.xml new file mode 100644 index 000000000..17f1f347f --- /dev/null +++ b/parent-web/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + + ru.javaops + parent + ../parent/pom.xml + 1.0-SNAPSHOT + + + parent-web + pom + 1.0-SNAPSHOT + Parent Web + + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + false + + + src/main/webapp + + + ${masterjava.config} + + version.html + + true + + + + + + + + org.codehaus.cargo + cargo-maven2-plugin + 1.6.2 + + + tomcat8x + + UTF-8 + + + + org.postgresql + postgresql + + + + + + + ${masterjava.config}/context.xml + conf/Catalina/localhost/ + context.xml.default + + + + + + ${project.groupId} + ${project.artifactId} + war + + ${project.build.finalName} + + + + + + + + + + + ${masterjava.config} + true + + logback.xml + app.conf + + + + src/main/resources + + + + + + + ${project.groupId} + common-web + ${project.version} + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + + + + + + \ No newline at end of file diff --git a/parent/pom.xml b/parent/pom.xml new file mode 100644 index 000000000..46400fac3 --- /dev/null +++ b/parent/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + + ru.javaops + parent + pom + 1.0-SNAPSHOT + Parent + + + 1.8 + UTF-8 + UTF-8 + + 1.2.2 + 1.7.25 + + + /apps/masterjava/config/ + false + + + + install + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + -Dfile.encoding=UTF-8 + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.4.1 + + + enforce + + + + + + + enforce + + + + + + + + + ${masterjava.config} + + logback-test.xml + + + + src/test/resources + + + + + + + com.google.guava + guava + 21.0 + + + one.util + streamex + 0.6.2 + + + + com.typesafe + config + 1.3.1 + + + + org.projectlombok + lombok + 1.16.16 + provided + + + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + runtime + + + + ch.qos.logback + logback-classic + ${logback.version} + + + + + junit + junit + 4.12 + test + + + + + + + + + + \ No newline at end of file diff --git a/patches/1_1_MailService.patch b/patches/1_1_MailService.patch new file mode 100644 index 000000000..3a6266eff --- /dev/null +++ b/patches/1_1_MailService.patch @@ -0,0 +1,96 @@ +Index: src/main/java/ru/javaops/masterjava/service/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/service/MailService.java (revision 500495ec05bb1a01c3811657f6d0770347ff8a8d) ++++ src/main/java/ru/javaops/masterjava/service/MailService.java (revision ) +@@ -1,8 +1,10 @@ + package ru.javaops.masterjava.service; + +-import java.util.Collections; ++import java.util.ArrayList; + import java.util.List; + import java.util.Set; ++import java.util.concurrent.*; ++import java.util.stream.Collectors; + + public class MailService { + private static final String OK = "OK"; +@@ -11,10 +13,74 @@ + private static final String INTERRUPTED_BY_TIMEOUT = "+++ Interrupted by timeout"; + private static final String INTERRUPTED_EXCEPTION = "+++ InterruptedException"; + ++ private final ExecutorService mailExecutor = Executors.newFixedThreadPool(8); ++ + public GroupResult sendToList(final String template, final Set emails) throws Exception { +- return new GroupResult(0, Collections.emptyList(), null); +- } ++ final CompletionService completionService = new ExecutorCompletionService<>(mailExecutor); ++ ++ List> futures = emails.stream() ++ .map(email -> completionService.submit(() -> sendToUser(template, email))) ++ .collect(Collectors.toList()); ++ ++ return new Callable() { ++ private int success = 0; ++ private List failed = new ArrayList<>(); ++ ++ @Override ++ public GroupResult call() { ++ while (!futures.isEmpty()) { ++ try { ++ Future future = completionService.poll(10, TimeUnit.SECONDS); ++ if (future == null) { ++ return cancelWithFail(INTERRUPTED_BY_TIMEOUT); ++ } ++ futures.remove(future); ++ MailResult mailResult = future.get(); ++ if (mailResult.isOk()) { ++ success++; ++ } else { ++ failed.add(mailResult); ++ if (failed.size() >= 5) { ++ return cancelWithFail(INTERRUPTED_BY_FAULTS_NUMBER); ++ } ++ } ++ } catch (ExecutionException e) { ++ return cancelWithFail(e.getCause().toString()); ++ } catch (InterruptedException e) { ++ return cancelWithFail(INTERRUPTED_EXCEPTION); ++ } ++ } ++/* ++ for (Future future : futures) { ++ MailResult mailResult; ++ try { ++ mailResult = future.get(10, TimeUnit.SECONDS); ++ } catch (InterruptedException e) { ++ return cancelWithFail(INTERRUPTED_EXCEPTION); ++ } catch (ExecutionException e) { ++ return cancelWithFail(e.getCause().toString()); ++ } catch (TimeoutException e) { ++ return cancelWithFail(INTERRUPTED_BY_TIMEOUT); ++ } ++ if (mailResult.isOk()) { ++ success++; ++ } else { ++ failed.add(mailResult); ++ if (failed.size() >= 5) { ++ return cancelWithFail(INTERRUPTED_BY_FAULTS_NUMBER); ++ } ++ } ++ } ++*/ ++ return new GroupResult(success, failed, null); ++ } + ++ private GroupResult cancelWithFail(String cause) { ++ futures.forEach(f -> f.cancel(true)); ++ return new GroupResult(success, failed, cause); ++ } ++ }.call(); ++ } + + // dummy realization + public MailResult sendToUser(String template, String email) throws Exception { diff --git a/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch b/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch new file mode 100644 index 000000000..64e55f4ba --- /dev/null +++ b/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch @@ -0,0 +1,54 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision 2306fbe9700d2df86b864a80a1a97f92f61d8324) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision ) +@@ -18,18 +18,24 @@ + return matrixC; + } + +- // TODO optimize by https://habrahabr.ru/post/114797/ +- public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { ++ // Optimized by https://habrahabr.ru/post/114797/ ++ public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + +- for (int i = 0; i < matrixSize; i++) { +- for (int j = 0; j < matrixSize; j++) { ++ for (int col = 0; col < matrixSize; col++) { ++ final int[] columnB = new int[matrixSize]; ++ for (int k = 0; k < matrixSize; k++) { ++ columnB[k] = matrixB[k][col]; ++ } ++ ++ for (int row = 0; row < matrixSize; row++) { + int sum = 0; ++ final int[] rowA = matrixA[row]; + for (int k = 0; k < matrixSize; k++) { +- sum += matrixA[i][k] * matrixB[k][j]; ++ sum += rowA[k] * columnB[k]; + } +- matrixC[i][j] = sum; ++ matrixC[row][col] = sum; + } + } + return matrixC; +Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision 2306fbe9700d2df86b864a80a1a97f92f61d8324) ++++ src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision ) +@@ -24,7 +24,7 @@ + while (count < 6) { + System.out.println("Pass " + count); + long start = System.currentTimeMillis(); +- final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); ++ final int[][] matrixC = MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); + double duration = (System.currentTimeMillis() - start) / 1000.; + out("Single thread time, sec: %.3f", duration); + singleThreadSum += duration; diff --git a/patches/lesson02/2_02_HW1_concurrentMultiply.patch b/patches/lesson02/2_02_HW1_concurrentMultiply.patch new file mode 100644 index 000000000..f0bc080a4 --- /dev/null +++ b/patches/lesson02/2_02_HW1_concurrentMultiply.patch @@ -0,0 +1,182 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1488832892000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision ) +@@ -1,8 +1,9 @@ + package ru.javaops.masterjava.matrix; + +-import java.util.Random; +-import java.util.concurrent.ExecutionException; +-import java.util.concurrent.ExecutorService; ++import java.util.*; ++import java.util.concurrent.*; ++import java.util.stream.Collectors; ++import java.util.stream.IntStream; + + /** + * gkislin +@@ -10,11 +11,153 @@ + */ + public class MatrixUtil { + +- // TODO implement parallel multiplication matrixA*matrixB + public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + ++ class ColumnMultipleResult { ++ private final int col; ++ private final int[] columnC; ++ ++ private ColumnMultipleResult(int col, int[] columnC) { ++ this.col = col; ++ this.columnC = columnC; ++ } ++ } ++ ++ final CompletionService completionService = new ExecutorCompletionService<>(executor); ++ ++ for (int j = 0; j < matrixSize; j++) { ++ final int col = j; ++ final int[] columnB = new int[matrixSize]; ++ for (int k = 0; k < matrixSize; k++) { ++ columnB[k] = matrixB[k][col]; ++ } ++ completionService.submit(() -> { ++ final int[] columnC = new int[matrixSize]; ++ ++ for (int row = 0; row < matrixSize; row++) { ++ final int[] rowA = matrixA[row]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += rowA[k] * columnB[k]; ++ } ++ columnC[row] = sum; ++ } ++ return new ColumnMultipleResult(col, columnC); ++ }); ++ } ++ ++ for (int i = 0; i < matrixSize; i++) { ++ ColumnMultipleResult res = completionService.take().get(); ++ for (int k = 0; k < matrixSize; k++) { ++ matrixC[k][res.col] = res.columnC[k]; ++ } ++ } ++ return matrixC; ++ } ++ ++ public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { ++ final int matrixSize = matrixA.length; ++ final int[][] matrixResult = new int[matrixSize][matrixSize]; ++ final int threadCount = Runtime.getRuntime().availableProcessors(); ++ final int maxIndex = matrixSize * matrixSize; ++ final int cellsInThread = maxIndex / threadCount; ++ final int[][] matrixBFinal = new int[matrixSize][matrixSize]; ++ ++ for (int i = 0; i < matrixSize; i++) { ++ for (int j = 0; j < matrixSize; j++) { ++ matrixBFinal[i][j] = matrixB[j][i]; ++ } ++ } ++ ++ Set> threads = new HashSet<>(); ++ int fromIndex = 0; ++ for (int i = 1; i <= threadCount; i++) { ++ final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; ++ final int firstIndexFinal = fromIndex; ++ threads.add(() -> { ++ for (int j = firstIndexFinal; j < toIndex; j++) { ++ final int row = j / matrixSize; ++ final int col = j % matrixSize; ++ ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += matrixA[row][k] * matrixBFinal[col][k]; ++ } ++ matrixResult[row][col] = sum; ++ } ++ return true; ++ }); ++ fromIndex = toIndex; ++ } ++ executor.invokeAll(threads); ++ return matrixResult; ++ } ++ ++ public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) ++ throws InterruptedException, ExecutionException { ++ ++ final int matrixSize = matrixA.length; ++ final int[][] matrixC = new int[matrixSize][matrixSize]; ++ ++ List> tasks = IntStream.range(0, matrixSize) ++ .parallel() ++ .mapToObj(i -> new Callable() { ++ private final int[] tempColumn = new int[matrixSize]; ++ ++ @Override ++ public Void call() throws Exception { ++ for (int c = 0; c < matrixSize; c++) { ++ tempColumn[c] = matrixB[c][i]; ++ } ++ for (int j = 0; j < matrixSize; j++) { ++ int row[] = matrixA[j]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += tempColumn[k] * row[k]; ++ } ++ matrixC[j][i] = sum; ++ } ++ return null; ++ } ++ }) ++ .collect(Collectors.toList()); ++ ++ executor.invokeAll(tasks); ++ return matrixC; ++ } ++ ++ public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { ++ final int matrixSize = matrixA.length; ++ final int[][] matrixC = new int[matrixSize][]; ++ ++ final int[][] matrixBT = new int[matrixSize][matrixSize]; ++ for (int i = 0; i < matrixSize; i++) { ++ for (int j = 0; j < matrixSize; j++) { ++ matrixBT[i][j] = matrixB[j][i]; ++ } ++ } ++ ++ List> tasks = new ArrayList<>(matrixSize); ++ for (int j = 0; j < matrixSize; j++) { ++ final int row = j; ++ tasks.add(() -> { ++ final int[] rowC = new int[matrixSize]; ++ for (int col = 0; col < matrixSize; col++) { ++ final int[] rowA = matrixA[row]; ++ final int[] columnB = matrixBT[col]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += rowA[k] * columnB[k]; ++ } ++ rowC[col] = sum; ++ } ++ matrixC[row] = rowC; ++ return null; ++ }); ++ } ++ executor.invokeAll(tasks); + return matrixC; + } + +@@ -64,4 +207,4 @@ + } + return true; + } +-} ++} +\ No newline at end of file diff --git a/patches/lesson02/2_03_HW1_concurrentMultiply3.patch b/patches/lesson02/2_03_HW1_concurrentMultiply3.patch new file mode 100644 index 000000000..edc3a1457 --- /dev/null +++ b/patches/lesson02/2_03_HW1_concurrentMultiply3.patch @@ -0,0 +1,163 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1488833367000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision ) +@@ -1,7 +1,12 @@ + package ru.javaops.masterjava.matrix; + +-import java.util.*; +-import java.util.concurrent.*; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Random; ++import java.util.concurrent.Callable; ++import java.util.concurrent.CountDownLatch; ++import java.util.concurrent.ExecutionException; ++import java.util.concurrent.ExecutorService; + import java.util.stream.Collectors; + import java.util.stream.IntStream; + +@@ -11,91 +16,7 @@ + */ + public class MatrixUtil { + +- public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { +- final int matrixSize = matrixA.length; +- final int[][] matrixC = new int[matrixSize][matrixSize]; +- +- class ColumnMultipleResult { +- private final int col; +- private final int[] columnC; +- +- private ColumnMultipleResult(int col, int[] columnC) { +- this.col = col; +- this.columnC = columnC; +- } +- } +- +- final CompletionService completionService = new ExecutorCompletionService<>(executor); +- +- for (int j = 0; j < matrixSize; j++) { +- final int col = j; +- final int[] columnB = new int[matrixSize]; +- for (int k = 0; k < matrixSize; k++) { +- columnB[k] = matrixB[k][col]; +- } +- completionService.submit(() -> { +- final int[] columnC = new int[matrixSize]; +- +- for (int row = 0; row < matrixSize; row++) { +- final int[] rowA = matrixA[row]; +- int sum = 0; +- for (int k = 0; k < matrixSize; k++) { +- sum += rowA[k] * columnB[k]; +- } +- columnC[row] = sum; +- } +- return new ColumnMultipleResult(col, columnC); +- }); +- } +- +- for (int i = 0; i < matrixSize; i++) { +- ColumnMultipleResult res = completionService.take().get(); +- for (int k = 0; k < matrixSize; k++) { +- matrixC[k][res.col] = res.columnC[k]; +- } +- } +- return matrixC; +- } +- +- public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { +- final int matrixSize = matrixA.length; +- final int[][] matrixResult = new int[matrixSize][matrixSize]; +- final int threadCount = Runtime.getRuntime().availableProcessors(); +- final int maxIndex = matrixSize * matrixSize; +- final int cellsInThread = maxIndex / threadCount; +- final int[][] matrixBFinal = new int[matrixSize][matrixSize]; +- +- for (int i = 0; i < matrixSize; i++) { +- for (int j = 0; j < matrixSize; j++) { +- matrixBFinal[i][j] = matrixB[j][i]; +- } +- } +- +- Set> threads = new HashSet<>(); +- int fromIndex = 0; +- for (int i = 1; i <= threadCount; i++) { +- final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; +- final int firstIndexFinal = fromIndex; +- threads.add(() -> { +- for (int j = firstIndexFinal; j < toIndex; j++) { +- final int row = j / matrixSize; +- final int col = j % matrixSize; +- +- int sum = 0; +- for (int k = 0; k < matrixSize; k++) { +- sum += matrixA[row][k] * matrixBFinal[col][k]; +- } +- matrixResult[row][col] = sum; +- } +- return true; +- }); +- fromIndex = toIndex; +- } +- executor.invokeAll(threads); +- return matrixResult; +- } +- +- public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) ++ public static int[][] concurrentMultiplyStreams(int[][] matrixA, int[][] matrixB, ExecutorService executor) + throws InterruptedException, ExecutionException { + + final int matrixSize = matrixA.length; +@@ -161,7 +82,30 @@ + return matrixC; + } + +- // Optimized by https://habrahabr.ru/post/114797/ ++ public static int[][] concurrentMultiply3(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException { ++ final int matrixSize = matrixA.length; ++ final int[][] matrixC = new int[matrixSize][matrixSize]; ++ final CountDownLatch latch = new CountDownLatch(matrixSize); ++ ++ for (int row = 0; row < matrixSize; row++) { ++ final int[] rowA = matrixA[row]; ++ final int[] rowC = matrixC[row]; ++ ++ executor.submit(() -> { ++ for (int idx = 0; idx < matrixSize; idx++) { ++ final int elA = rowA[idx]; ++ final int[] rowB = matrixB[idx]; ++ for (int col = 0; col < matrixSize; col++) { ++ rowC[col] += elA * rowB[col]; ++ } ++ } ++ latch.countDown(); ++ }); ++ } ++ latch.await(); ++ return matrixC; ++ } ++ + public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; +Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (date 1488833367000) ++++ src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision ) +@@ -30,7 +30,7 @@ + singleThreadSum += duration; + + start = System.currentTimeMillis(); +- final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); ++ final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply2(matrixA, matrixB, executor); + duration = (System.currentTimeMillis() - start) / 1000.; + out("Concurrent thread time, sec: %.3f", duration); + concurrentThreadSum += duration; diff --git a/patches/lesson02/2_04_JMH_Benchmark_patch.patch b/patches/lesson02/2_04_JMH_Benchmark_patch.patch new file mode 100644 index 000000000..a6dd998d0 --- /dev/null +++ b/patches/lesson02/2_04_JMH_Benchmark_patch.patch @@ -0,0 +1,95 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) +@@ -0,0 +1,62 @@ ++package ru.javaops.masterjava.matrix; ++ ++import org.openjdk.jmh.annotations.*; ++ ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; ++import java.util.concurrent.TimeUnit; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++@Warmup(iterations = 10) ++@Measurement(iterations = 10) ++@BenchmarkMode({Mode.SingleShotTime}) ++@OutputTimeUnit(TimeUnit.MILLISECONDS) ++@State(Scope.Benchmark) ++@Threads(1) ++@Fork(1) ++@Timeout(time = 5, timeUnit = TimeUnit.MINUTES) ++public class MatrixBenchmark { ++ // Matrix size ++ @Param({"100", "1000"}) ++ private int matrixSize; ++ ++ private static final int THREAD_NUMBER = 10; ++ private final static ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMBER); ++ ++ private static int[][] matrixA; ++ private static int[][] matrixB; ++ ++ @Setup ++ public void setUp() { ++ matrixA = MatrixUtil.create(matrixSize); ++ matrixB = MatrixUtil.create(matrixSize); ++ } ++ ++ @Benchmark ++ public int[][] singleThreadMultiplyOpt() throws Exception { ++ return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); ++ } ++ ++ @Benchmark ++ public int[][] concurrentMultiplyStreams() throws Exception { ++ return MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, executor); ++ } ++ ++ @Benchmark ++ public int[][] concurrentMultiply2() throws Exception { ++ return MatrixUtil.concurrentMultiply2(matrixA, matrixB, executor); ++ } ++ ++ @Benchmark ++ public int[][] concurrentMultiply3() throws Exception { ++ return MatrixUtil.concurrentMultiply3(matrixA, matrixB, executor); ++ } ++ ++ @TearDown ++ public void tearDown() { ++ executor.shutdown(); ++ } ++} +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1488834916000) ++++ pom.xml (revision ) +@@ -34,6 +34,17 @@ + + + ++ ++ org.openjdk.jmh ++ jmh-core ++ RELEASE ++ ++ ++ org.openjdk.jmh ++ jmh-generator-annprocess ++ RELEASE ++ provided ++ + + + diff --git a/patches/lesson02/2_05_JMH_main_jar.patch b/patches/lesson02/2_05_JMH_main_jar.patch new file mode 100644 index 000000000..4033562e9 --- /dev/null +++ b/patches/lesson02/2_05_JMH_main_jar.patch @@ -0,0 +1,107 @@ +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1488835608000) ++++ pom.xml (revision ) +@@ -30,6 +30,41 @@ + ${java.version} + + ++ ++ org.apache.maven.plugins ++ maven-shade-plugin ++ 2.2 ++ ++ ++ package ++ ++ shade ++ ++ ++ benchmarks ++ ++ ++ org.openjdk.jmh.Main ++ ++ ++ ++ ++ ++ *:* ++ ++ META-INF/*.SF ++ META-INF/*.DSA ++ META-INF/*.RSA ++ ++ ++ ++ ++ ++ ++ + + + +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (date 1488835608000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) +@@ -1,6 +1,11 @@ + package ru.javaops.masterjava.matrix; + + import org.openjdk.jmh.annotations.*; ++import org.openjdk.jmh.runner.Runner; ++import org.openjdk.jmh.runner.RunnerException; ++import org.openjdk.jmh.runner.options.Options; ++import org.openjdk.jmh.runner.options.OptionsBuilder; ++import org.openjdk.jmh.runner.options.TimeValue; + + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; +@@ -16,11 +21,11 @@ + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Benchmark) + @Threads(1) +-@Fork(1) ++@Fork(10) + @Timeout(time = 5, timeUnit = TimeUnit.MINUTES) + public class MatrixBenchmark { + // Matrix size +- @Param({"100", "1000"}) ++ @Param({"1000"}) + private int matrixSize; + + private static final int THREAD_NUMBER = 10; +@@ -35,12 +40,22 @@ + matrixB = MatrixUtil.create(matrixSize); + } + +- @Benchmark ++ public static void main(String[] args) throws RunnerException { ++ Options options = new OptionsBuilder() ++ .include(MatrixBenchmark.class.getSimpleName()) ++ .threads(1) ++ .forks(10) ++ .timeout(TimeValue.minutes(5)) ++ .build(); ++ new Runner(options).run(); ++ } ++ ++// @Benchmark + public int[][] singleThreadMultiplyOpt() throws Exception { + return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); + } + +- @Benchmark ++// @Benchmark + public int[][] concurrentMultiplyStreams() throws Exception { + return MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, executor); + } diff --git a/patches/lesson02/2_06_xml_scheme.patch b/patches/lesson02/2_06_xml_scheme.patch new file mode 100644 index 000000000..5222ac908 --- /dev/null +++ b/patches/lesson02/2_06_xml_scheme.patch @@ -0,0 +1,754 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/CityType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision ) +@@ -0,0 +1,94 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlID; ++import javax.xml.bind.annotation.XmlSchemaType; ++import javax.xml.bind.annotation.XmlType; ++import javax.xml.bind.annotation.XmlValue; ++import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; ++import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; ++ ++ ++/** ++ *

Java class for cityType complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++ * <complexType name="cityType">
++ *   <simpleContent>
++ *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
++ *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++ *     </extension>
++ *   </simpleContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "cityType", namespace = "http://javaops.ru", propOrder = { ++ "value" ++}) ++public class CityType { ++ ++ @XmlValue ++ protected String value; ++ @XmlAttribute(name = "id", required = true) ++ @XmlJavaTypeAdapter(CollapsedStringAdapter.class) ++ @XmlID ++ @XmlSchemaType(name = "ID") ++ protected String id; ++ ++ /** ++ * Gets the value of the value property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getValue() { ++ return value; ++ } ++ ++ /** ++ * Sets the value of the value property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setValue(String value) { ++ this.value = value; ++ } ++ ++ /** ++ * Gets the value of the id property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getId() { ++ return id; ++ } ++ ++ /** ++ * Sets the value of the id property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setId(String value) { ++ this.id = value; ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) +@@ -0,0 +1,151 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlElement; ++import javax.xml.bind.annotation.XmlIDREF; ++import javax.xml.bind.annotation.XmlRootElement; ++import javax.xml.bind.annotation.XmlSchemaType; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++ * <complexType>
++ *   <complexContent>
++ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *       <sequence>
++ *         <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ *         <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ *       </sequence>
++ *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
++ *       <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
++ *     </restriction>
++ *   </complexContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "", propOrder = { ++ "email", ++ "fullName" ++}) ++@XmlRootElement(name = "User", namespace = "http://javaops.ru") ++public class User { ++ ++ @XmlElement(namespace = "http://javaops.ru", required = true) ++ protected String email; ++ @XmlElement(namespace = "http://javaops.ru", required = true) ++ protected String fullName; ++ @XmlAttribute(name = "flag", required = true) ++ protected FlagType flag; ++ @XmlAttribute(name = "city", required = true) ++ @XmlIDREF ++ @XmlSchemaType(name = "IDREF") ++ protected Object city; ++ ++ /** ++ * Gets the value of the email property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getEmail() { ++ return email; ++ } ++ ++ /** ++ * Sets the value of the email property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setEmail(String value) { ++ this.email = value; ++ } ++ ++ /** ++ * Gets the value of the fullName property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getFullName() { ++ return fullName; ++ } ++ ++ /** ++ * Sets the value of the fullName property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setFullName(String value) { ++ this.fullName = value; ++ } ++ ++ /** ++ * Gets the value of the flag property. ++ * ++ * @return ++ * possible object is ++ * {@link FlagType } ++ * ++ */ ++ public FlagType getFlag() { ++ return flag; ++ } ++ ++ /** ++ * Sets the value of the flag property. ++ * ++ * @param value ++ * allowed object is ++ * {@link FlagType } ++ * ++ */ ++ public void setFlag(FlagType value) { ++ this.flag = value; ++ } ++ ++ /** ++ * Gets the value of the city property. ++ * ++ * @return ++ * possible object is ++ * {@link Object } ++ * ++ */ ++ public Object getCity() { ++ return city; ++ } ++ ++ /** ++ * Sets the value of the city property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Object } ++ * ++ */ ++ public void setCity(Object value) { ++ this.city = value; ++ } ++ ++} +Index: src/test/resources/payload.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/resources/payload.xml (revision ) ++++ src/test/resources/payload.xml (revision ) +@@ -0,0 +1,23 @@ ++ ++ ++ ++ gmail@gmail.com ++ Full Name ++ ++ ++ admin@javaops.ru ++ Admin ++ ++ ++ mail@yandex.ru ++ Deleted ++ ++ ++ ++ Санкт-Петербург ++ Киев ++ Минск ++ ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision ) +@@ -0,0 +1,233 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import java.util.ArrayList; ++import java.util.List; ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlElement; ++import javax.xml.bind.annotation.XmlRootElement; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++ * <complexType>
++ *   <complexContent>
++ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *       <all>
++ *         <element name="Cities">
++ *           <complexType>
++ *             <complexContent>
++ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *                 <sequence maxOccurs="unbounded">
++ *                   <element ref="{http://javaops.ru}City"/>
++ *                 </sequence>
++ *               </restriction>
++ *             </complexContent>
++ *           </complexType>
++ *         </element>
++ *         <element name="Users">
++ *           <complexType>
++ *             <complexContent>
++ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *                 <sequence maxOccurs="unbounded" minOccurs="0">
++ *                   <element ref="{http://javaops.ru}User"/>
++ *                 </sequence>
++ *               </restriction>
++ *             </complexContent>
++ *           </complexType>
++ *         </element>
++ *       </all>
++ *     </restriction>
++ *   </complexContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "", propOrder = { ++ ++}) ++@XmlRootElement(name = "Payload", namespace = "http://javaops.ru") ++public class Payload { ++ ++ @XmlElement(name = "Cities", namespace = "http://javaops.ru", required = true) ++ protected Payload.Cities cities; ++ @XmlElement(name = "Users", namespace = "http://javaops.ru", required = true) ++ protected Payload.Users users; ++ ++ /** ++ * Gets the value of the cities property. ++ * ++ * @return ++ * possible object is ++ * {@link Payload.Cities } ++ * ++ */ ++ public Payload.Cities getCities() { ++ return cities; ++ } ++ ++ /** ++ * Sets the value of the cities property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Payload.Cities } ++ * ++ */ ++ public void setCities(Payload.Cities value) { ++ this.cities = value; ++ } ++ ++ /** ++ * Gets the value of the users property. ++ * ++ * @return ++ * possible object is ++ * {@link Payload.Users } ++ * ++ */ ++ public Payload.Users getUsers() { ++ return users; ++ } ++ ++ /** ++ * Sets the value of the users property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Payload.Users } ++ * ++ */ ++ public void setUsers(Payload.Users value) { ++ this.users = value; ++ } ++ ++ ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <sequence maxOccurs="unbounded">
++     *         <element ref="{http://javaops.ru}City"/>
++     *       </sequence>
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "", propOrder = { ++ "city" ++ }) ++ public static class Cities { ++ ++ @XmlElement(name = "City", namespace = "http://javaops.ru", required = true) ++ protected List city; ++ ++ /** ++ * Gets the value of the city property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the city property. ++ * ++ *

++ * For example, to add a new item, do as follows: ++ *

++         *    getCity().add(newItem);
++         * 
++ * ++ * ++ *

++ * Objects of the following type(s) are allowed in the list ++ * {@link CityType } ++ * ++ * ++ */ ++ public List getCity() { ++ if (city == null) { ++ city = new ArrayList(); ++ } ++ return this.city; ++ } ++ ++ } ++ ++ ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <sequence maxOccurs="unbounded" minOccurs="0">
++     *         <element ref="{http://javaops.ru}User"/>
++     *       </sequence>
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "", propOrder = { ++ "user" ++ }) ++ public static class Users { ++ ++ @XmlElement(name = "User", namespace = "http://javaops.ru") ++ protected List user; ++ ++ /** ++ * Gets the value of the user property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the user property. ++ * ++ *

++ * For example, to add a new item, do as follows: ++ *

++         *    getUser().add(newItem);
++         * 
++ * ++ * ++ *

++ * Objects of the following type(s) are allowed in the list ++ * {@link User } ++ * ++ * ++ */ ++ public List getUser() { ++ if (user == null) { ++ user = new ArrayList(); ++ } ++ return this.user; ++ } ++ ++ } ++ ++} +Index: src/main/resources/payload.xsd +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/resources/payload.xsd (revision ) ++++ src/main/resources/payload.xsd (revision ) +@@ -0,0 +1,56 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision ) +@@ -0,0 +1,54 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlEnum; ++import javax.xml.bind.annotation.XmlEnumValue; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for flagType. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ *

++ *

++ * <simpleType name="flagType">
++ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
++ *     <enumeration value="active"/>
++ *     <enumeration value="deleted"/>
++ *     <enumeration value="superuser"/>
++ *   </restriction>
++ * </simpleType>
++ * 
++ * ++ */ ++@XmlType(name = "flagType", namespace = "http://javaops.ru") ++@XmlEnum ++public enum FlagType { ++ ++ @XmlEnumValue("active") ++ ACTIVE("active"), ++ @XmlEnumValue("deleted") ++ DELETED("deleted"), ++ @XmlEnumValue("superuser") ++ SUPERUSER("superuser"); ++ private final String value; ++ ++ FlagType(String v) { ++ value = v; ++ } ++ ++ public String value() { ++ return value; ++ } ++ ++ public static FlagType fromValue(String v) { ++ for (FlagType c: FlagType.values()) { ++ if (c.value.equals(v)) { ++ return c; ++ } ++ } ++ throw new IllegalArgumentException(v); ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision ) +@@ -0,0 +1,85 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.JAXBElement; ++import javax.xml.bind.annotation.XmlElementDecl; ++import javax.xml.bind.annotation.XmlRegistry; ++import javax.xml.namespace.QName; ++ ++ ++/** ++ * This object contains factory methods for each ++ * Java content interface and Java element interface ++ * generated in the ru.javaops.masterjava.xml.schema package. ++ *

An ObjectFactory allows you to programatically ++ * construct new instances of the Java representation ++ * for XML content. The Java representation of XML ++ * content can consist of schema derived interfaces ++ * and classes representing the binding of schema ++ * type definitions, element declarations and model ++ * groups. Factory methods for each of these are ++ * provided in this class. ++ * ++ */ ++@XmlRegistry ++public class ObjectFactory { ++ ++ private final static QName _City_QNAME = new QName("http://javaops.ru", "City"); ++ ++ /** ++ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ru.javaops.masterjava.xml.schema ++ * ++ */ ++ public ObjectFactory() { ++ } ++ ++ /** ++ * Create an instance of {@link Payload } ++ * ++ */ ++ public Payload createPayload() { ++ return new Payload(); ++ } ++ ++ /** ++ * Create an instance of {@link User } ++ * ++ */ ++ public User createUser() { ++ return new User(); ++ } ++ ++ /** ++ * Create an instance of {@link Payload.Cities } ++ * ++ */ ++ public Payload.Cities createPayloadCities() { ++ return new Payload.Cities(); ++ } ++ ++ /** ++ * Create an instance of {@link Payload.Users } ++ * ++ */ ++ public Payload.Users createPayloadUsers() { ++ return new Payload.Users(); ++ } ++ ++ /** ++ * Create an instance of {@link CityType } ++ * ++ */ ++ public CityType createCityType() { ++ return new CityType(); ++ } ++ ++ /** ++ * Create an instance of {@link JAXBElement }{@code <}{@link CityType }{@code >}} ++ * ++ */ ++ @XmlElementDecl(namespace = "http://javaops.ru", name = "City") ++ public JAXBElement createCity(CityType value) { ++ return new JAXBElement(_City_QNAME, CityType.class, null, value); ++ } ++ ++} diff --git a/patches/lesson02/2_07_JAXB.patch b/patches/lesson02/2_07_JAXB.patch new file mode 100644 index 000000000..f319308e8 --- /dev/null +++ b/patches/lesson02/2_07_JAXB.patch @@ -0,0 +1,358 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision ) +@@ -0,0 +1,89 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import org.xml.sax.SAXException; ++ ++import javax.xml.bind.JAXBContext; ++import javax.xml.bind.JAXBException; ++import javax.xml.bind.PropertyException; ++import javax.xml.transform.stream.StreamSource; ++import javax.xml.validation.Schema; ++import java.io.*; ++ ++ ++/** ++ * Marshalling/Unmarshalling JAXB helper ++ * XML Facade ++ * @author Grigory Kislin ++ */ ++public class JaxbParser { ++ ++ protected JaxbMarshaller jaxbMarshaller; ++ protected JaxbUnmarshaller jaxbUnmarshaller; ++ protected Schema schema; ++ ++ public JaxbParser(Class... classesToBeBound) { ++ try { ++ init(JAXBContext.newInstance(classesToBeBound)); ++ } catch (JAXBException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ // http://stackoverflow.com/questions/30643802/what-is-jaxbcontext-newinstancestring-contextpath ++ public JaxbParser(String context) { ++ try { ++ init(JAXBContext.newInstance(context)); ++ } catch (JAXBException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ private void init(JAXBContext ctx) throws JAXBException { ++ jaxbMarshaller = new JaxbMarshaller(ctx); ++ jaxbUnmarshaller = new JaxbUnmarshaller(ctx); ++ } ++ ++ // Unmarshaller ++ public T unmarshal(InputStream is) throws JAXBException { ++ return (T) jaxbUnmarshaller.unmarshal(is); ++ } ++ ++ public T unmarshal(Reader reader) throws JAXBException { ++ return (T) jaxbUnmarshaller.unmarshal(reader); ++ } ++ ++ public T unmarshal(String str) throws JAXBException { ++ return (T) jaxbUnmarshaller.unmarshal(str); ++ } ++ ++ // Marshaller ++ public void setMarshallerProperty(String prop, Object value) { ++ try { ++ jaxbMarshaller.setProperty(prop, value); ++ } catch (PropertyException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ public synchronized String marshal(Object instance) throws JAXBException { ++ return jaxbMarshaller.marshal(instance); ++ } ++ ++ public void marshal(Object instance, Writer writer) throws JAXBException { ++ jaxbMarshaller.marshal(instance, writer); ++ } ++ ++ public void setSchema(Schema schema) { ++ this.schema = schema; ++ jaxbUnmarshaller.setSchema(schema); ++ jaxbMarshaller.setSchema(schema); ++ } ++ ++ public void validate(String str) throws IOException, SAXException { ++ validate(new StringReader(str)); ++ } ++ ++ public void validate(Reader reader) throws IOException, SAXException { ++ schema.newValidator().validate(new StreamSource(reader)); ++ } ++} +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision ) +@@ -0,0 +1,37 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import javax.xml.bind.JAXBContext; ++import javax.xml.bind.JAXBException; ++import javax.xml.bind.Unmarshaller; ++import javax.xml.validation.Schema; ++import java.io.InputStream; ++import java.io.Reader; ++import java.io.StringReader; ++ ++/** ++ * @author GKislin ++ * Date: 18.11.2008 ++ */ ++public class JaxbUnmarshaller { ++ private Unmarshaller unmarshaller; ++ ++ public JaxbUnmarshaller(JAXBContext ctx) throws JAXBException { ++ unmarshaller = ctx.createUnmarshaller(); ++ } ++ ++ public synchronized void setSchema(Schema schema) { ++ unmarshaller.setSchema(schema); ++ } ++ ++ public synchronized Object unmarshal(InputStream is) throws JAXBException { ++ return unmarshaller.unmarshal(is); ++ } ++ ++ public synchronized Object unmarshal(Reader reader) throws JAXBException { ++ return unmarshaller.unmarshal(reader); ++ } ++ ++ public Object unmarshal(String str) throws JAXBException { ++ return unmarshal(new StringReader(str)); ++ } ++} +Index: src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision ) ++++ src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision ) +@@ -0,0 +1,44 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import com.google.common.io.Resources; ++import org.junit.Test; ++import ru.javaops.masterjava.xml.schema.CityType; ++import ru.javaops.masterjava.xml.schema.ObjectFactory; ++import ru.javaops.masterjava.xml.schema.Payload; ++ ++import javax.xml.bind.JAXBElement; ++import javax.xml.namespace.QName; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class JaxbParserTest { ++ private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class); ++ ++ static { ++ JAXB_PARSER.setSchema(Schemas.ofClasspath("payload.xsd")); ++ } ++ ++ @Test ++ public void testPayload() throws Exception { ++// JaxbParserTest.class.getResourceAsStream("/city.xml") ++ Payload payload = JAXB_PARSER.unmarshal( ++ Resources.getResource("payload.xml").openStream()); ++ String strPayload = JAXB_PARSER.marshal(payload); ++ JAXB_PARSER.validate(strPayload); ++ System.out.println(strPayload); ++ } ++ ++ @Test ++ public void testCity() throws Exception { ++ JAXBElement cityElement = JAXB_PARSER.unmarshal( ++ Resources.getResource("city.xml").openStream()); ++ CityType city = cityElement.getValue(); ++ JAXBElement cityElement2 = ++ new JAXBElement<>(new QName("http://javaops.ru", "City"), CityType.class, city); ++ String strCity = JAXB_PARSER.marshal(cityElement2); ++ JAXB_PARSER.validate(strCity); ++ System.out.println(strCity); ++ } ++} +\ No newline at end of file +Index: src/test/resources/city.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/resources/city.xml (revision ) ++++ src/test/resources/city.xml (revision ) +@@ -0,0 +1,4 @@ ++Санкт-Петербург ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/util/Schemas.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision ) +@@ -0,0 +1,51 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import com.google.common.io.Resources; ++import org.xml.sax.SAXException; ++ ++import javax.xml.XMLConstants; ++import javax.xml.transform.stream.StreamSource; ++import javax.xml.validation.Schema; ++import javax.xml.validation.SchemaFactory; ++import java.io.File; ++import java.io.StringReader; ++import java.net.URL; ++ ++ ++/** ++ * @author Grigory Kislin ++ */ ++public class Schemas { ++ ++ // SchemaFactory is not thread-safe ++ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); ++ ++ public static synchronized Schema ofString(String xsd) { ++ try { ++ return SCHEMA_FACTORY.newSchema(new StreamSource(new StringReader(xsd))); ++ } catch (SAXException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ public static synchronized Schema ofClasspath(String resource) { ++ // http://digitalsanctum.com/2012/11/30/how-to-read-file-contents-in-java-the-easy-way-with-guava/ ++ return ofURL(Resources.getResource(resource)); ++ } ++ ++ public static synchronized Schema ofURL(URL url) { ++ try { ++ return SCHEMA_FACTORY.newSchema(url); ++ } catch (SAXException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ public static synchronized Schema ofFile(File file) { ++ try { ++ return SCHEMA_FACTORY.newSchema(file); ++ } catch (SAXException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++} +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision ) +@@ -0,0 +1,43 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import javax.xml.bind.JAXBContext; ++import javax.xml.bind.JAXBException; ++import javax.xml.bind.Marshaller; ++import javax.xml.bind.PropertyException; ++import javax.xml.validation.Schema; ++import java.io.StringWriter; ++import java.io.Writer; ++ ++/** ++ * @author GKislin ++ * Date: 18.11.2008 ++ */ ++public class JaxbMarshaller { ++ private Marshaller marshaller; ++ ++ public JaxbMarshaller(JAXBContext ctx) throws JAXBException { ++ marshaller = ctx.createMarshaller(); ++ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); ++ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); ++ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); ++ } ++ ++ public void setProperty(String prop, Object value) throws PropertyException { ++ marshaller.setProperty(prop, value); ++ } ++ ++ public synchronized void setSchema(Schema schema) { ++ marshaller.setSchema(schema); ++ } ++ ++ public String marshal(Object instance) throws JAXBException { ++ StringWriter sw = new StringWriter(); ++ marshal(instance, sw); ++ return sw.toString(); ++ } ++ ++ public synchronized void marshal(Object instance, Writer writer) throws JAXBException { ++ marshaller.marshal(instance, writer); ++ } ++ ++} +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1488837115000) ++++ pom.xml (revision ) +@@ -32,6 +32,14 @@ + + + org.apache.maven.plugins ++ maven-surefire-plugin ++ 2.19.1 ++ ++ -Dfile.encoding=UTF-8 ++ ++ ++ ++ org.apache.maven.plugins + maven-shade-plugin + 2.2 + +@@ -79,6 +87,17 @@ + jmh-generator-annprocess + RELEASE + provided ++ ++ ++ com.google.guava ++ guava ++ 21.0 ++ ++ ++ junit ++ junit ++ 4.12 ++ test + + + diff --git a/patches/lesson02/2_08_StAX.patch b/patches/lesson02/2_08_StAX.patch new file mode 100644 index 000000000..30167fae5 --- /dev/null +++ b/patches/lesson02/2_08_StAX.patch @@ -0,0 +1,117 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision ) +@@ -0,0 +1,60 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import javax.xml.stream.XMLInputFactory; ++import javax.xml.stream.XMLStreamException; ++import javax.xml.stream.XMLStreamReader; ++import javax.xml.stream.events.XMLEvent; ++import java.io.InputStream; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class StaxStreamProcessor implements AutoCloseable { ++ private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); ++ ++ private final XMLStreamReader reader; ++ ++ public StaxStreamProcessor(InputStream is) throws XMLStreamException { ++ reader = FACTORY.createXMLStreamReader(is); ++ } ++ ++ public XMLStreamReader getReader() { ++ return reader; ++ } ++ ++ public boolean doUntil(int stopEvent, String value) throws XMLStreamException { ++ while (reader.hasNext()) { ++ int event = reader.next(); ++ if (event == stopEvent) { ++ if (value.equals(getValue(event))) { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ public String getValue(int event) throws XMLStreamException { ++ return (event == XMLEvent.CHARACTERS) ? reader.getText() : reader.getLocalName(); ++ } ++ ++ public String getElementValue(String element) throws XMLStreamException { ++ return doUntil(XMLEvent.START_ELEMENT, element) ? reader.getElementText() : null; ++ } ++ ++ public String getText() throws XMLStreamException { ++ return reader.getElementText(); ++ } ++ ++ @Override ++ public void close() { ++ if (reader != null) { ++ try { ++ reader.close(); ++ } catch (XMLStreamException e) { ++ // empty ++ } ++ } ++ } ++} +Index: src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision ) ++++ src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision ) +@@ -0,0 +1,40 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import com.google.common.io.Resources; ++import org.junit.Test; ++ ++import javax.xml.stream.XMLStreamReader; ++import javax.xml.stream.events.XMLEvent; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class StaxStreamProcessorTest { ++ @Test ++ public void readCities() throws Exception { ++ try (StaxStreamProcessor processor = ++ new StaxStreamProcessor(Resources.getResource("payload.xml").openStream())) { ++ XMLStreamReader reader = processor.getReader(); ++ while (reader.hasNext()) { ++ int event = reader.next(); ++ if (event == XMLEvent.START_ELEMENT) { ++ if ("City".equals(reader.getLocalName())) { ++ System.out.println(reader.getElementText()); ++ } ++ } ++ } ++ } ++ } ++ ++ @Test ++ public void readCities2() throws Exception { ++ try (StaxStreamProcessor processor = ++ new StaxStreamProcessor(Resources.getResource("payload.xml").openStream())) { ++ String city; ++ while ((city = processor.getElementValue("City")) != null) { ++ System.out.println(city); ++ } ++ } ++ } ++} +\ No newline at end of file diff --git a/patches/lesson02/2_09_XPath.patch b/patches/lesson02/2_09_XPath.patch new file mode 100644 index 000000000..4745b852f --- /dev/null +++ b/patches/lesson02/2_09_XPath.patch @@ -0,0 +1,109 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision ) +@@ -0,0 +1,62 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import org.w3c.dom.Document; ++import org.xml.sax.SAXException; ++ ++import javax.xml.namespace.QName; ++import javax.xml.parsers.DocumentBuilder; ++import javax.xml.parsers.DocumentBuilderFactory; ++import javax.xml.parsers.ParserConfigurationException; ++import javax.xml.xpath.XPath; ++import javax.xml.xpath.XPathExpression; ++import javax.xml.xpath.XPathExpressionException; ++import javax.xml.xpath.XPathFactory; ++import java.io.IOException; ++import java.io.InputStream; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class XPathProcessor { ++ private static final DocumentBuilderFactory DOCUMENT_FACTORY = DocumentBuilderFactory.newInstance(); ++ private static final DocumentBuilder DOCUMENT_BUILDER; ++ ++ private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance(); ++ private static final XPath XPATH = XPATH_FACTORY.newXPath(); ++ ++ static { ++ DOCUMENT_FACTORY.setNamespaceAware(true); ++ try { ++ DOCUMENT_BUILDER = DOCUMENT_FACTORY.newDocumentBuilder(); ++ } catch (ParserConfigurationException e) { ++ throw new IllegalStateException(e); ++ } ++ } ++ ++ private final Document doc; ++ ++ public XPathProcessor(InputStream is) { ++ try { ++ doc = DOCUMENT_BUILDER.parse(is); ++ } catch (SAXException | IOException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ public static synchronized XPathExpression getExpression(String exp) { ++ try { ++ return XPATH.compile(exp); ++ } catch (XPathExpressionException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++ ++ public T evaluate(XPathExpression expression, QName type) { ++ try { ++ return (T) expression.evaluate(doc, type); ++ } catch (XPathExpressionException e) { ++ throw new IllegalArgumentException(e); ++ } ++ } ++} +Index: src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision ) ++++ src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision ) +@@ -0,0 +1,30 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import com.google.common.io.Resources; ++import org.junit.Test; ++import org.w3c.dom.NodeList; ++ ++import javax.xml.xpath.XPathConstants; ++import javax.xml.xpath.XPathExpression; ++import java.io.InputStream; ++import java.util.stream.IntStream; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class XPathProcessorTest { ++ @Test ++ public void getCities() throws Exception { ++ try (InputStream is = ++ Resources.getResource("payload.xml").openStream()) { ++ XPathProcessor processor = new XPathProcessor(is); ++ XPathExpression expression = ++ XPathProcessor.getExpression("/*[name()='Payload']/*[name()='Cities']/*[name()='City']/text()"); ++ NodeList nodes = processor.evaluate(expression, XPathConstants.NODESET); ++ IntStream.range(0, nodes.getLength()).forEach( ++ i -> System.out.println(nodes.item(i).getNodeValue()) ++ ); ++ } ++ } ++} +\ No newline at end of file diff --git a/patches/lesson02/2_10_Xslt.patch b/patches/lesson02/2_10_Xslt.patch new file mode 100644 index 000000000..bf72e67b2 --- /dev/null +++ b/patches/lesson02/2_10_Xslt.patch @@ -0,0 +1,104 @@ +Index: src/main/resources/cities.xsl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/resources/cities.xsl (revision 78baa61bd953eda6b18fb8d08f54646375549d66) ++++ src/main/resources/cities.xsl (revision 78baa61bd953eda6b18fb8d08f54646375549d66) +@@ -0,0 +1,9 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66) ++++ src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66) +@@ -0,0 +1,48 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import javax.xml.transform.*; ++import javax.xml.transform.stream.StreamResult; ++import javax.xml.transform.stream.StreamSource; ++import java.io.*; ++import java.nio.charset.StandardCharsets; ++ ++/** ++ * User: GKislin ++ * Date: 18.05.2009 ++ */ ++ ++public class XsltProcessor { ++ private static TransformerFactory FACTORY = TransformerFactory.newInstance(); ++ private final Transformer xformer; ++ ++ public XsltProcessor(InputStream xslInputStream) { ++ this(new BufferedReader(new InputStreamReader(xslInputStream, StandardCharsets.UTF_8))); ++ } ++ ++ public XsltProcessor(Reader xslReader) { ++ try { ++ Templates template = FACTORY.newTemplates(new StreamSource(xslReader)); ++ xformer = template.newTransformer(); ++ } catch (TransformerConfigurationException e) { ++ throw new IllegalStateException("XSLT transformer creation failed: " + e.toString(), e); ++ } ++ } ++ ++ public String transform(InputStream xmlInputStream) throws TransformerException { ++ StringWriter out = new StringWriter(); ++ transform(xmlInputStream, out); ++ return out.getBuffer().toString(); ++ } ++ ++ public void transform(InputStream xmlInputStream, Writer result) throws TransformerException { ++ transform(new BufferedReader(new InputStreamReader(xmlInputStream, StandardCharsets.UTF_8)), result); ++ } ++ ++ public void transform(Reader sourceReader, Writer result) throws TransformerException { ++ xformer.transform(new StreamSource(sourceReader), new StreamResult(result)); ++ } ++ ++ public static String getXsltHeader(String xslt) { ++ return "\n"; ++ } ++} +Index: src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66) ++++ src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66) +@@ -0,0 +1,22 @@ ++package ru.javaops.masterjava.xml.util; ++ ++import com.google.common.io.Resources; ++import org.junit.Test; ++ ++import java.io.InputStream; ++ ++/** ++ * gkislin ++ * 23.09.2016 ++ */ ++public class XsltProcessorTest { ++ @Test ++ public void transform() throws Exception { ++ try (InputStream xslInputStream = Resources.getResource("cities.xsl").openStream(); ++ InputStream xmlInputStream = Resources.getResource("payload.xml").openStream()) { ++ ++ XsltProcessor processor = new XsltProcessor(xslInputStream); ++ System.out.println(processor.transform(xmlInputStream)); ++ } ++ } ++} diff --git a/patches/lesson03/3_1_HW2_schema.patch b/patches/lesson03/3_1_HW2_schema.patch new file mode 100644 index 000000000..7b0bf03a5 --- /dev/null +++ b/patches/lesson03/3_1_HW2_schema.patch @@ -0,0 +1,782 @@ +Index: src/main/resources/payload.xsd +=================================================================== +--- src/main/resources/payload.xsd (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1) ++++ src/main/resources/payload.xsd (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -6,7 +6,14 @@ + + + +- ++ ++ ++ ++ ++ ++ ++ ++ + + + +@@ -21,18 +28,39 @@ + + + +- ++ + + + +- ++ + + +- +- ++ ++ ++ ++ ++ ++ ++ ++ ++ + +- +- ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +@@ -44,7 +72,13 @@ + + + +- ++ ++ ++ ++ ++ ++ ++ + + + +@@ -53,4 +87,11 @@ + + + ++ ++ ++ ++ ++ ++ ++ + +\ No newline at end of file +Index: src/test/resources/payload.xml +=================================================================== +--- src/test/resources/payload.xml (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1) ++++ src/test/resources/payload.xml (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -1,23 +1,31 @@ + +- +- +- gmail@gmail.com +- Full Name +- +- +- admin@javaops.ru +- Admin +- +- +- mail@yandex.ru +- Deleted +- +- ++ ++ ++ ++ Topjava ++ ++ ++ ++ ++ ++ Masterjava ++ ++ ++ + + Санкт-Петербург ++ Москва + Киев + Минск + ++ ++ Full Name ++ Admin ++ Deleted ++ User1 ++ User2 ++ User3 ++ + +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1) ++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -1,14 +1,16 @@ + + package ru.javaops.masterjava.xml.schema; + ++import java.util.ArrayList; ++import java.util.List; + import javax.xml.bind.annotation.XmlAccessType; + import javax.xml.bind.annotation.XmlAccessorType; + import javax.xml.bind.annotation.XmlAttribute; +-import javax.xml.bind.annotation.XmlElement; + import javax.xml.bind.annotation.XmlIDREF; + import javax.xml.bind.annotation.XmlRootElement; + import javax.xml.bind.annotation.XmlSchemaType; + import javax.xml.bind.annotation.XmlType; ++import javax.xml.bind.annotation.XmlValue; + + + /** +@@ -18,16 +20,14 @@ + * + *

+  * <complexType>
+- *   <complexContent>
+- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+- *       <sequence>
+- *         <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
+- *         <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+- *       </sequence>
++ *   <simpleContent>
++ *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
++ *       <attribute name="email" type="{http://javaops.ru}emailAddressType" />
+  *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+  *       <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
+- *     </restriction>
+- *   </complexContent>
++ *       <attribute name="groupRefs" type="{http://www.w3.org/2001/XMLSchema}IDREFS" />
++ *     </extension>
++ *   </simpleContent>
+  * </complexType>
+  * 
+ * +@@ -35,69 +35,72 @@ + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { +- "email", +- "fullName" ++ "value" + }) + @XmlRootElement(name = "User", namespace = "http://javaops.ru") + public class User { + +- @XmlElement(namespace = "http://javaops.ru", required = true) ++ @XmlValue ++ protected String value; ++ @XmlAttribute(name = "email") + protected String email; +- @XmlElement(namespace = "http://javaops.ru", required = true) +- protected String fullName; + @XmlAttribute(name = "flag", required = true) + protected FlagType flag; + @XmlAttribute(name = "city", required = true) + @XmlIDREF + @XmlSchemaType(name = "IDREF") + protected Object city; ++ @XmlAttribute(name = "groupRefs") ++ @XmlIDREF ++ @XmlSchemaType(name = "IDREFS") ++ protected List groupRefs; + + /** +- * Gets the value of the email property. ++ * Gets the value of the value property. + * + * @return + * possible object is + * {@link String } + * + */ +- public String getEmail() { +- return email; ++ public String getValue() { ++ return value; + } + + /** +- * Sets the value of the email property. ++ * Sets the value of the value property. + * + * @param value + * allowed object is + * {@link String } + * + */ +- public void setEmail(String value) { +- this.email = value; ++ public void setValue(String value) { ++ this.value = value; + } + + /** +- * Gets the value of the fullName property. ++ * Gets the value of the email property. + * + * @return + * possible object is + * {@link String } + * + */ +- public String getFullName() { +- return fullName; ++ public String getEmail() { ++ return email; + } + + /** +- * Sets the value of the fullName property. ++ * Sets the value of the email property. + * + * @param value + * allowed object is + * {@link String } + * + */ +- public void setFullName(String value) { +- this.fullName = value; ++ public void setEmail(String value) { ++ this.email = value; + } + + /** +@@ -148,4 +151,33 @@ + this.city = value; + } + ++ /** ++ * Gets the value of the groupRefs property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the groupRefs property. ++ * ++ *

++ * For example, to add a new item, do as follows: ++ *

++     *    getGroupRefs().add(newItem);
++     * 
++ * ++ * ++ *

++ * Objects of the following type(s) are allowed in the list ++ * {@link Object } ++ * ++ * ++ */ ++ public List getGroupRefs() { ++ if (groupRefs == null) { ++ groupRefs = new ArrayList(); ++ } ++ return this.groupRefs; ++ } ++ + } +Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1) ++++ src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -19,7 +19,18 @@ + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> +- * <all> ++ * <sequence> ++ * <element name="Projects"> ++ * <complexType> ++ * <complexContent> ++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> ++ * <sequence maxOccurs="unbounded"> ++ * <element ref="{http://javaops.ru}Project"/> ++ * </sequence> ++ * </restriction> ++ * </complexContent> ++ * </complexType> ++ * </element> + * <element name="Cities"> + * <complexType> + * <complexContent> +@@ -42,7 +53,7 @@ + * </complexContent> + * </complexType> + * </element> +- * </all> ++ * </sequence> + * </restriction> + * </complexContent> + * </complexType> +@@ -52,16 +63,44 @@ + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { +- ++ "projects", ++ "cities", ++ "users" + }) + @XmlRootElement(name = "Payload", namespace = "http://javaops.ru") + public class Payload { + ++ @XmlElement(name = "Projects", namespace = "http://javaops.ru", required = true) ++ protected Payload.Projects projects; + @XmlElement(name = "Cities", namespace = "http://javaops.ru", required = true) + protected Payload.Cities cities; + @XmlElement(name = "Users", namespace = "http://javaops.ru", required = true) + protected Payload.Users users; + ++ /** ++ * Gets the value of the projects property. ++ * ++ * @return ++ * possible object is ++ * {@link Payload.Projects } ++ * ++ */ ++ public Payload.Projects getProjects() { ++ return projects; ++ } ++ ++ /** ++ * Sets the value of the projects property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Payload.Projects } ++ * ++ */ ++ public void setProjects(Payload.Projects value) { ++ this.projects = value; ++ } ++ + /** + * Gets the value of the cities property. + * +@@ -171,6 +210,66 @@ + } + + ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <sequence maxOccurs="unbounded">
++     *         <element ref="{http://javaops.ru}Project"/>
++     *       </sequence>
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "", propOrder = { ++ "project" ++ }) ++ public static class Projects { ++ ++ @XmlElement(name = "Project", namespace = "http://javaops.ru", required = true) ++ protected List project; ++ ++ /** ++ * Gets the value of the project property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the project property. ++ * ++ *

++ * For example, to add a new item, do as follows: ++ *

++         *    getProject().add(newItem);
++         * 
++ * ++ * ++ *

++ * Objects of the following type(s) are allowed in the list ++ * {@link Project } ++ * ++ * ++ */ ++ public List getProject() { ++ if (project == null) { ++ project = new ArrayList(); ++ } ++ return this.project; ++ } ++ ++ } ++ ++ + /** + *

Java class for anonymous complex type. + * +Index: src/main/java/ru/javaops/masterjava/xml/schema/Project.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) ++++ src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -0,0 +1,223 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import java.util.ArrayList; ++import java.util.List; ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlElement; ++import javax.xml.bind.annotation.XmlID; ++import javax.xml.bind.annotation.XmlRootElement; ++import javax.xml.bind.annotation.XmlSchemaType; ++import javax.xml.bind.annotation.XmlType; ++import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; ++import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; ++ ++ ++/** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++ * <complexType>
++ *   <complexContent>
++ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *       <sequence>
++ *         <element name="description" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ *         <sequence maxOccurs="unbounded">
++ *           <element name="Group">
++ *             <complexType>
++ *               <complexContent>
++ *                 <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *                   <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++ *                   <attribute name="type" use="required" type="{http://javaops.ru}groupType" />
++ *                 </restriction>
++ *               </complexContent>
++ *             </complexType>
++ *           </element>
++ *         </sequence>
++ *       </sequence>
++ *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
++ *     </restriction>
++ *   </complexContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "", propOrder = { ++ "description", ++ "group" ++}) ++@XmlRootElement(name = "Project", namespace = "http://javaops.ru") ++public class Project { ++ ++ @XmlElement(namespace = "http://javaops.ru", required = true) ++ protected String description; ++ @XmlElement(name = "Group", namespace = "http://javaops.ru", required = true) ++ protected List group; ++ @XmlAttribute(name = "name", required = true) ++ protected String name; ++ ++ /** ++ * Gets the value of the description property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getDescription() { ++ return description; ++ } ++ ++ /** ++ * Sets the value of the description property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setDescription(String value) { ++ this.description = value; ++ } ++ ++ /** ++ * Gets the value of the group property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the group property. ++ * ++ *

++ * For example, to add a new item, do as follows: ++ *

++     *    getGroup().add(newItem);
++     * 
++ * ++ * ++ *

++ * Objects of the following type(s) are allowed in the list ++ * {@link Project.Group } ++ * ++ * ++ */ ++ public List getGroup() { ++ if (group == null) { ++ group = new ArrayList(); ++ } ++ return this.group; ++ } ++ ++ /** ++ * Gets the value of the name property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getName() { ++ return name; ++ } ++ ++ /** ++ * Sets the value of the name property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setName(String value) { ++ this.name = value; ++ } ++ ++ ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ * ++ *

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++     *       <attribute name="type" use="required" type="{http://javaops.ru}groupType" />
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "") ++ public static class Group { ++ ++ @XmlAttribute(name = "name", required = true) ++ @XmlJavaTypeAdapter(CollapsedStringAdapter.class) ++ @XmlID ++ @XmlSchemaType(name = "ID") ++ protected String name; ++ @XmlAttribute(name = "type", required = true) ++ protected GroupType type; ++ ++ /** ++ * Gets the value of the name property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getName() { ++ return name; ++ } ++ ++ /** ++ * Sets the value of the name property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setName(String value) { ++ this.name = value; ++ } ++ ++ /** ++ * Gets the value of the type property. ++ * ++ * @return ++ * possible object is ++ * {@link GroupType } ++ * ++ */ ++ public GroupType getType() { ++ return type; ++ } ++ ++ /** ++ * Sets the value of the type property. ++ * ++ * @param value ++ * allowed object is ++ * {@link GroupType } ++ * ++ */ ++ public void setType(GroupType value) { ++ this.type = value; ++ } ++ ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) ++++ src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -0,0 +1,40 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlEnum; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for groupType. ++ * ++ *

The following schema fragment specifies the expected content contained within this class. ++ *

++ *

++ * <simpleType name="groupType">
++ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
++ *     <enumeration value="REGISTERING"/>
++ *     <enumeration value="CURRENT"/>
++ *     <enumeration value="FINISHED"/>
++ *   </restriction>
++ * </simpleType>
++ * 
++ * ++ */ ++@XmlType(name = "groupType", namespace = "http://javaops.ru") ++@XmlEnum ++public enum GroupType { ++ ++ REGISTERING, ++ CURRENT, ++ FINISHED; ++ ++ public String value() { ++ return name(); ++ } ++ ++ public static GroupType fromValue(String v) { ++ return valueOf(v); ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1) ++++ src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e) +@@ -33,6 +33,14 @@ + public ObjectFactory() { + } + ++ /** ++ * Create an instance of {@link Project } ++ * ++ */ ++ public Project createProject() { ++ return new Project(); ++ } ++ + /** + * Create an instance of {@link Payload } + * +@@ -41,6 +49,14 @@ + return new Payload(); + } + ++ /** ++ * Create an instance of {@link Project.Group } ++ * ++ */ ++ public Project.Group createProjectGroup() { ++ return new Project.Group(); ++ } ++ + /** + * Create an instance of {@link User } + * +@@ -49,6 +65,14 @@ + return new User(); + } + ++ /** ++ * Create an instance of {@link Payload.Projects } ++ * ++ */ ++ public Payload.Projects createPayloadProjects() { ++ return new Payload.Projects(); ++ } ++ + /** + * Create an instance of {@link Payload.Cities } + * diff --git a/patches/lesson03/3_2_HW2_JAXB_HTML.patch b/patches/lesson03/3_2_HW2_JAXB_HTML.patch new file mode 100644 index 000000000..9f7279b70 --- /dev/null +++ b/patches/lesson03/3_2_HW2_JAXB_HTML.patch @@ -0,0 +1,179 @@ +Index: src/test/java/ru/javaops/masterjava/MainXml.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/MainXml.java (revision ) ++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision ) +@@ -0,0 +1,81 @@ ++package ru.javaops.masterjava; ++ ++import com.google.common.io.Resources; ++import j2html.tags.ContainerTag; ++import one.util.streamex.StreamEx; ++import ru.javaops.masterjava.xml.schema.ObjectFactory; ++import ru.javaops.masterjava.xml.schema.Payload; ++import ru.javaops.masterjava.xml.schema.Project; ++import ru.javaops.masterjava.xml.schema.User; ++import ru.javaops.masterjava.xml.util.JaxbParser; ++import ru.javaops.masterjava.xml.util.Schemas; ++ ++import java.io.InputStream; ++import java.io.Writer; ++import java.net.URL; ++import java.nio.file.Files; ++import java.nio.file.Paths; ++import java.util.*; ++import java.util.stream.Collectors; ++ ++import static j2html.TagCreator.*; ++ ++ ++/** ++ * User: gkislin ++ */ ++public class MainXml { ++ private static final Comparator USER_COMPARATOR = Comparator.comparing(User::getValue).thenComparing(User::getEmail); ++ ++ public static void main(String[] args) throws Exception { ++ if (args.length != 1) { ++ System.out.println("Format: projectName"); ++ System.exit(1); ++ } ++ String projectName = args[0]; ++ URL payloadUrl = Resources.getResource("payload.xml"); ++ ++ Set users = parseByJaxb(projectName, payloadUrl); ++ users.forEach(System.out::println); ++ ++ String html = toHtml(users, projectName); ++ System.out.println(html); ++ try (Writer writer = Files.newBufferedWriter(Paths.get("out/users.html"))) { ++ writer.write(html); ++ } ++ } ++ ++ private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception { ++ JaxbParser parser = new JaxbParser(ObjectFactory.class); ++ parser.setSchema(Schemas.ofClasspath("payload.xsd")); ++ Payload payload; ++ try (InputStream is = payloadUrl.openStream()) { ++ payload = parser.unmarshal(is); ++ } ++ ++ Project project = StreamEx.of(payload.getProjects().getProject()) ++ .filter(p -> p.getName().equals(projectName)) ++ .findAny() ++ .orElseThrow(() -> new IllegalArgumentException("Invalid project name '" + projectName + '\'')); ++ ++ final Set groups = new HashSet<>(project.getGroup()); // identity compare ++ return StreamEx.of(payload.getUsers().getUser()) ++ .filter(u -> !Collections.disjoint(groups, u.getGroupRefs())) ++ .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR))); ++ } ++ ++ private static String toHtml(Set users, String projectName) { ++ final ContainerTag table = table().with( ++ tr().with(th("FullName"), th("email"))) ++ .attr("border", "1") ++ .attr("cellpadding", "8") ++ .attr("cellspacing", "0"); ++ ++ users.forEach(u -> table.with(tr().with(td(u.getValue()), td(u.getEmail())))); ++ ++ return html().with( ++ head().with(title(projectName + " users")), ++ body().with(h1(projectName + " users"), table) ++ ).render(); ++ } ++} +Index: out/placeholder +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- out/placeholder (revision ) ++++ out/placeholder (revision ) +@@ -0,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/Main.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/Main.java (date 1489369117000) ++++ src/main/java/ru/javaops/masterjava/Main.java (date 1489369117000) +@@ -1,14 +0,0 @@ +-package ru.javaops.masterjava; +- +-/** +- * User: gkislin +- * Date: 05.08.2015 +- * +- * @link http://caloriesmng.herokuapp.com/ +- * @link https://github.com/JavaOPs/topjava +- */ +-public class Main { +- public static void main(String[] args) { +- System.out.format("Hello MasterJava!"); +- } +-} +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1489369117000) ++++ pom.xml (revision ) +@@ -94,6 +94,19 @@ + 21.0 + + ++ one.util ++ streamex ++ RELEASE ++ ++ ++ ++ com.j2html ++ j2html ++ RELEASE ++ ++ ++ ++ + junit + junit + 4.12 +Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (date 1489369117000) ++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) +@@ -1,16 +1,9 @@ + + package ru.javaops.masterjava.xml.schema; + ++import javax.xml.bind.annotation.*; + import java.util.ArrayList; + import java.util.List; +-import javax.xml.bind.annotation.XmlAccessType; +-import javax.xml.bind.annotation.XmlAccessorType; +-import javax.xml.bind.annotation.XmlAttribute; +-import javax.xml.bind.annotation.XmlIDREF; +-import javax.xml.bind.annotation.XmlRootElement; +-import javax.xml.bind.annotation.XmlSchemaType; +-import javax.xml.bind.annotation.XmlType; +-import javax.xml.bind.annotation.XmlValue; + + + /** +@@ -180,4 +173,10 @@ + return this.groupRefs; + } + ++ @Override ++ public String toString() { ++ return value + '(' + email + ')'; ++ } ++ ++ + } diff --git a/patches/lesson03/3_3_HW2_StAX.patch b/patches/lesson03/3_3_HW2_StAX.patch new file mode 100644 index 000000000..1898adfe2 --- /dev/null +++ b/patches/lesson03/3_3_HW2_StAX.patch @@ -0,0 +1,127 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (date 1489431163000) ++++ src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision ) +@@ -24,15 +24,26 @@ + } + + public boolean doUntil(int stopEvent, String value) throws XMLStreamException { ++ return doUntilAny(stopEvent, value) != null; ++ } ++ ++ public String getAttribute(String name) throws XMLStreamException { ++ return reader.getAttributeValue(null, name); ++ } ++ ++ public String doUntilAny(int stopEvent, String... values) throws XMLStreamException { + while (reader.hasNext()) { + int event = reader.next(); + if (event == stopEvent) { +- if (value.equals(getValue(event))) { +- return true; ++ String xmlValue = getValue(event); ++ for (String value : values) { ++ if (value.equals(xmlValue)) { ++ return xmlValue; ++ } + } + } + } +- return false; ++ return null; + } + + public String getValue(int event) throws XMLStreamException { +Index: src/test/java/ru/javaops/masterjava/MainXml.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489431163000) ++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision ) +@@ -1,5 +1,6 @@ + package ru.javaops.masterjava; + ++import com.google.common.base.Splitter; + import com.google.common.io.Resources; + import j2html.tags.ContainerTag; + import one.util.streamex.StreamEx; +@@ -9,7 +10,9 @@ + import ru.javaops.masterjava.xml.schema.User; + import ru.javaops.masterjava.xml.util.JaxbParser; + import ru.javaops.masterjava.xml.util.Schemas; ++import ru.javaops.masterjava.xml.util.StaxStreamProcessor; + ++import javax.xml.stream.events.XMLEvent; + import java.io.InputStream; + import java.io.Writer; + import java.net.URL; +@@ -18,6 +21,7 @@ + import java.util.*; + import java.util.stream.Collectors; + ++import static com.google.common.base.Strings.nullToEmpty; + import static j2html.TagCreator.*; + + +@@ -43,6 +47,10 @@ + try (Writer writer = Files.newBufferedWriter(Paths.get("out/users.html"))) { + writer.write(html); + } ++ ++ System.out.println(); ++ users = processByStax(projectName, payloadUrl); ++ users.forEach(System.out::println); + } + + private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception { +@@ -64,6 +72,46 @@ + .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR))); + } + ++ private static Set processByStax(String projectName, URL payloadUrl) throws Exception { ++ ++ try (InputStream is = payloadUrl.openStream()) { ++ StaxStreamProcessor processor = new StaxStreamProcessor(is); ++ final Set groupNames = new HashSet<>(); ++ ++ // Projects loop ++ projects: ++ while (processor.doUntil(XMLEvent.START_ELEMENT, "Project")) { ++ if (projectName.equals(processor.getAttribute("name"))) { ++ // Groups loop ++ String element; ++ while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, "Project", "Group", "Users")) != null) { ++ if (!element.equals("Group")) { ++ break projects; ++ } ++ groupNames.add(processor.getAttribute("name")); ++ } ++ } ++ } ++ if (groupNames.isEmpty()) { ++ throw new IllegalArgumentException("Invalid " + projectName + " or no groups"); ++ } ++ ++ // Users loop ++ Set users = new TreeSet<>(USER_COMPARATOR); ++ ++ while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { ++ String groupRefs = processor.getAttribute("groupRefs"); ++ if (!Collections.disjoint(groupNames, Splitter.on(' ').splitToList(nullToEmpty(groupRefs)))) { ++ User user = new User(); ++ user.setEmail(processor.getAttribute("email")); ++ user.setValue(processor.getText()); ++ users.add(user); ++ } ++ } ++ return users; ++ } ++ } ++ + private static String toHtml(Set users, String projectName) { + final ContainerTag table = table().with( + tr().with(th("FullName"), th("email"))) diff --git a/patches/lesson03/3_4_HW2_xslt.patch b/patches/lesson03/3_4_HW2_xslt.patch new file mode 100644 index 000000000..19a0e9ce5 --- /dev/null +++ b/patches/lesson03/3_4_HW2_xslt.patch @@ -0,0 +1,102 @@ +Index: src/main/resources/groups.xsl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/resources/groups.xsl (revision ) ++++ src/main/resources/groups.xsl (revision ) +@@ -0,0 +1,36 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ <xsl:value-of select="$projectName"/> groups ++ ++ ++ ++

++ groups ++

++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
GroupType
++ ++ ++ ++
++ ++ ++
++
+\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (date 1489431506000) ++++ src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision ) +@@ -45,4 +45,8 @@ + public static String getXsltHeader(String xslt) { + return "\n"; + } ++ ++ public void setParameter(String name, String value) { ++ xformer.setParameter(name, value); ++ } + } +Index: src/test/java/ru/javaops/masterjava/MainXml.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489431506000) ++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision ) +@@ -11,6 +11,7 @@ + import ru.javaops.masterjava.xml.util.JaxbParser; + import ru.javaops.masterjava.xml.util.Schemas; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; ++import ru.javaops.masterjava.xml.util.XsltProcessor; + + import javax.xml.stream.events.XMLEvent; + import java.io.InputStream; +@@ -51,6 +52,11 @@ + System.out.println(); + users = processByStax(projectName, payloadUrl); + users.forEach(System.out::println); ++ ++ html = transform(projectName, payloadUrl); ++ try (Writer writer = Files.newBufferedWriter(Paths.get("out/groups.html"))) { ++ writer.write(html); ++ } + } + + private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception { +@@ -126,4 +132,13 @@ + body().with(h1(projectName + " users"), table) + ).render(); + } ++ ++ private static String transform(String projectName, URL payloadUrl) throws Exception { ++ URL xsl = Resources.getResource("groups.xsl"); ++ try (InputStream xmlStream = payloadUrl.openStream(); InputStream xslStream = xsl.openStream()) { ++ XsltProcessor processor = new XsltProcessor(xslStream); ++ processor.setParameter("projectName", projectName); ++ return processor.transform(xmlStream); ++ } ++ } + } diff --git a/patches/lesson03/3_5_multimodule.patch b/patches/lesson03/3_5_multimodule.patch new file mode 100644 index 000000000..c558ac2d8 --- /dev/null +++ b/patches/lesson03/3_5_multimodule.patch @@ -0,0 +1,294 @@ +Index: export/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- export/pom.xml (revision ) ++++ export/pom.xml (revision ) +@@ -0,0 +1,39 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ export ++ 1.0-SNAPSHOT ++ war ++ Export ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-war-plugin ++ 3.0.0 ++ ++ false ++ ++ ++ ++ ++ ++ ++ ++ ru.javaops ++ common ++ ${project.version} ++ ++ ++ +\ No newline at end of file +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (revision ) ++++ parent/pom.xml (revision ) +@@ -0,0 +1,69 @@ ++ ++ ++ 4.0.0 ++ ++ ru.javaops ++ parent ++ pom ++ 1.0-SNAPSHOT ++ Parent ++ ++ ++ 1.8 ++ UTF-8 ++ UTF-8 ++ ++ ++ ++ install ++ ++ ++ org.apache.maven.plugins ++ maven-compiler-plugin ++ 3.1 ++ ++ ${java.version} ++ ${java.version} ++ ++ ++ ++ org.apache.maven.plugins ++ maven-surefire-plugin ++ 2.19.1 ++ ++ -Dfile.encoding=UTF-8 ++ ++ ++ ++ ++ ++ ++ ++ com.google.guava ++ guava ++ 21.0 ++ ++ ++ one.util ++ streamex ++ RELEASE ++ ++ ++ ++ ++ junit ++ junit ++ 4.12 ++ test ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: common/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/pom.xml (revision ) ++++ common/pom.xml (revision ) +@@ -0,0 +1,21 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ common ++ 1.0-SNAPSHOT ++ jar ++ Common ++ ++ ++ ++ +\ No newline at end of file +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1489432214000) ++++ pom.xml (revision ) +@@ -4,119 +4,22 @@ + + ru.javaops + masterjava +- jar ++ pom + + 1.0-SNAPSHOT + + Master Java + https://github.com/JavaOPs/masterjava + +- +- 1.8 +- UTF-8 +- UTF-8 +- ++ ++ export ++ common + +- +- masterjava +- install +- +- +- org.apache.maven.plugins +- maven-compiler-plugin +- 3.1 +- +- ${java.version} +- ${java.version} +- +- +- +- org.apache.maven.plugins +- maven-surefire-plugin +- 2.19.1 +- +- -Dfile.encoding=UTF-8 +- +- +- +- org.apache.maven.plugins +- maven-shade-plugin +- 2.2 +- +- +- package +- +- shade +- +- +- benchmarks +- +- +- org.openjdk.jmh.Main +- +- +- +- +- +- *:* +- +- META-INF/*.SF +- META-INF/*.DSA +- META-INF/*.RSA +- +- +- +- +- +- +- +- +- +- +- +- +- org.openjdk.jmh +- jmh-core +- RELEASE +- +- +- org.openjdk.jmh +- jmh-generator-annprocess +- RELEASE +- provided +- +- +- com.google.guava +- guava +- 21.0 +- +- +- one.util +- streamex +- RELEASE +- +- +- +- com.j2html +- j2html +- RELEASE +- +- +- +- +- junit +- junit +- 4.12 +- test +- +- +- +- +- +- +- +- ++ ++ +
diff --git a/patches/lesson04/4_1_HW3_pom_structure.patch b/patches/lesson04/4_1_HW3_pom_structure.patch new file mode 100644 index 000000000..a48d1f546 --- /dev/null +++ b/patches/lesson04/4_1_HW3_pom_structure.patch @@ -0,0 +1,490 @@ +Index: services/mail-api/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/pom.xml (revision ) ++++ services/mail-api/pom.xml (revision ) +@@ -0,0 +1,26 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ mail-api ++ 1.0-SNAPSHOT ++ Mail API ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ ++ +\ No newline at end of file +Index: web/webapp/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/pom.xml (revision ) ++++ web/webapp/pom.xml (revision ) +@@ -0,0 +1,26 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent-web ++ ../../parent-web/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ webapp ++ 1.0-SNAPSHOT ++ war ++ WebApp ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ +\ No newline at end of file +Index: web/export/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/pom.xml (revision ) ++++ web/export/pom.xml (revision ) +@@ -0,0 +1,31 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent-web ++ ../../parent-web/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ export ++ 1.0-SNAPSHOT ++ war ++ Export ++ ++ ++ export ++ ++ ++ ++ ++ com.j2html ++ j2html ++ 0.7 ++ ++ ++ ++ +\ No newline at end of file +Index: web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/pom.xml (revision ) ++++ web/pom.xml (revision ) +@@ -0,0 +1,15 @@ ++ ++ 4.0.0 ++ ++ ru.javaops ++ web ++ pom ++ 1.0-SNAPSHOT ++ MasterJava Web ++ ++ ++ export ++ webapp ++ ++ +Index: services/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/pom.xml (revision ) ++++ services/pom.xml (revision ) +@@ -0,0 +1,15 @@ ++ ++ 4.0.0 ++ ++ ru.javaops ++ services ++ pom ++ 1.0-SNAPSHOT ++ ++ MasterJava Services ++ ++ mail-api ++ mail-service ++ ++ +Index: test/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- test/pom.xml (revision ) ++++ test/pom.xml (revision ) +@@ -0,0 +1,76 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ test ++ 1.0-SNAPSHOT ++ Test ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-shade-plugin ++ 2.2 ++ ++ ++ package ++ ++ shade ++ ++ ++ benchmarks ++ ++ ++ org.openjdk.jmh.Main ++ ++ ++ ++ ++ ++ *:* ++ ++ META-INF/*.SF ++ META-INF/*.DSA ++ META-INF/*.RSA ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ org.openjdk.jmh ++ jmh-core ++ RELEASE ++ ++ ++ org.openjdk.jmh ++ jmh-generator-annprocess ++ RELEASE ++ provided ++ ++ ++ +\ No newline at end of file +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (revision ) ++++ services/mail-service/pom.xml (revision ) +@@ -0,0 +1,26 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent-web ++ ../../parent-web/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ mail-service ++ 1.0-SNAPSHOT ++ war ++ Mail Service ++ ++ ++ ++ ${project.groupId} ++ mail-api ++ ${project.version} ++ ++ ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (date 1489440274000) ++++ test/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (date 1489440274000) ++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (date 1489440274000) ++++ test/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/resources/groups.xsl +=================================================================== +--- src/main/resources/groups.xsl (date 1489440274000) ++++ web/export/src/main/resources/groups.xsl (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (date 1489440274000) ++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/service/MailService.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/service/MailService.java (date 1489440274000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -1,4 +1,4 @@ +-package ru.javaops.masterjava.service; ++package ru.javaops.masterjava.service.mail; + + import java.util.ArrayList; + import java.util.List; +Index: src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/resources/cities.xsl +=================================================================== +--- src/main/resources/cities.xsl (date 1489440274000) ++++ web/export/src/main/resources/cities.xsl (revision ) +@@ -1,0 +1,0 @@ +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1489440274000) ++++ pom.xml (revision ) +@@ -8,18 +8,14 @@ + + 1.0-SNAPSHOT + +- Master Java ++ MasterJava Root + https://github.com/JavaOPs/masterjava + + +- export + common +- +- ++ ++ web ++ services + + +Index: src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1489440274000) ++++ test/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/Schemas.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/Project.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Project.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (date 1489440274000) ++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision ) +@@ -1,0 +1,0 @@ +Index: export/pom.xml +=================================================================== +--- export/pom.xml (date 1489440274000) ++++ parent-web/pom.xml (revision ) +@@ -11,10 +11,10 @@ + 1.0-SNAPSHOT + + +- export ++ parent-web ++ pom + 1.0-SNAPSHOT +- war +- Export ++ Parent Web + + + +@@ -31,9 +31,16 @@ + + + +- ru.javaops +- common +- ${project.version} ++ javax.servlet ++ javax.servlet-api ++ 3.1.0 ++ provided + + ++ ++ ++ ++ ++ ++ + +\ No newline at end of file +Index: src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java +=================================================================== +--- src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (date 1489440274000) ++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/resources/payload.xsd +=================================================================== +--- src/main/resources/payload.xsd (date 1489440274000) ++++ web/export/src/main/resources/payload.xsd (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/resources/city.xml +=================================================================== +--- src/test/resources/city.xml (date 1489440274000) ++++ web/export/src/test/resources/city.xml (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/resources/payload.xml +=================================================================== +--- src/test/resources/payload.xml (date 1489440274000) ++++ web/export/src/test/resources/payload.xml (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/test/java/ru/javaops/masterjava/MainXml.java +=================================================================== +--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489440274000) ++++ web/export/src/test/java/ru/javaops/masterjava/MainXml.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/CityType.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision ) +@@ -1,0 +1,0 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (date 1489440274000) ++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) +@@ -1,0 +1,0 @@ diff --git a/patches/lesson04/4_2_HW3_thymeleaf_upload.patch b/patches/lesson04/4_2_HW3_thymeleaf_upload.patch new file mode 100644 index 000000000..c42d4ff8b --- /dev/null +++ b/patches/lesson04/4_2_HW3_thymeleaf_upload.patch @@ -0,0 +1,428 @@ +Index: web/export/src/main/webapp/WEB-INF/templates/exception.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/exception.html (revision ) ++++ web/export/src/main/webapp/WEB-INF/templates/exception.html (revision ) +@@ -0,0 +1,19 @@ ++ ++ ++ ++ Export XML ++ ++ ++ ++
++
++
++

Application error:

++

exception.message

++
    ++
  • ++
++
++
++ ++ +\ No newline at end of file +Index: web/export/src/main/webapp/WEB-INF/templates/export.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/export.html (revision ) ++++ web/export/src/main/webapp/WEB-INF/templates/export.html (revision ) +@@ -0,0 +1,16 @@ ++ ++ ++ Export XML ++ ++ ++
++

Select xml file to upload

++

++
++

++

++ ++

++
++ ++ +\ No newline at end of file +Index: web/common-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/common-web/pom.xml (revision ) ++++ web/common-web/pom.xml (revision ) +@@ -0,0 +1,42 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ common-web ++ 1.0-SNAPSHOT ++ Common Web ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ commons-fileupload ++ commons-fileupload ++ 1.3.2 ++ ++ ++ javax.servlet ++ javax.servlet-api ++ 3.1.0 ++ provided ++ ++ ++ ++ org.thymeleaf ++ thymeleaf ++ 3.0.3.RELEASE ++ ++ ++ +\ No newline at end of file +Index: web/export/src/main/webapp/WEB-INF/templates/result.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/result.html (revision ) ++++ web/export/src/main/webapp/WEB-INF/templates/result.html (revision ) +@@ -0,0 +1,26 @@ ++ ++ ++ ++ Uploaded users ++ ++ ++

Export XML

++

Uploaded users

++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
Full NameEmailFlag
++ ++ +\ No newline at end of file +Index: web/export/src/main/java/ru/javaops/masterjava/model/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/model/User.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/model/User.java (revision ) +@@ -0,0 +1,63 @@ ++package ru.javaops.masterjava.model; ++ ++import java.util.Objects; ++ ++public class User { ++ private final Integer id; ++ private final String fullName; ++ private final String email; ++ private final UserFlag flag; ++ ++ public User(String fullName, String email, UserFlag flag) { ++ this(null, fullName, email, flag); ++ } ++ ++ public User(Integer id, String fullName, String email, UserFlag flag) { ++ this.id = id; ++ this.fullName = fullName; ++ this.email = email; ++ this.flag = flag; ++ } ++ ++ public Integer getId() { ++ return id; ++ } ++ ++ public String getFullName() { ++ return fullName; ++ } ++ ++ public String getEmail() { ++ return email; ++ } ++ ++ public UserFlag getFlag() { ++ return flag; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ User user = (User) o; ++ return Objects.equals(id, user.id) && ++ Objects.equals(fullName, user.fullName) && ++ Objects.equals(email, user.email) && ++ flag == user.flag; ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(id, fullName, email, flag); ++ } ++ ++ @Override ++ public String toString() { ++ return "User (" + ++ "id=" + id + ++ ", fullName='" + fullName + '\'' + ++ ", email='" + email + '\'' + ++ ", flag=" + flag + ++ ')'; ++ } ++} +Index: web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java (revision ) +@@ -0,0 +1,21 @@ ++package ru.javaops.masterjava.export; ++ ++import org.thymeleaf.TemplateEngine; ++import ru.javaops.masterjava.common.web.ThymeleafUtil; ++ ++import javax.servlet.ServletContextEvent; ++import javax.servlet.ServletContextListener; ++import javax.servlet.annotation.WebListener; ++ ++@WebListener ++public class ThymeleafListener implements ServletContextListener { ++ ++ public static TemplateEngine engine; ++ ++ public void contextInitialized(ServletContextEvent sce) { ++ engine = ThymeleafUtil.getTemplateEngine(sce.getServletContext()); ++ } ++ ++ public void contextDestroyed(ServletContextEvent sce) { ++ } ++} +Index: web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java (revision ) +@@ -0,0 +1,11 @@ ++package ru.javaops.masterjava.model; ++ ++/** ++ * gkislin ++ * 13.10.2016 ++ */ ++public enum UserFlag { ++ active, ++ deleted, ++ superuser; ++} +Index: web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java (revision ) ++++ web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java (revision ) +@@ -0,0 +1,24 @@ ++package ru.javaops.masterjava.common.web; ++ ++import org.thymeleaf.TemplateEngine; ++import org.thymeleaf.templatemode.TemplateMode; ++import org.thymeleaf.templateresolver.ServletContextTemplateResolver; ++ ++import javax.servlet.ServletContext; ++ ++public class ThymeleafUtil { ++ ++ private ThymeleafUtil() { ++ } ++ ++ public static TemplateEngine getTemplateEngine(ServletContext context) { ++ final ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(context); ++ templateResolver.setTemplateMode(TemplateMode.HTML); ++ templateResolver.setPrefix("/WEB-INF/templates/"); ++ templateResolver.setSuffix(".html"); ++ templateResolver.setCacheTTLMs(1000L); ++ final TemplateEngine engine = new TemplateEngine(); ++ engine.setTemplateResolver(templateResolver); ++ return engine; ++ } ++} +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -0,0 +1,56 @@ ++package ru.javaops.masterjava.export; ++ ++import org.apache.commons.fileupload.FileItemIterator; ++import org.apache.commons.fileupload.FileItemStream; ++import org.apache.commons.fileupload.servlet.ServletFileUpload; ++import org.thymeleaf.context.WebContext; ++import ru.javaops.masterjava.model.User; ++ ++import javax.servlet.ServletException; ++import javax.servlet.annotation.WebServlet; ++import javax.servlet.http.HttpServlet; ++import javax.servlet.http.HttpServletRequest; ++import javax.servlet.http.HttpServletResponse; ++import java.io.IOException; ++import java.io.InputStream; ++import java.util.List; ++ ++import static ru.javaops.masterjava.export.ThymeleafListener.engine; ++ ++@WebServlet("/") ++public class UploadServlet extends HttpServlet { ++ ++ private final UserExport userExport = new UserExport(); ++ ++ @Override ++ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ++ final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale()); ++ engine.process("export", webContext, resp.getWriter()); ++ } ++ ++ @Override ++ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ++ final ServletFileUpload upload = new ServletFileUpload(); ++ final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale()); ++ ++ try { ++// https://commons.apache.org/proper/commons-fileupload/streaming.html ++ ++ final FileItemIterator itemIterator = upload.getItemIterator(req); ++ while (itemIterator.hasNext()) { //expect that it's only one file ++ FileItemStream fileItemStream = itemIterator.next(); ++ if (!fileItemStream.isFormField()) { ++ try (InputStream is = fileItemStream.openStream()) { ++ List users = userExport.process(is); ++ webContext.setVariable("users", users); ++ engine.process("result", webContext, resp.getWriter()); ++ } ++ break; ++ } ++ } ++ } catch (Exception e) { ++ webContext.setVariable("exception", e); ++ engine.process("exception", webContext, resp.getWriter()); ++ } ++ } ++} +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -0,0 +1,32 @@ ++package ru.javaops.masterjava.export; ++ ++import ru.javaops.masterjava.model.User; ++import ru.javaops.masterjava.model.UserFlag; ++import ru.javaops.masterjava.xml.util.StaxStreamProcessor; ++ ++import javax.xml.stream.XMLStreamException; ++import javax.xml.stream.events.XMLEvent; ++import java.io.InputStream; ++import java.util.ArrayList; ++import java.util.List; ++ ++/** ++ * gkislin ++ * 14.10.2016 ++ */ ++public class UserExport { ++ ++ public List process(final InputStream is) throws XMLStreamException { ++ final StaxStreamProcessor processor = new StaxStreamProcessor(is); ++ List users = new ArrayList<>(); ++ ++ while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { ++ final String email = processor.getAttribute("email"); ++ final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); ++ final String fullName = processor.getReader().getElementText(); ++ final User user = new User(fullName, email, flag); ++ users.add(user); ++ } ++ return users; ++ } ++} +Index: parent-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent-web/pom.xml (date 1490039474000) ++++ parent-web/pom.xml (revision ) +@@ -31,6 +31,11 @@ + + + ++ ${project.groupId} ++ common-web ++ ${project.version} ++ ++ + javax.servlet + javax.servlet-api + 3.1.0 +Index: web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/pom.xml (date 1490039474000) ++++ web/pom.xml (revision ) +@@ -9,6 +9,7 @@ + MasterJava Web + + ++ common-web + export + webapp + diff --git a/patches/lesson04/4_3_HW3_upload_servlet3.patch b/patches/lesson04/4_3_HW3_upload_servlet3.patch new file mode 100644 index 000000000..f32945a97 --- /dev/null +++ b/patches/lesson04/4_3_HW3_upload_servlet3.patch @@ -0,0 +1,83 @@ +Index: web/common-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/common-web/pom.xml (date 1490050751000) ++++ web/common-web/pom.xml (revision ) +@@ -22,11 +22,6 @@ + ${project.version} + + +- commons-fileupload +- commons-fileupload +- 1.3.2 +- +- + javax.servlet + javax.servlet-api + 3.1.0 +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1490050751000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -1,16 +1,15 @@ + package ru.javaops.masterjava.export; + +-import org.apache.commons.fileupload.FileItemIterator; +-import org.apache.commons.fileupload.FileItemStream; +-import org.apache.commons.fileupload.servlet.ServletFileUpload; + import org.thymeleaf.context.WebContext; + import ru.javaops.masterjava.model.User; + + import javax.servlet.ServletException; ++import javax.servlet.annotation.MultipartConfig; + import javax.servlet.annotation.WebServlet; + import javax.servlet.http.HttpServlet; + import javax.servlet.http.HttpServletRequest; + import javax.servlet.http.HttpServletResponse; ++import javax.servlet.http.Part; + import java.io.IOException; + import java.io.InputStream; + import java.util.List; +@@ -18,6 +17,7 @@ + import static ru.javaops.masterjava.export.ThymeleafListener.engine; + + @WebServlet("/") ++@MultipartConfig + public class UploadServlet extends HttpServlet { + + private final UserExport userExport = new UserExport(); +@@ -30,23 +30,15 @@ + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { +- final ServletFileUpload upload = new ServletFileUpload(); + final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale()); + + try { +-// https://commons.apache.org/proper/commons-fileupload/streaming.html +- +- final FileItemIterator itemIterator = upload.getItemIterator(req); +- while (itemIterator.hasNext()) { //expect that it's only one file +- FileItemStream fileItemStream = itemIterator.next(); +- if (!fileItemStream.isFormField()) { +- try (InputStream is = fileItemStream.openStream()) { +- List users = userExport.process(is); +- webContext.setVariable("users", users); +- engine.process("result", webContext, resp.getWriter()); +- } +- break; +- } ++// http://docs.oracle.com/javaee/6/tutorial/doc/glraq.html ++ Part filePart = req.getPart("fileToUpload"); ++ try (InputStream is = filePart.getInputStream()) { ++ List users = userExport.process(is); ++ webContext.setVariable("users", users); ++ engine.process("result", webContext, resp.getWriter()); + } + } catch (Exception e) { + webContext.setVariable("exception", e); diff --git a/patches/lesson04/4_4_dependencies.patch b/patches/lesson04/4_4_dependencies.patch new file mode 100644 index 000000000..03cf7222c --- /dev/null +++ b/patches/lesson04/4_4_dependencies.patch @@ -0,0 +1,33 @@ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490101176000) ++++ parent/pom.xml (revision ) +@@ -14,6 +14,8 @@ + 1.8 + UTF-8 + UTF-8 ++ ++ false + + + +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1490101176000) ++++ pom.xml (revision ) +@@ -12,6 +12,9 @@ + https://github.com/JavaOPs/masterjava + + ++ parent ++ parent-web ++ + common + test + diff --git a/patches/lesson04/4_5_fix_convergence.patch b/patches/lesson04/4_5_fix_convergence.patch new file mode 100644 index 000000000..44767bfc1 --- /dev/null +++ b/patches/lesson04/4_5_fix_convergence.patch @@ -0,0 +1,58 @@ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490101492000) ++++ parent/pom.xml (revision ) +@@ -50,7 +50,7 @@ + + one.util + streamex +- RELEASE ++ 0.6.2 + + + +Index: test/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- test/pom.xml (date 1490101492000) ++++ test/pom.xml (revision ) +@@ -64,12 +64,12 @@ + + org.openjdk.jmh + jmh-core +- RELEASE ++ 1.15 + + + org.openjdk.jmh + jmh-generator-annprocess +- RELEASE ++ 1.15 + provided + + +Index: web/export/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/pom.xml (date 1490101492000) ++++ web/export/pom.xml (revision ) +@@ -25,6 +25,12 @@ + com.j2html + j2html + 0.7 ++ ++ ++ com.google.guava ++ guava ++ ++ + + + diff --git a/patches/lesson04/4_6_enforcer.patch b/patches/lesson04/4_6_enforcer.patch new file mode 100644 index 000000000..d9905cbce --- /dev/null +++ b/patches/lesson04/4_6_enforcer.patch @@ -0,0 +1,32 @@ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490103087000) ++++ parent/pom.xml (revision ) +@@ -38,6 +38,24 @@ + -Dfile.encoding=UTF-8 + + ++ ++ org.apache.maven.plugins ++ maven-enforcer-plugin ++ 1.4.1 ++ ++ ++ enforce ++ ++ ++ ++ ++ ++ ++ enforce ++ ++ ++ ++ +
+
+ diff --git a/patches/lesson04/4_7_logging.patch b/patches/lesson04/4_7_logging.patch new file mode 100644 index 000000000..a0507792e --- /dev/null +++ b/patches/lesson04/4_7_logging.patch @@ -0,0 +1,186 @@ +Index: config_templates/logback-test.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/logback-test.xml (revision ) ++++ config_templates/logback-test.xml (revision ) +@@ -0,0 +1,21 @@ ++ ++ ++ ++ true ++ ++ ++ ++ ++ UTF-8 ++ %-5level %logger{0} [%file:%line] %msg%n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: config_templates/logback.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/logback.xml (revision ) ++++ config_templates/logback.xml (revision ) +@@ -0,0 +1,40 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ${LOG_DIR}/${project.build.finalName}.log ++ ++ UTF-8 ++ %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{0} [%file:%line] - %msg%n ++ ++ ++ ++ ${LOG_DIR}/archived/${project.build.finalName}.%d{yyyy-MM-dd}.%i.log ++ ++ ++ 5MB ++ ++ ++ ++ ++ ++ ++ UTF-8 ++ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} [%file:%line] - %msg%n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490105015000) ++++ parent/pom.xml (revision ) +@@ -14,7 +14,11 @@ + 1.8 + UTF-8 + UTF-8 ++ ++ 1.2.2 ++ 1.7.25 + ++ /apps/masterjava/config/ + false + + +@@ -57,6 +61,18 @@ + + + ++ ++ ++ ++ ${masterjava.config} ++ ++ logback-test.xml ++ ++ ++ ++ src/test/resources ++ ++ + + + +@@ -70,6 +86,21 @@ + streamex + 0.6.2 + ++ ++ ++ ++ org.slf4j ++ jcl-over-slf4j ++ ${slf4j.version} ++ runtime ++ ++ ++ ++ ch.qos.logback ++ logback-classic ++ ${logback.version} ++ runtime ++ + + + +Index: web/common-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/common-web/pom.xml (date 1490105015000) ++++ web/common-web/pom.xml (revision ) +@@ -32,6 +32,12 @@ + org.thymeleaf + thymeleaf + 3.0.3.RELEASE ++ ++ ++ org.slf4j ++ slf4j-api ++ ++ + + + +\ No newline at end of file +Index: parent-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent-web/pom.xml (date 1490105015000) ++++ parent-web/pom.xml (revision ) +@@ -27,6 +27,19 @@ + + + ++ ++ ++ ++ ${masterjava.config} ++ true ++ ++ logback.xml ++ ++ ++ ++ src/main/resources ++ ++ + + + diff --git a/patches/lesson04/4_8_fix_and_context.patch b/patches/lesson04/4_8_fix_and_context.patch new file mode 100644 index 000000000..68ee604ae --- /dev/null +++ b/patches/lesson04/4_8_fix_and_context.patch @@ -0,0 +1,87 @@ +Index: config_templates/context.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/context.xml (revision ) ++++ config_templates/context.xml (revision ) +@@ -0,0 +1,49 @@ ++ ++ ++ ++ ++ ++ ++ ++ WEB-INF/web.xml ++ ${catalina.base}/conf/web.xml ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490107732000) ++++ parent/pom.xml (revision ) +@@ -99,7 +99,6 @@ + ch.qos.logback + logback-classic + ${logback.version} +- runtime + + + +Index: config_templates/logback-test.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/logback-test.xml (date 1490107732000) ++++ config_templates/logback-test.xml (revision ) +@@ -12,7 +12,6 @@ + + + +- + + + diff --git a/patches/lesson04/4_9_persist.patch b/patches/lesson04/4_9_persist.patch new file mode 100644 index 000000000..ae9ae0afe --- /dev/null +++ b/patches/lesson04/4_9_persist.patch @@ -0,0 +1,559 @@ +diff --git a/config_templates/logback-test.xml b/config_templates/logback-test.xml +index b6815ab..739dd6d 100644 +--- a/config_templates/logback-test.xml ++++ b/config_templates/logback-test.xml +@@ -12,6 +12,7 @@ + + + ++ + + + +diff --git a/config_templates/sql/initDB.sql b/config_templates/sql/initDB.sql +new file mode 100644 +index 0000000..888ba81 +--- /dev/null ++++ b/config_templates/sql/initDB.sql +@@ -0,0 +1,15 @@ ++DROP TABLE IF EXISTS users; ++DROP SEQUENCE IF EXISTS user_seq; ++DROP TYPE IF EXISTS user_flag; ++ ++CREATE TYPE user_flag AS ENUM ('active', 'deleted', 'superuser'); ++ ++CREATE SEQUENCE user_seq START 100000; ++ ++CREATE TABLE users ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('user_seq'), ++ full_name TEXT NOT NULL, ++ email TEXT NOT NULL, ++ flag user_flag NOT NULL ++); ++ +diff --git a/persist/pom.xml b/persist/pom.xml +new file mode 100644 +index 0000000..5816258 +--- /dev/null ++++ b/persist/pom.xml +@@ -0,0 +1,46 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ persist ++ 1.0-SNAPSHOT ++ Persist ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ org.jdbi ++ jdbi ++ 2.78 ++ ++ ++ com.bertoncelj.jdbi.entitymapper ++ jdbi-entity-mapper ++ 1.0.0 ++ ++ ++ org.jdbi ++ jdbi ++ ++ ++ ++ ++ org.postgresql ++ postgresql ++ 9.4.1211 ++ ++ ++ +\ No newline at end of file +diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java b/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java +new file mode 100644 +index 0000000..69904ce +--- /dev/null ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java +@@ -0,0 +1,56 @@ ++package ru.javaops.masterjava.persist; ++ ++import org.skife.jdbi.v2.DBI; ++import org.skife.jdbi.v2.logging.SLF4JLog; ++import org.skife.jdbi.v2.tweak.ConnectionFactory; ++import org.slf4j.Logger; ++import ru.javaops.masterjava.persist.dao.AbstractDao; ++ ++import javax.naming.InitialContext; ++import javax.sql.DataSource; ++ ++import static org.slf4j.LoggerFactory.getLogger; ++ ++/** ++ * gkislin ++ * 01.11.2016 ++ */ ++public class DBIProvider { ++ private static final Logger log = getLogger(DBIProvider.class); ++ ++ private volatile static ConnectionFactory connectionFactory = null; ++ ++ private static class DBIHolder { ++ static final DBI jDBI; ++ ++ static { ++ final DBI dbi; ++ if (connectionFactory != null) { ++ log.info("Init jDBI with connectionFactory"); ++ dbi = new DBI(connectionFactory); ++ } else { ++ try { ++ log.info("Init jDBI with JNDI"); ++ InitialContext ctx = new InitialContext(); ++ dbi = new DBI((DataSource) ctx.lookup("java:/comp/env/jdbc/masterjava")); ++ } catch (Exception ex) { ++ throw new IllegalStateException("PostgreSQL initialization failed", ex); ++ } ++ } ++ jDBI = dbi; ++ jDBI.setSQLLog(new SLF4JLog()); ++ } ++ } ++ ++ public static void init(ConnectionFactory connectionFactory) { ++ DBIProvider.connectionFactory = connectionFactory; ++ } ++ ++ public static DBI getDBI() { ++ return DBIHolder.jDBI; ++ } ++ ++ public static T getDao(Class daoClass) { ++ return DBIHolder.jDBI.onDemand(daoClass); ++ } ++} +diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/AbstractDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/AbstractDao.java +new file mode 100644 +index 0000000..f7e97e4 +--- /dev/null ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/AbstractDao.java +@@ -0,0 +1,11 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ *

++ *

++ */ ++public interface AbstractDao { ++ void clean(); ++} +diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +new file mode 100644 +index 0000000..915efdf +--- /dev/null ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +@@ -0,0 +1,43 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import org.skife.jdbi.v2.sqlobject.*; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.model.User; ++ ++import java.util.List; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ *

++ *

++ */ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class UserDao implements AbstractDao { ++ ++ public User insert(User user) { ++ if (user.isNew()) { ++ int id = insertGeneratedId(user); ++ user.setId(id); ++ } else { ++ insertWitId(user); ++ } ++ return user; ++ } ++ ++ @SqlUpdate("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS user_flag)) ") ++ @GetGeneratedKeys ++ abstract int insertGeneratedId(@BindBean User user); ++ ++ @SqlUpdate("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS user_flag)) ") ++ abstract void insertWitId(@BindBean User user); ++ ++ @SqlQuery("SELECT * FROM users ORDER BY full_name, email LIMIT :it") ++ public abstract List getWithLimit(@Bind int limit); ++ ++ // http://stackoverflow.com/questions/13223820/postgresql-delete-all-content ++ @SqlUpdate("TRUNCATE users") ++ @Override ++ public abstract void clean(); ++} +diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +new file mode 100644 +index 0000000..c967068 +--- /dev/null ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +@@ -0,0 +1,41 @@ ++package ru.javaops.masterjava.persist.model; ++ ++/** ++ * gkislin ++ * 28.10.2016 ++ */ ++abstract public class BaseEntity { ++ protected BaseEntity() { ++ } ++ ++ protected BaseEntity(Integer id) { ++ this.id = id; ++ } ++ ++ protected Integer id; ++ ++ public Integer getId() { ++ return id; ++ } ++ ++ protected void setId(Integer id) { ++ this.id = id; ++ } ++ ++ public boolean isNew() { ++ return id == null; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ BaseEntity baseEntity = (BaseEntity) o; ++ return id != null && id.equals(baseEntity.id); ++ } ++ ++ @Override ++ public int hashCode() { ++ return id == null ? 0 : id; ++ } ++} +diff --git a/web/export/src/main/java/ru/javaops/masterjava/model/User.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +similarity index 69% +rename from web/export/src/main/java/ru/javaops/masterjava/model/User.java +rename to persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +index d7c3f8c..f4445cb 100644 +--- a/web/export/src/main/java/ru/javaops/masterjava/model/User.java ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +@@ -1,28 +1,31 @@ +-package ru.javaops.masterjava.model; ++package ru.javaops.masterjava.persist.model; ++ ++import com.bertoncelj.jdbi.entitymapper.Column; + + import java.util.Objects; + +-public class User { +- private final Integer id; +- private final String fullName; +- private final String email; +- private final UserFlag flag; ++public class User extends BaseEntity { ++ @Column("full_name") ++ private String fullName; ++ ++ private String email; ++ ++ private UserFlag flag; ++ ++ public User() { ++ } + + public User(String fullName, String email, UserFlag flag) { + this(null, fullName, email, flag); + } + + public User(Integer id, String fullName, String email, UserFlag flag) { +- this.id = id; ++ super(id); + this.fullName = fullName; + this.email = email; + this.flag = flag; + } + +- public Integer getId() { +- return id; +- } +- + public String getFullName() { + return fullName; + } +@@ -35,6 +38,22 @@ public class User { + return flag; + } + ++ public void setId(Integer id) { ++ this.id = id; ++ } ++ ++ public void setFullName(String fullName) { ++ this.fullName = fullName; ++ } ++ ++ public void setEmail(String email) { ++ this.email = email; ++ } ++ ++ public void setFlag(UserFlag flag) { ++ this.flag = flag; ++ } ++ + @Override + public boolean equals(Object o) { + if (this == o) return true; +@@ -60,4 +79,4 @@ public class User { + ", flag=" + flag + + ')'; + } +-} ++} +\ No newline at end of file +diff --git a/web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/UserFlag.java +similarity index 68% +rename from web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java +rename to persist/src/main/java/ru/javaops/masterjava/persist/model/UserFlag.java +index 603626a..bc2f691 100644 +--- a/web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java ++++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/UserFlag.java +@@ -1,4 +1,4 @@ +-package ru.javaops.masterjava.model; ++package ru.javaops.masterjava.persist.model; + + /** + * gkislin +diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java b/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java +new file mode 100644 +index 0000000..79467af +--- /dev/null ++++ b/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java +@@ -0,0 +1,24 @@ ++package ru.javaops.masterjava.persist; ++ ++import java.sql.DriverManager; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ */ ++public class DBITestProvider { ++ public static void initDBI() { ++ initDBI("jdbc:postgresql://localhost:5432/masterjava", "user", "password"); ++ } ++ ++ public static void initDBI(String dbUrl, String dbUser, String dbPassword) { ++ DBIProvider.init(() -> { ++ try { ++ Class.forName("org.postgresql.Driver"); ++ } catch (ClassNotFoundException e) { ++ throw new IllegalStateException("PostgreSQL driver not found", e); ++ } ++ return DriverManager.getConnection(dbUrl, dbUser, dbPassword); ++ }); ++ } ++} +\ No newline at end of file +diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java +new file mode 100644 +index 0000000..bc80bba +--- /dev/null ++++ b/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java +@@ -0,0 +1,41 @@ ++package ru.javaops.masterjava.persist; ++ ++import com.google.common.collect.ImmutableList; ++import ru.javaops.masterjava.persist.dao.UserDao; ++import ru.javaops.masterjava.persist.model.User; ++import ru.javaops.masterjava.persist.model.UserFlag; ++ ++import java.util.List; ++ ++/** ++ * gkislin ++ * 14.11.2016 ++ */ ++public class UserTestData { ++ public static User ADMIN; ++ public static User DELETED; ++ public static User FULL_NAME; ++ public static User USER1; ++ public static User USER2; ++ public static User USER3; ++ public static List FIST5_USERS; ++ ++ public static void init() { ++ ADMIN = new User("Admin", "admin@javaops.ru", UserFlag.superuser); ++ DELETED = new User("Deleted", "deleted@yandex.ru", UserFlag.deleted); ++ FULL_NAME = new User("Full Name", "gmail@gmail.com", UserFlag.active); ++ USER1 = new User("User1", "user1@gmail.com", UserFlag.active); ++ USER2 = new User("User2", "user2@yandex.ru", UserFlag.active); ++ USER3 = new User("User3", "user3@yandex.ru", UserFlag.active); ++ FIST5_USERS = ImmutableList.of(ADMIN, DELETED, FULL_NAME, USER1, USER2); ++ } ++ ++ public static void setUp() { ++ UserDao dao = DBIProvider.getDao(UserDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ FIST5_USERS.forEach(dao::insert); ++ dao.insert(USER3); ++ }); ++ } ++} +diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java +new file mode 100644 +index 0000000..76ceb14 +--- /dev/null ++++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java +@@ -0,0 +1,20 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.persist.DBITestProvider; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ */ ++public abstract class AbstractDaoTest { ++ static { ++ DBITestProvider.initDBI(); ++ } ++ ++ protected DAO dao; ++ ++ protected AbstractDaoTest(Class daoClass) { ++ this.dao = DBIProvider.getDao(daoClass); ++ } ++} +diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +new file mode 100644 +index 0000000..e47dbac +--- /dev/null ++++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +@@ -0,0 +1,39 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import org.junit.Assert; ++import org.junit.Before; ++import org.junit.BeforeClass; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.UserTestData; ++import ru.javaops.masterjava.persist.model.User; ++ ++import java.util.List; ++ ++import static ru.javaops.masterjava.persist.UserTestData.FIST5_USERS; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ */ ++public class UserDaoTest extends AbstractDaoTest { ++ ++ public UserDaoTest() { ++ super(UserDao.class); ++ } ++ ++ @BeforeClass ++ public static void init() throws Exception { ++ UserTestData.init(); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ UserTestData.setUp(); ++ } ++ ++ @Test ++ public void getWithLimit() { ++ List users = dao.getWithLimit(5); ++ Assert.assertEquals(FIST5_USERS, users); ++ } ++} +\ No newline at end of file +diff --git a/pom.xml b/pom.xml +index d7da81f..e6aa92b 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -16,6 +16,7 @@ + parent-web + + common ++ persist + test + + web +diff --git a/web/export/pom.xml b/web/export/pom.xml +index e64c945..3196e8a 100644 +--- a/web/export/pom.xml ++++ b/web/export/pom.xml +@@ -22,6 +22,11 @@ + + + ++ ${project.groupId} ++ persist ++ ${project.version} ++ ++ + com.j2html + j2html + 0.7 +diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java b/web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +index 6b8e587..b254d14 100644 +--- a/web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java ++++ b/web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +@@ -1,7 +1,7 @@ + package ru.javaops.masterjava.export; + + import org.thymeleaf.context.WebContext; +-import ru.javaops.masterjava.model.User; ++import ru.javaops.masterjava.persist.model.User; + + import javax.servlet.ServletException; + import javax.servlet.annotation.MultipartConfig; +diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +index 27daf5f..078268b 100644 +--- a/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java ++++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +@@ -1,7 +1,7 @@ + package ru.javaops.masterjava.export; + +-import ru.javaops.masterjava.model.User; +-import ru.javaops.masterjava.model.UserFlag; ++import ru.javaops.masterjava.persist.model.User; ++import ru.javaops.masterjava.persist.model.UserFlag; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; + + import javax.xml.stream.XMLStreamException; diff --git a/patches/lesson05/5_1_HW4_export_chunk.patch b/patches/lesson05/5_1_HW4_export_chunk.patch new file mode 100644 index 000000000..5421c5973 --- /dev/null +++ b/patches/lesson05/5_1_HW4_export_chunk.patch @@ -0,0 +1,249 @@ +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java (date 1490553921000) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java (revision ) +@@ -36,4 +36,11 @@ + List users = dao.getWithLimit(5); + Assert.assertEquals(FIST5_USERS, users); + } ++ ++ @Test ++ public void insertBatch() throws Exception { ++ dao.clean(); ++ dao.insertBatch(FIST5_USERS, 3); ++ Assert.assertEquals(5, dao.getWithLimit(100).size()); ++ } + } +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1490553921000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -2,6 +2,7 @@ + + import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; + import org.skife.jdbi.v2.sqlobject.*; ++import org.skife.jdbi.v2.sqlobject.customizers.BatchChunkSize; + import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; + import ru.javaops.masterjava.persist.model.User; + +@@ -26,11 +27,11 @@ + return user; + } + +- @SqlUpdate("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS user_flag)) ") ++ @SqlUpdate("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG)) ") + @GetGeneratedKeys + abstract int insertGeneratedId(@BindBean User user); + +- @SqlUpdate("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS user_flag)) ") ++ @SqlUpdate("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG)) ") + abstract void insertWitId(@BindBean User user); + + @SqlQuery("SELECT * FROM users ORDER BY full_name, email LIMIT :it") +@@ -40,4 +41,8 @@ + @SqlUpdate("TRUNCATE users") + @Override + public abstract void clean(); ++ ++ @SqlBatch("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG))") ++ public abstract void insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); ++ + } +Index: parent-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent-web/pom.xml (date 1490553921000) ++++ parent-web/pom.xml (revision ) +@@ -26,6 +26,47 @@ + false + + ++ ++ ++ ++ org.codehaus.cargo ++ cargo-maven2-plugin ++ 1.6.2 ++ ++ ++ tomcat8x ++ ++ UTF-8 ++ ++ ++ ++ org.postgresql ++ postgresql ++ ++ ++ ++ ++ ++ ++ ${masterjava.config}/context.xml ++ conf/Catalina/localhost/ ++ context.xml.default ++ ++ ++ ++ ++ ++ ${project.groupId} ++ ${project.artifactId} ++ war ++ ++ ${project.build.finalName} ++ ++ ++ ++ ++ ++ + + + +Index: web/export/src/main/webapp/WEB-INF/templates/export.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/export.html (date 1490553921000) ++++ web/export/src/main/webapp/WEB-INF/templates/export.html (revision ) +@@ -1,11 +1,17 @@ ++ + + + Export XML + + +

++ ++

Message

+

Select xml file to upload

+

++ ++ ++

+
+

+

+Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1490553921000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -1,5 +1,8 @@ + package ru.javaops.masterjava.export; + ++import com.google.common.collect.ImmutableMap; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; + import org.thymeleaf.context.WebContext; + import ru.javaops.masterjava.persist.model.User; + +@@ -19,30 +22,49 @@ + @WebServlet("/") + @MultipartConfig + public class UploadServlet extends HttpServlet { ++ private static final Logger log = LoggerFactory.getLogger(UploadServlet.class); ++ private static final int CHUNK_SIZE = 2000; + + private final UserExport userExport = new UserExport(); + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { +- final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale()); +- engine.process("export", webContext, resp.getWriter()); ++ outExport(req, resp, "", CHUNK_SIZE); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { +- final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale()); +- ++ String message; ++ int chunkSize = CHUNK_SIZE; + try { + // http://docs.oracle.com/javaee/6/tutorial/doc/glraq.html +- Part filePart = req.getPart("fileToUpload"); +- try (InputStream is = filePart.getInputStream()) { +- List users = userExport.process(is); +- webContext.setVariable("users", users); +- engine.process("result", webContext, resp.getWriter()); ++ chunkSize = Integer.parseInt(req.getParameter("chunkSize")); ++ if (chunkSize < 1) { ++ message = "Chunk Size must be > 1"; ++ } else { ++ Part filePart = req.getPart("fileToUpload"); ++ try (InputStream is = filePart.getInputStream()) { ++ List users = userExport.process(is, chunkSize); ++ log.info("Successfully uploaded " + users.size() + " users"); ++ final WebContext webContext = ++ new WebContext(req, resp, req.getServletContext(), req.getLocale(), ++ ImmutableMap.of("users", users)); ++ engine.process("result", webContext, resp.getWriter()); ++ return; ++ } + } + } catch (Exception e) { +- webContext.setVariable("exception", e); +- engine.process("exception", webContext, resp.getWriter()); ++ log.info(e.getMessage(), e); ++ message = e.toString(); + } ++ outExport(req, resp, message, chunkSize); ++ } ++ ++ private void outExport(HttpServletRequest req, HttpServletResponse resp, String message, int chunkSize) throws IOException { ++ resp.setCharacterEncoding("utf-8"); ++ final WebContext webContext = ++ new WebContext(req, resp, req.getServletContext(), req.getLocale(), ++ ImmutableMap.of("message", message, "chunkSize", chunkSize)); ++ engine.process("export", webContext, resp.getWriter()); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1490553921000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -1,5 +1,7 @@ + package ru.javaops.masterjava.export; + ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.User; + import ru.javaops.masterjava.persist.model.UserFlag; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; +@@ -16,7 +18,9 @@ + */ + public class UserExport { + +- public List process(final InputStream is) throws XMLStreamException { ++ private UserDao userDao = DBIProvider.getDao(UserDao.class); ++ ++ public List process(final InputStream is, int chunkSize) throws XMLStreamException { + final StaxStreamProcessor processor = new StaxStreamProcessor(is); + List users = new ArrayList<>(); + +@@ -27,6 +31,7 @@ + final User user = new User(fullName, email, flag); + users.add(user); + } ++ userDao.insertBatch(users, chunkSize); + return users; + } + } diff --git a/patches/lesson05/5_2_HW4_webapp_users.patch b/patches/lesson05/5_2_HW4_webapp_users.patch new file mode 100644 index 000000000..e5f55ca49 --- /dev/null +++ b/patches/lesson05/5_2_HW4_webapp_users.patch @@ -0,0 +1,95 @@ +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java (revision ) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java (revision ) +@@ -0,0 +1,28 @@ ++package ru.javaops.masterjava.webapp; ++ ++import com.google.common.collect.ImmutableMap; ++import org.thymeleaf.TemplateEngine; ++import org.thymeleaf.context.WebContext; ++import ru.javaops.masterjava.common.web.ThymeleafUtil; ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.persist.dao.UserDao; ++ ++import javax.servlet.ServletException; ++import javax.servlet.annotation.WebServlet; ++import javax.servlet.http.HttpServlet; ++import javax.servlet.http.HttpServletRequest; ++import javax.servlet.http.HttpServletResponse; ++import java.io.IOException; ++ ++@WebServlet("") ++public class UsersServlet extends HttpServlet { ++ private UserDao userDao = DBIProvider.getDao(UserDao.class); ++ ++ @Override ++ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ++ final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale(), ++ ImmutableMap.of("users", userDao.getWithLimit(20))); ++ final TemplateEngine engine = ThymeleafUtil.getTemplateEngine(getServletContext()); ++ engine.process("users", webContext, resp.getWriter()); ++ } ++} +Index: web/webapp/src/main/webapp/WEB-INF/templates/users.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/webapp/WEB-INF/templates/users.html (revision ) ++++ web/webapp/src/main/webapp/WEB-INF/templates/users.html (revision ) +@@ -0,0 +1,27 @@ ++ ++ ++ ++ Users ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
Full NameEmailFlag
++ ++ +\ No newline at end of file +Index: web/webapp/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/pom.xml (date 1490735901000) ++++ web/webapp/pom.xml (revision ) +@@ -16,10 +16,14 @@ + war + WebApp + ++ ++ webapp ++ ++ + + + ${project.groupId} +- common ++ persist + ${project.version} + + diff --git a/patches/lesson05/5_3_HW4_already_present.patch b/patches/lesson05/5_3_HW4_already_present.patch new file mode 100644 index 000000000..6db84494c --- /dev/null +++ b/patches/lesson05/5_3_HW4_already_present.patch @@ -0,0 +1,117 @@ +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1490737306000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -42,7 +42,9 @@ + @Override + public abstract void clean(); + +- @SqlBatch("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG))") +- public abstract void insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); +- ++ // https://habrahabr.ru/post/264281/ ++ @SqlBatch("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG))" + ++ "ON CONFLICT DO NOTHING") ++// "ON CONFLICT (email) DO UPDATE SET full_name=:fullName, flag=CAST(:flag AS USER_FLAG)") ++ public abstract int[] insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); + } +Index: web/export/src/main/webapp/WEB-INF/templates/result.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/result.html (date 1490737306000) ++++ web/export/src/main/webapp/WEB-INF/templates/result.html (revision ) +@@ -1,11 +1,11 @@ + + + +- Uploaded users ++ Already present users + + +

Export XML

+-

Uploaded users

++

Already present users

+ + + +Index: config_templates/sql/initDB.sql +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/initDB.sql (date 1490737306000) ++++ config_templates/sql/initDB.sql (revision ) +@@ -13,3 +13,4 @@ + flag user_flag NOT NULL + ); + ++CREATE UNIQUE INDEX email_idx ON users (email); +\ No newline at end of file +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1490737306000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -1,5 +1,6 @@ + package ru.javaops.masterjava.export; + ++import one.util.streamex.IntStreamEx; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.User; +@@ -20,6 +21,12 @@ + + private UserDao userDao = DBIProvider.getDao(UserDao.class); + ++ /** ++ * @param is thr payload input stream ++ * @param chunkSize the batch chunk size ++ * @return users, already present in DB ++ * @throws XMLStreamException ++ */ + public List process(final InputStream is, int chunkSize) throws XMLStreamException { + final StaxStreamProcessor processor = new StaxStreamProcessor(is); + List users = new ArrayList<>(); +@@ -31,7 +38,11 @@ + final User user = new User(fullName, email, flag); + users.add(user); + } +- userDao.insertBatch(users, chunkSize); +- return users; ++ ++ int[] result = userDao.insertBatch(users, chunkSize); ++ return IntStreamEx.range(0, users.size()) ++ .filter(i -> result[i] == 0) ++ .mapToObj(users::get) ++ .toList(); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1490737306000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -44,11 +44,11 @@ + } else { + Part filePart = req.getPart("fileToUpload"); + try (InputStream is = filePart.getInputStream()) { +- List users = userExport.process(is, chunkSize); +- log.info("Successfully uploaded " + users.size() + " users"); ++ List alreadyPresentUsers = userExport.process(is, chunkSize); ++ log.info("Already present in DB " + alreadyPresentUsers.size() + " users"); + final WebContext webContext = + new WebContext(req, resp, req.getServletContext(), req.getLocale(), +- ImmutableMap.of("users", users)); ++ ImmutableMap.of("users", alreadyPresentUsers)); + engine.process("result", webContext, resp.getWriter()); + return; + } diff --git a/patches/lesson05/5_4_HW4_parallel.patch b/patches/lesson05/5_4_HW4_parallel.patch new file mode 100644 index 000000000..593e90b42 --- /dev/null +++ b/patches/lesson05/5_4_HW4_parallel.patch @@ -0,0 +1,284 @@ +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java (date 1490738942000) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java (revision ) +@@ -43,4 +43,11 @@ + dao.insertBatch(FIST5_USERS, 3); + Assert.assertEquals(5, dao.getWithLimit(100).size()); + } ++ ++ @Test ++ public void getSeqAndSkip() throws Exception { ++ int seq1 = dao.getSeqAndSkip(5); ++ int seq2 = dao.getSeqAndSkip(1); ++ Assert.assertEquals(5, seq2 - seq1); ++ } + } +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1490738942000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -1,9 +1,11 @@ + package ru.javaops.masterjava.persist.dao; + + import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import one.util.streamex.IntStreamEx; + import org.skife.jdbi.v2.sqlobject.*; + import org.skife.jdbi.v2.sqlobject.customizers.BatchChunkSize; + import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.model.User; + + import java.util.List; +@@ -27,6 +29,16 @@ + return user; + } + ++ @SqlQuery("SELECT nextval('user_seq')") ++ abstract int getNextVal(); ++ ++ @Transaction ++ public int getSeqAndSkip(int step) { ++ int id = getNextVal(); ++ DBIProvider.getDBI().useHandle(h -> h.execute("ALTER SEQUENCE user_seq RESTART WITH " + (id + step))); ++ return id; ++ } ++ + @SqlUpdate("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG)) ") + @GetGeneratedKeys + abstract int insertGeneratedId(@BindBean User user); +@@ -43,8 +55,17 @@ + public abstract void clean(); + + // https://habrahabr.ru/post/264281/ +- @SqlBatch("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG))" + ++ @SqlBatch("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG))" + + "ON CONFLICT DO NOTHING") + // "ON CONFLICT (email) DO UPDATE SET full_name=:fullName, flag=CAST(:flag AS USER_FLAG)") + public abstract int[] insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); ++ ++ ++ public List insertAndGetAlreadyPresent(List users) { ++ int[] result = insertBatch(users, users.size()); ++ return IntStreamEx.range(0, users.size()) ++ .filter(i -> result[i] == 0) ++ .mapToObj(index -> users.get(index).getEmail()) ++ .toList(); ++ } + } +Index: web/export/src/main/webapp/WEB-INF/templates/result.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/result.html (date 1490738942000) ++++ web/export/src/main/webapp/WEB-INF/templates/result.html (revision ) +@@ -1,26 +1,14 @@ + + + +- Already present users ++ Failed users + + +

Export XML

+-

Already present users

+-
+- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
Full NameEmailFlag
++

Failed users

++
    ++ ++
  • ++
+ + +\ No newline at end of file +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1490738942000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -4,7 +4,6 @@ + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + import org.thymeleaf.context.WebContext; +-import ru.javaops.masterjava.persist.model.User; + + import javax.servlet.ServletException; + import javax.servlet.annotation.MultipartConfig; +@@ -44,11 +43,11 @@ + } else { + Part filePart = req.getPart("fileToUpload"); + try (InputStream is = filePart.getInputStream()) { +- List alreadyPresentUsers = userExport.process(is, chunkSize); +- log.info("Already present in DB " + alreadyPresentUsers.size() + " users"); ++ List failed = userExport.process(is, chunkSize); ++ log.info("Failed users: " + failed); + final WebContext webContext = + new WebContext(req, resp, req.getServletContext(), req.getLocale(), +- ImmutableMap.of("users", alreadyPresentUsers)); ++ ImmutableMap.of("failed", failed)); + engine.process("result", webContext, resp.getWriter()); + return; + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1490738942000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -1,6 +1,8 @@ + package ru.javaops.masterjava.export; + +-import one.util.streamex.IntStreamEx; ++import one.util.streamex.StreamEx; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.User; +@@ -12,37 +14,99 @@ + import java.io.InputStream; + import java.util.ArrayList; + import java.util.List; ++import java.util.concurrent.Callable; ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; ++import java.util.concurrent.Future; + + /** + * gkislin + * 14.10.2016 + */ + public class UserExport { ++ private static final Logger log = LoggerFactory.getLogger(UserExport.class); + + private UserDao userDao = DBIProvider.getDao(UserDao.class); ++ private static final int NUMBER_THREADS = 4; ++ private ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + +- /** +- * @param is thr payload input stream +- * @param chunkSize the batch chunk size +- * @return users, already present in DB +- * @throws XMLStreamException +- */ +- public List process(final InputStream is, int chunkSize) throws XMLStreamException { +- final StaxStreamProcessor processor = new StaxStreamProcessor(is); +- List users = new ArrayList<>(); ++ public static class FailedEmail { ++ public String emailOrRange; ++ public String reason; ++ ++ public FailedEmail(String emailOrRange, String reason) { ++ this.emailOrRange = emailOrRange; ++ this.reason = reason; ++ } ++ ++ @Override ++ public String toString() { ++ return emailOrRange + " : " + reason; ++ } ++ } ++ ++ public List process(final InputStream is, int chunkSize) throws XMLStreamException { ++ log.info("Start proseccing with chunkSize=" + chunkSize); ++ ++ return new Callable>() { ++ class ChunkFuture { ++ String emailRange; ++ Future> future; ++ ++ public ChunkFuture(List chunk, Future> future) { ++ this.future = future; ++ this.emailRange = chunk.get(0).getEmail(); ++ if (chunk.size() > 1) { ++ this.emailRange += '-' + chunk.get(chunk.size() - 1).getEmail(); ++ } ++ } ++ } ++ ++ @Override ++ public List call() throws XMLStreamException { ++ List futures = new ArrayList<>(); ++ ++ int id = userDao.getSeqAndSkip(chunkSize); ++ List chunk = new ArrayList<>(chunkSize); ++ final StaxStreamProcessor processor = new StaxStreamProcessor(is); + +- while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { +- final String email = processor.getAttribute("email"); +- final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); +- final String fullName = processor.getReader().getElementText(); +- final User user = new User(fullName, email, flag); +- users.add(user); +- } ++ while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { ++ final String email = processor.getAttribute("email"); ++ final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); ++ final String fullName = processor.getReader().getElementText(); ++ final User user = new User(id++, fullName, email, flag); ++ chunk.add(user); ++ if (chunk.size() == chunkSize) { ++ futures.add(submit(chunk)); ++ chunk.clear(); ++ id = userDao.getSeqAndSkip(chunkSize); ++ } ++ } + +- int[] result = userDao.insertBatch(users, chunkSize); +- return IntStreamEx.range(0, users.size()) +- .filter(i -> result[i] == 0) +- .mapToObj(users::get) +- .toList(); ++ if (!chunk.isEmpty()) { ++ futures.add(submit(chunk)); ++ } ++ ++ List failed = new ArrayList<>(); ++ futures.forEach(cf -> { ++ try { ++ failed.addAll(StreamEx.of(cf.future.get()).map(email -> new FailedEmail(email, "already present")).toList()); ++ log.info(cf.emailRange + " successfully executed"); ++ } catch (Exception e) { ++ log.error(cf.emailRange + " failed", e); ++ failed.add(new FailedEmail(cf.emailRange, e.toString())); ++ } ++ }); ++ return failed; ++ } ++ ++ private ChunkFuture submit(List chunk) { ++ ChunkFuture chunkFuture = new ChunkFuture(chunk, ++ executorService.submit(() -> userDao.insertAndGetAlreadyPresent(chunk)) ++ ); ++ log.info("Submit " + chunkFuture.emailRange); ++ return chunkFuture; ++ } ++ }.call(); + } + } diff --git a/patches/lesson05/5_5_typesafe_config.patch b/patches/lesson05/5_5_typesafe_config.patch new file mode 100644 index 000000000..57d5fbfa8 --- /dev/null +++ b/patches/lesson05/5_5_typesafe_config.patch @@ -0,0 +1,88 @@ +Index: persist/src/main/resources/persist.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/resources/persist.conf (revision ) ++++ persist/src/main/resources/persist.conf (revision ) +@@ -0,0 +1,7 @@ ++db { ++ url = "jdbc:postgresql://localhost:5432/masterjava" ++ user = user ++ password = password ++} ++ ++include required(file("/apps/masterjava/config/persist.conf")) +Index: common/src/main/java/ru/javaops/masterjava/config/Configs.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/config/Configs.java (revision ) ++++ common/src/main/java/ru/javaops/masterjava/config/Configs.java (revision ) +@@ -0,0 +1,19 @@ ++package ru.javaops.masterjava.config; ++ ++import com.typesafe.config.Config; ++import com.typesafe.config.ConfigFactory; ++ ++/** ++ * gkislin ++ * 01.11.2016 ++ */ ++public class Configs { ++ ++ public static Config getConfig(String resource) { ++ return ConfigFactory.parseResources(resource).resolve(); ++ } ++ ++ public static Config getConfig(String resource, String domain) { ++ return getConfig(resource).getConfig(domain); ++ } ++} +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490746427000) ++++ parent/pom.xml (revision ) +@@ -86,6 +86,12 @@ + streamex + 0.6.2 + ++ ++ ++ com.typesafe ++ config ++ 1.3.1 ++ + + + +Index: persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java (date 1490746427000) ++++ persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java (revision ) +@@ -1,5 +1,8 @@ + package ru.javaops.masterjava.persist; + ++import com.typesafe.config.Config; ++import ru.javaops.masterjava.config.Configs; ++ + import java.sql.DriverManager; + + /** +@@ -8,7 +11,8 @@ + */ + public class DBITestProvider { + public static void initDBI() { +- initDBI("jdbc:postgresql://localhost:5432/masterjava", "user", "password"); ++ Config db = Configs.getConfig("persist.conf","db"); ++ initDBI(db.getString("url"), db.getString("user"), db.getString("password")); + } + + public static void initDBI(String dbUrl, String dbUser, String dbPassword) { diff --git a/patches/lesson05/5_6_lombook.patch b/patches/lesson05/5_6_lombook.patch new file mode 100644 index 000000000..7072c50a5 --- /dev/null +++ b/patches/lesson05/5_6_lombook.patch @@ -0,0 +1,268 @@ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (date 1490748029000) ++++ parent/pom.xml (revision ) +@@ -93,6 +93,13 @@ + 1.3.1 + + ++ ++ org.projectlombok ++ lombok ++ 1.16.16 ++ provided ++ ++ + + + org.slf4j +Index: persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java (date 1490748029000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java (revision ) +@@ -1,22 +1,20 @@ + package ru.javaops.masterjava.persist; + ++import lombok.extern.slf4j.Slf4j; + import org.skife.jdbi.v2.DBI; + import org.skife.jdbi.v2.logging.SLF4JLog; + import org.skife.jdbi.v2.tweak.ConnectionFactory; +-import org.slf4j.Logger; + import ru.javaops.masterjava.persist.dao.AbstractDao; + + import javax.naming.InitialContext; + import javax.sql.DataSource; + +-import static org.slf4j.LoggerFactory.getLogger; +- + /** + * gkislin + * 01.11.2016 + */ ++@Slf4j + public class DBIProvider { +- private static final Logger log = getLogger(DBIProvider.class); + + private volatile static ConnectionFactory connectionFactory = null; + +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (date 1490748029000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (revision ) +@@ -1,82 +1,20 @@ + package ru.javaops.masterjava.persist.model; + + import com.bertoncelj.jdbi.entitymapper.Column; ++import lombok.*; + +-import java.util.Objects; +- ++@Data ++@RequiredArgsConstructor ++@EqualsAndHashCode(callSuper = true) ++@NoArgsConstructor + public class User extends BaseEntity { + @Column("full_name") +- private String fullName; +- +- private String email; +- +- private UserFlag flag; +- +- public User() { +- } +- +- public User(String fullName, String email, UserFlag flag) { +- this(null, fullName, email, flag); +- } ++ private @NonNull String fullName; ++ private @NonNull String email; ++ private @NonNull UserFlag flag; + + public User(Integer id, String fullName, String email, UserFlag flag) { +- super(id); +- this.fullName = fullName; +- this.email = email; +- this.flag = flag; +- } +- +- public String getFullName() { +- return fullName; +- } +- +- public String getEmail() { +- return email; +- } +- +- public UserFlag getFlag() { +- return flag; +- } +- +- public void setId(Integer id) { +- this.id = id; ++ this(fullName, email, flag); ++ this.id=id; + } +- +- public void setFullName(String fullName) { +- this.fullName = fullName; +- } +- +- public void setEmail(String email) { +- this.email = email; +- } +- +- public void setFlag(UserFlag flag) { +- this.flag = flag; +- } +- +- @Override +- public boolean equals(Object o) { +- if (this == o) return true; +- if (o == null || getClass() != o.getClass()) return false; +- User user = (User) o; +- return Objects.equals(id, user.id) && +- Objects.equals(fullName, user.fullName) && +- Objects.equals(email, user.email) && +- flag == user.flag; +- } +- +- @Override +- public int hashCode() { +- return Objects.hash(id, fullName, email, flag); +- } +- +- @Override +- public String toString() { +- return "User (" + +- "id=" + id + +- ", fullName='" + fullName + '\'' + +- ", email='" + email + '\'' + +- ", flag=" + flag + +- ')'; +- } + } +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java (date 1490748029000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java (revision ) +@@ -1,27 +1,22 @@ + package ru.javaops.masterjava.persist.model; + ++import lombok.AllArgsConstructor; ++import lombok.Getter; ++import lombok.NoArgsConstructor; ++import lombok.Setter; ++ + /** + * gkislin + * 28.10.2016 + */ ++@NoArgsConstructor ++@AllArgsConstructor + abstract public class BaseEntity { +- protected BaseEntity() { +- } + +- protected BaseEntity(Integer id) { +- this.id = id; +- } +- ++ @Getter ++ @Setter + protected Integer id; + +- public Integer getId() { +- return id; +- } +- +- protected void setId(Integer id) { +- this.id = id; +- } +- + public boolean isNew() { + return id == null; + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1490748029000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -1,8 +1,7 @@ + package ru.javaops.masterjava.export; + + import com.google.common.collect.ImmutableMap; +-import org.slf4j.Logger; +-import org.slf4j.LoggerFactory; ++import lombok.extern.slf4j.Slf4j; + import org.thymeleaf.context.WebContext; + + import javax.servlet.ServletException; +@@ -20,8 +19,8 @@ + + @WebServlet("/") + @MultipartConfig ++@Slf4j + public class UploadServlet extends HttpServlet { +- private static final Logger log = LoggerFactory.getLogger(UploadServlet.class); + private static final int CHUNK_SIZE = 2000; + + private final UserExport userExport = new UserExport(); +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1490748029000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -1,8 +1,8 @@ + package ru.javaops.masterjava.export; + ++import lombok.Value; ++import lombok.extern.slf4j.Slf4j; + import one.util.streamex.StreamEx; +-import org.slf4j.Logger; +-import org.slf4j.LoggerFactory; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.User; +@@ -23,22 +23,18 @@ + * gkislin + * 14.10.2016 + */ ++@Slf4j + public class UserExport { +- private static final Logger log = LoggerFactory.getLogger(UserExport.class); + + private UserDao userDao = DBIProvider.getDao(UserDao.class); + private static final int NUMBER_THREADS = 4; + private ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + ++ @Value + public static class FailedEmail { + public String emailOrRange; + public String reason; + +- public FailedEmail(String emailOrRange, String reason) { +- this.emailOrRange = emailOrRange; +- this.reason = reason; +- } +- + @Override + public String toString() { + return emailOrRange + " : " + reason; diff --git a/patches/lesson05/5_7_fix.patch b/patches/lesson05/5_7_fix.patch new file mode 100644 index 000000000..c455ea351 --- /dev/null +++ b/patches/lesson05/5_7_fix.patch @@ -0,0 +1,53 @@ +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1490995613000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -61,7 +61,7 @@ + public abstract int[] insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); + + +- public List insertAndGetAlreadyPresent(List users) { ++ public List insertAndGetConflictEmails(List users) { + int[] result = insertBatch(users, users.size()); + return IntStreamEx.range(0, users.size()) + .filter(i -> result[i] == 0) +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1490995613000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -26,9 +26,9 @@ + @Slf4j + public class UserExport { + +- private UserDao userDao = DBIProvider.getDao(UserDao.class); + private static final int NUMBER_THREADS = 4; +- private ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); ++ private final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); ++ private final UserDao userDao = DBIProvider.getDao(UserDao.class); + + @Value + public static class FailedEmail { +@@ -74,7 +74,7 @@ + chunk.add(user); + if (chunk.size() == chunkSize) { + futures.add(submit(chunk)); +- chunk.clear(); ++ chunk = new ArrayList<>(chunkSize); + id = userDao.getSeqAndSkip(chunkSize); + } + } +@@ -98,7 +98,7 @@ + + private ChunkFuture submit(List chunk) { + ChunkFuture chunkFuture = new ChunkFuture(chunk, +- executorService.submit(() -> userDao.insertAndGetAlreadyPresent(chunk)) ++ executorService.submit(() -> userDao.insertAndGetConflictEmails(chunk)) + ); + log.info("Submit " + chunkFuture.emailRange); + return chunkFuture; diff --git a/patches/lesson05/5_8_fix_share_ThymeleafListener.patch b/patches/lesson05/5_8_fix_share_ThymeleafListener.patch new file mode 100644 index 000000000..4c26c9869 --- /dev/null +++ b/patches/lesson05/5_8_fix_share_ThymeleafListener.patch @@ -0,0 +1,63 @@ +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java (date 1491066006000) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java (revision ) +@@ -1,9 +1,7 @@ + package ru.javaops.masterjava.webapp; + + import com.google.common.collect.ImmutableMap; +-import org.thymeleaf.TemplateEngine; + import org.thymeleaf.context.WebContext; +-import ru.javaops.masterjava.common.web.ThymeleafUtil; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + +@@ -14,6 +12,8 @@ + import javax.servlet.http.HttpServletResponse; + import java.io.IOException; + ++import static ru.javaops.masterjava.common.web.ThymeleafListener.engine; ++ + @WebServlet("") + public class UsersServlet extends HttpServlet { + private UserDao userDao = DBIProvider.getDao(UserDao.class); +@@ -22,7 +22,6 @@ + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + final WebContext webContext = new WebContext(req, resp, req.getServletContext(), req.getLocale(), + ImmutableMap.of("users", userDao.getWithLimit(20))); +- final TemplateEngine engine = ThymeleafUtil.getTemplateEngine(getServletContext()); + engine.process("users", webContext, resp.getWriter()); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java (date 1491066006000) ++++ web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafListener.java (revision ) +@@ -1,7 +1,6 @@ +-package ru.javaops.masterjava.export; ++package ru.javaops.masterjava.common.web; + + import org.thymeleaf.TemplateEngine; +-import ru.javaops.masterjava.common.web.ThymeleafUtil; + + import javax.servlet.ServletContextEvent; + import javax.servlet.ServletContextListener; +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1491066006000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (revision ) +@@ -15,7 +15,7 @@ + import java.io.InputStream; + import java.util.List; + +-import static ru.javaops.masterjava.export.ThymeleafListener.engine; ++import static ru.javaops.masterjava.common.web.ThymeleafListener.engine; + + @WebServlet("/") + @MultipartConfig diff --git a/patches/lesson06/6_1_HW5_model_sql.patch b/patches/lesson06/6_1_HW5_model_sql.patch new file mode 100644 index 000000000..0a72c3271 --- /dev/null +++ b/patches/lesson06/6_1_HW5_model_sql.patch @@ -0,0 +1,290 @@ +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/City.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/City.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/City.java (revision ) +@@ -0,0 +1,21 @@ ++package ru.javaops.masterjava.persist.model; ++ ++import lombok.*; ++ ++@Data ++@EqualsAndHashCode(callSuper = true) ++@RequiredArgsConstructor ++@NoArgsConstructor ++@ToString(callSuper = true) ++public class City extends BaseEntity { ++ ++ @NonNull ++ private String ref; ++ @NonNull ++ private String name; ++ ++ public City(Integer id, String ref, String name) { ++ this(ref, name); ++ this.id = id; ++ } ++} +\ No newline at end of file +Index: config_templates/sql/001_add_city.sql +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/001_add_city.sql (revision ) ++++ config_templates/sql/001_add_city.sql (revision ) +@@ -0,0 +1,10 @@ ++CREATE SEQUENCE common_seq START 100000; ++ ++CREATE TABLE city ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ ref TEXT UNIQUE, ++ name TEXT NOT NULL ++); ++ ++ALTER TABLE users ++ ADD COLUMN city_id INTEGER REFERENCES city (id); +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java (revision ) +@@ -0,0 +1,21 @@ ++package ru.javaops.masterjava.persist.model; ++ ++import com.bertoncelj.jdbi.entitymapper.Column; ++import lombok.*; ++ ++@Data ++@EqualsAndHashCode(callSuper = true) ++@RequiredArgsConstructor ++@NoArgsConstructor ++@ToString(callSuper = true) ++public class Group extends BaseEntity { ++ ++ @NonNull private String name; ++ @NonNull private GroupType type; ++ @NonNull @Column("project_id") private int projectId; ++ ++ public Group(Integer id, String name, GroupType type, int projectId) { ++ this(name, type, projectId); ++ this.id = id; ++ } ++} +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java (revision ) +@@ -0,0 +1,12 @@ ++package ru.javaops.masterjava.persist.model; ++ ++import com.bertoncelj.jdbi.entitymapper.Column; ++import lombok.*; ++ ++@Data ++@RequiredArgsConstructor ++@NoArgsConstructor ++public class UserGroup { ++ @NonNull @Column("user_id") private Integer userId; ++ @NonNull @Column("group_id") private Integer groupId; ++} +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision b77b7479e8e01d0eb7b3264d7ac986220f1b7951) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -50,7 +50,7 @@ + public abstract List getWithLimit(@Bind int limit); + + // http://stackoverflow.com/questions/13223820/postgresql-delete-all-content +- @SqlUpdate("TRUNCATE users") ++ @SqlUpdate("TRUNCATE users CASCADE") + @Override + public abstract void clean(); + +Index: config_templates/sql/databaseChangeLog.sql +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/databaseChangeLog.sql (revision ) ++++ config_templates/sql/databaseChangeLog.sql (revision ) +@@ -0,0 +1,35 @@ ++--liquibase formatted sql ++ ++--changeset gkislin:1 ++CREATE SEQUENCE common_seq START 100000; ++ ++CREATE TABLE city ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ ref TEXT UNIQUE, ++ name TEXT NOT NULL ++); ++ ++ALTER TABLE users ++ ADD COLUMN city_id INTEGER REFERENCES city (id); ++ ++--changeset gkislin:2 ++CREATE TABLE project ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ name TEXT NOT NULL UNIQUE, ++ description TEXT ++); ++ ++CREATE TYPE GROUP_TYPE AS ENUM ('REGISTERING', 'CURRENT', 'FINISHED'); ++ ++CREATE TABLE groups ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ name TEXT NOT NULL UNIQUE, ++ type GROUP_TYPE NOT NULL, ++ project_id INTEGER NOT NULL REFERENCES project (id) ++); ++ ++CREATE TABLE user_group ( ++ user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, ++ group_id INTEGER NOT NULL REFERENCES groups (id), ++ CONSTRAINT users_group_idx UNIQUE (user_id, group_id) ++); +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (revision b77b7479e8e01d0eb7b3264d7ac986220f1b7951) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (revision ) +@@ -4,9 +4,10 @@ + import lombok.*; + + @Data +-@RequiredArgsConstructor + @EqualsAndHashCode(callSuper = true) ++@RequiredArgsConstructor + @NoArgsConstructor ++@ToString(callSuper = true) + public class User extends BaseEntity { + @Column("full_name") + private @NonNull String fullName; +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java (revision b77b7479e8e01d0eb7b3264d7ac986220f1b7951) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java (revision ) +@@ -1,9 +1,6 @@ + package ru.javaops.masterjava.persist.model; + +-import lombok.AllArgsConstructor; +-import lombok.Getter; +-import lombok.NoArgsConstructor; +-import lombok.Setter; ++import lombok.*; + + /** + * gkislin +@@ -11,6 +8,7 @@ + */ + @NoArgsConstructor + @AllArgsConstructor ++@ToString + abstract public class BaseEntity { + + @Getter +Index: config_templates/sql/lb_apply.bat +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/lb_apply.bat (revision ) ++++ config_templates/sql/lb_apply.bat (revision ) +@@ -0,0 +1,8 @@ ++set LB_HOME=c:\java\liquibase-3.5.3 ++call %LB_HOME%\liquibase.bat --driver=org.postgresql.Driver ^ ++--classpath=%LB_HOME%\lib ^ ++--changeLogFile=databaseChangeLog.sql ^ ++--url="jdbc:postgresql://localhost:5432/masterjava" ^ ++--username=user ^ ++--password=password ^ ++migrate +\ No newline at end of file +Index: config_templates/sql/002_add_projects.sql +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/002_add_projects.sql (revision ) ++++ config_templates/sql/002_add_projects.sql (revision ) +@@ -0,0 +1,20 @@ ++CREATE TABLE project ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ name TEXT NOT NULL UNIQUE, ++ description TEXT ++); ++ ++CREATE TYPE group_type AS ENUM ('REGISTERING', 'CURRENT', 'FINISHED'); ++ ++CREATE TABLE groups ( ++ id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), ++ name TEXT NOT NULL UNIQUE, ++ type group_type NOT NULL, ++ project_id INTEGER NOT NULL REFERENCES project (id) ++); ++ ++CREATE TABLE user_group ( ++ user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, ++ group_id INTEGER NOT NULL REFERENCES groups (id), ++ CONSTRAINT users_group_idx UNIQUE (user_id, group_id) ++); +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java (revision ) +@@ -0,0 +1,19 @@ ++package ru.javaops.masterjava.persist.model; ++ ++import lombok.*; ++ ++@Data ++@EqualsAndHashCode(callSuper = true) ++@RequiredArgsConstructor ++@NoArgsConstructor ++@ToString(callSuper = true) ++public class Project extends BaseEntity { ++ ++ @NonNull private String name; ++ @NonNull private String description; ++ ++ public Project(Integer id, String name, String description) { ++ this(name, description); ++ this.id = id; ++ } ++} +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java (revision ) +@@ -0,0 +1,7 @@ ++package ru.javaops.masterjava.persist.model; ++ ++public enum GroupType { ++ REGISTERING, ++ CURRENT, ++ FINISHED; ++} diff --git a/patches/lesson06/6_2_HW5_dao_test.patch b/patches/lesson06/6_2_HW5_dao_test.patch new file mode 100644 index 000000000..d211ddf09 --- /dev/null +++ b/patches/lesson06/6_2_HW5_dao_test.patch @@ -0,0 +1,698 @@ +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java (revision ) +@@ -0,0 +1,37 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import one.util.streamex.StreamEx; ++import org.skife.jdbi.v2.sqlobject.BindBean; ++import org.skife.jdbi.v2.sqlobject.GetGeneratedKeys; ++import org.skife.jdbi.v2.sqlobject.SqlQuery; ++import org.skife.jdbi.v2.sqlobject.SqlUpdate; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.model.Group; ++ ++import java.util.List; ++import java.util.Map; ++ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class GroupDao implements AbstractDao { ++ ++ @SqlUpdate("TRUNCATE groups CASCADE ") ++ @Override ++ public abstract void clean(); ++ ++ @SqlQuery("SELECT * FROM groups ORDER BY name") ++ public abstract List getAll(); ++ ++ public Map getAsMap() { ++ return StreamEx.of(getAll()).toMap(Group::getName, g -> g); ++ } ++ ++ @SqlUpdate("INSERT INTO groups (name, type, project_id) VALUES (:name, CAST(:type AS group_type), :projectId)") ++ @GetGeneratedKeys ++ public abstract int insertGeneratedId(@BindBean Group groups); ++ ++ public void insert(Group groups) { ++ int id = insertGeneratedId(groups); ++ groups.setId(id); ++ } ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java (revision ) +@@ -0,0 +1,30 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import org.junit.Before; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.ProjectTestData; ++import ru.javaops.masterjava.persist.model.Project; ++ ++import java.util.Map; ++ ++import static org.junit.Assert.assertEquals; ++import static ru.javaops.masterjava.persist.ProjectTestData.PROJECTS; ++ ++public class ProjectDaoTest extends AbstractDaoTest { ++ ++ public ProjectDaoTest() { ++ super(ProjectDao.class); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ ProjectTestData.setUp(); ++ } ++ ++ @Test ++ public void getAll() throws Exception { ++ final Map projects = dao.getAsMap(); ++ assertEquals(PROJECTS, projects); ++ System.out.println(projects.values()); ++ } ++} +\ No newline at end of file +Index: persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java (revision ) +@@ -0,0 +1,45 @@ ++package ru.javaops.masterjava.persist; ++ ++import ru.javaops.masterjava.persist.dao.UserGroupDao; ++import ru.javaops.masterjava.persist.model.UserGroup; ++ ++import java.util.List; ++import java.util.Set; ++ ++import static ru.javaops.masterjava.persist.dao.UserGroupDao.toUserGroups; ++import static ru.javaops.masterjava.persist.GroupTestData.*; ++ ++/** ++ * gkislin ++ * 14.11.2016 ++ */ ++public class UserGroupTestData { ++ ++ public static List USER_GROUPS; ++ ++ public static void init() { ++ UserTestData.init(); ++ UserTestData.setUp(); ++ ++ GroupTestData.init(); ++ GroupTestData.setUp(); ++ ++ USER_GROUPS = toUserGroups(UserTestData.ADMIN.getId(), TOPJAVA_07_ID, TOPJAVA_08_ID, MASTERJAVA_01_ID); ++ USER_GROUPS.addAll(toUserGroups(UserTestData.FULL_NAME.getId(), TOPJAVA_07_ID, MASTERJAVA_01_ID)); ++ USER_GROUPS.addAll(toUserGroups(UserTestData.USER1.getId(), TOPJAVA_06_ID, MASTERJAVA_01_ID)); ++ USER_GROUPS.add(new UserGroup(UserTestData.USER2.getId(), MASTERJAVA_01_ID)); ++ USER_GROUPS.add(new UserGroup(UserTestData.USER3.getId(), MASTERJAVA_01_ID)); ++ } ++ ++ public static void setUp() { ++ UserGroupDao dao = DBIProvider.getDao(UserGroupDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ dao.insertBatch(USER_GROUPS); ++ }); ++ } ++ ++ public static Set getByGroupId(int groupId) { ++ return UserGroupDao.getByGroupId(groupId, USER_GROUPS); ++ } ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java (revision ) +@@ -0,0 +1,32 @@ ++package ru.javaops.masterjava.persist; ++ ++import com.google.common.collect.ImmutableMap; ++import ru.javaops.masterjava.persist.dao.ProjectDao; ++import ru.javaops.masterjava.persist.model.Project; ++ ++import java.util.Map; ++ ++/** ++ * gkislin ++ * 14.11.2016 ++ */ ++public class ProjectTestData { ++ public static final Project TOPJAVA = new Project("topjava", "Topjava"); ++ public static final Project MASTERJAVA = new Project("masterjava", "Masterjava"); ++ public static final Map PROJECTS = ImmutableMap.of( ++ TOPJAVA.getName(), TOPJAVA, ++ MASTERJAVA.getName(), MASTERJAVA); ++ ++ public static int TOPJAVA_ID; ++ public static int MASTERJAVA_ID; ++ ++ public static void setUp() { ++ ProjectDao dao = DBIProvider.getDao(ProjectDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ PROJECTS.values().forEach(dao::insert); ++ }); ++ TOPJAVA_ID = TOPJAVA.getId(); ++ MASTERJAVA_ID = MASTERJAVA.getId(); ++ } ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java (revision ) +@@ -0,0 +1,39 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import org.junit.Assert; ++import org.junit.Before; ++import org.junit.BeforeClass; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.UserGroupTestData; ++ ++import java.util.Set; ++ ++import static ru.javaops.masterjava.persist.GroupTestData.MASTERJAVA_01_ID; ++import static ru.javaops.masterjava.persist.GroupTestData.TOPJAVA_07_ID; ++import static ru.javaops.masterjava.persist.UserGroupTestData.getByGroupId; ++ ++public class UserGroupDaoTest extends AbstractDaoTest { ++ ++ public UserGroupDaoTest() { ++ super(UserGroupDao.class); ++ } ++ ++ @BeforeClass ++ public static void init() throws Exception { ++ UserGroupTestData.init(); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ UserGroupTestData.setUp(); ++ } ++ ++ @Test ++ public void getAll() throws Exception { ++ Set userIds = dao.getUserIds(MASTERJAVA_01_ID); ++ Assert.assertEquals(getByGroupId(MASTERJAVA_01_ID), userIds); ++ ++ userIds = dao.getUserIds(TOPJAVA_07_ID); ++ Assert.assertEquals(getByGroupId(TOPJAVA_07_ID), userIds); ++ } ++} +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java (revision ) +@@ -0,0 +1,38 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import one.util.streamex.StreamEx; ++import org.skife.jdbi.v2.sqlobject.*; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.model.UserGroup; ++ ++import java.util.List; ++import java.util.Set; ++ ++/** ++ * gkislin ++ * 27.10.2016 ++ *

++ *

++ */ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class UserGroupDao implements AbstractDao { ++ ++ @SqlUpdate("TRUNCATE user_group CASCADE") ++ @Override ++ public abstract void clean(); ++ ++ @SqlBatch("INSERT INTO user_group (user_id, group_id) VALUES (:userId, :groupId)") ++ public abstract void insertBatch(@BindBean List userGroups); ++ ++ @SqlQuery("SELECT user_id FROM user_group WHERE group_id=:it") ++ public abstract Set getUserIds(@Bind int groupId); ++ ++ public static List toUserGroups(int userId, Integer... groupIds) { ++ return StreamEx.of(groupIds).map(groupId -> new UserGroup(userId, groupId)).toList(); ++ } ++ ++ public static Set getByGroupId(int groupId, List userGroups) { ++ return StreamEx.of(userGroups).filter(ug -> ug.getGroupId() == groupId).map(UserGroup::getUserId).toSet(); ++ } ++} +\ No newline at end of file +Index: persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java (revision ) +@@ -0,0 +1,32 @@ ++package ru.javaops.masterjava.persist; ++ ++import com.google.common.collect.ImmutableMap; ++import ru.javaops.masterjava.persist.dao.CityDao; ++import ru.javaops.masterjava.persist.model.City; ++ ++import java.util.Map; ++ ++/** ++ * gkislin ++ * 14.11.2016 ++ */ ++public class CityTestData { ++ public static final City KIEV = new City("kiv", "Киев"); ++ public static final City MINSK = new City("mnsk", "Минск"); ++ public static final City MOSCOW = new City("mow", "Москва"); ++ public static final City SPB = new City("spb", "Санкт-Петербург"); ++ ++ public static final Map CITIES = ImmutableMap.of( ++ KIEV.getRef(), KIEV, ++ MINSK.getRef(), MINSK, ++ MOSCOW.getRef(), MOSCOW, ++ SPB.getRef(), SPB); ++ ++ public static void setUp() { ++ CityDao dao = DBIProvider.getDao(CityDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ CITIES.values().forEach(dao::insert); ++ }); ++ } ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java (revision ) +@@ -0,0 +1,36 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import org.junit.Before; ++import org.junit.BeforeClass; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.GroupTestData; ++import ru.javaops.masterjava.persist.model.Group; ++ ++import java.util.Map; ++ ++import static org.junit.Assert.assertEquals; ++import static ru.javaops.masterjava.persist.GroupTestData.GROUPS; ++ ++public class GroupDaoTest extends AbstractDaoTest { ++ ++ public GroupDaoTest() { ++ super(GroupDao.class); ++ } ++ ++ @BeforeClass ++ public static void init() throws Exception { ++ GroupTestData.init(); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ GroupTestData.setUp(); ++ } ++ ++ @Test ++ public void getAll() throws Exception { ++ final Map projects = dao.getAsMap(); ++ assertEquals(GROUPS, projects); ++ System.out.println(projects.values()); ++ } ++} +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java (revision ) +@@ -0,0 +1,38 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import one.util.streamex.StreamEx; ++import org.skife.jdbi.v2.sqlobject.*; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.model.City; ++ ++import java.util.Collection; ++import java.util.List; ++import java.util.Map; ++ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class CityDao implements AbstractDao { ++ ++ @SqlUpdate("TRUNCATE city CASCADE ") ++ @Override ++ public abstract void clean(); ++ ++ @SqlQuery("SELECT * FROM city ORDER BY name") ++ public abstract List getAll(); ++ ++ public Map getAsMap() { ++ return StreamEx.of(getAll()).toMap(City::getRef, c -> c); ++ } ++ ++ @SqlUpdate("INSERT INTO city (ref, name) VALUES (:ref, :name)") ++ @GetGeneratedKeys ++ public abstract int insertGeneratedId(@BindBean City city); ++ ++ public void insert(City city) { ++ int id = insertGeneratedId(city); ++ city.setId(id); ++ } ++ ++ @SqlBatch("INSERT INTO city (ref, name) VALUES (:ref, :name)") ++ public abstract void insertBatch(@BindBean Collection cities); ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java (revision ) +@@ -0,0 +1,55 @@ ++package ru.javaops.masterjava.persist; ++ ++import com.google.common.collect.ImmutableMap; ++import ru.javaops.masterjava.persist.dao.GroupDao; ++import ru.javaops.masterjava.persist.model.Group; ++ ++import java.util.Map; ++ ++import static ru.javaops.masterjava.persist.ProjectTestData.MASTERJAVA_ID; ++import static ru.javaops.masterjava.persist.ProjectTestData.TOPJAVA_ID; ++import static ru.javaops.masterjava.persist.model.GroupType.CURRENT; ++import static ru.javaops.masterjava.persist.model.GroupType.FINISHED; ++ ++/** ++ * gkislin ++ * 14.11.2016 ++ */ ++public class GroupTestData { ++ public static Group TOPJAVA_06; ++ public static Group TOPJAVA_07; ++ public static Group TOPJAVA_08; ++ public static Group MASTERJAVA_01; ++ public static Map GROUPS; ++ ++ public static int TOPJAVA_06_ID; ++ public static int TOPJAVA_07_ID; ++ public static int TOPJAVA_08_ID; ++ public static int MASTERJAVA_01_ID; ++ ++ ++ public static void init() { ++ ProjectTestData.setUp(); ++ TOPJAVA_06 = new Group("topjava06", FINISHED, TOPJAVA_ID); ++ TOPJAVA_07 = new Group("topjava07", FINISHED, TOPJAVA_ID); ++ TOPJAVA_08 = new Group("topjava08", CURRENT, TOPJAVA_ID); ++ MASTERJAVA_01 = new Group("masterjava01", CURRENT, MASTERJAVA_ID); ++ GROUPS = ImmutableMap.of( ++ TOPJAVA_06.getName(), TOPJAVA_06, ++ TOPJAVA_07.getName(), TOPJAVA_07, ++ TOPJAVA_08.getName(), TOPJAVA_08, ++ MASTERJAVA_01.getName(), MASTERJAVA_01); ++ } ++ ++ public static void setUp() { ++ GroupDao dao = DBIProvider.getDao(GroupDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ GROUPS.values().forEach(dao::insert); ++ }); ++ TOPJAVA_06_ID = TOPJAVA_06.getId(); ++ TOPJAVA_07_ID = TOPJAVA_07.getId(); ++ TOPJAVA_08_ID = TOPJAVA_08.getId(); ++ MASTERJAVA_01_ID = MASTERJAVA_01.getId(); ++ } ++} +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java (revision ) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java (revision ) +@@ -0,0 +1,30 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import org.junit.Before; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.CityTestData; ++import ru.javaops.masterjava.persist.model.City; ++ ++import java.util.Map; ++ ++import static org.junit.Assert.assertEquals; ++import static ru.javaops.masterjava.persist.CityTestData.CITIES; ++ ++public class CityDaoTest extends AbstractDaoTest { ++ ++ public CityDaoTest() { ++ super(CityDao.class); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ CityTestData.setUp(); ++ } ++ ++ @Test ++ public void getAll() throws Exception { ++ final Map cities = dao.getAsMap(); ++ assertEquals(CITIES, cities); ++ System.out.println(cities.values()); ++ } ++} +\ No newline at end of file +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java (revision ) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java (revision ) +@@ -0,0 +1,37 @@ ++package ru.javaops.masterjava.persist.dao; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import one.util.streamex.StreamEx; ++import org.skife.jdbi.v2.sqlobject.BindBean; ++import org.skife.jdbi.v2.sqlobject.GetGeneratedKeys; ++import org.skife.jdbi.v2.sqlobject.SqlQuery; ++import org.skife.jdbi.v2.sqlobject.SqlUpdate; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.model.Project; ++ ++import java.util.List; ++import java.util.Map; ++ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class ProjectDao implements AbstractDao { ++ ++ @SqlUpdate("TRUNCATE project CASCADE ") ++ @Override ++ public abstract void clean(); ++ ++ @SqlQuery("SELECT * FROM project ORDER BY name") ++ public abstract List getAll(); ++ ++ public Map getAsMap() { ++ return StreamEx.of(getAll()).toMap(Project::getName, g -> g); ++ } ++ ++ @SqlUpdate("INSERT INTO project (name, description) VALUES (:name, :description)") ++ @GetGeneratedKeys ++ public abstract int insertGeneratedId(@BindBean Project project); ++ ++ public void insert(Project project) { ++ int id = insertGeneratedId(project); ++ project.setId(id); ++ } ++} +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1491594064000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -39,11 +39,11 @@ + return id; + } + +- @SqlUpdate("INSERT INTO users (full_name, email, flag) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG)) ") ++ @SqlUpdate("INSERT INTO users (full_name, email, flag, city_id) VALUES (:fullName, :email, CAST(:flag AS USER_FLAG), :cityId) ") + @GetGeneratedKeys + abstract int insertGeneratedId(@BindBean User user); + +- @SqlUpdate("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG)) ") ++ @SqlUpdate("INSERT INTO users (id, full_name, email, flag, city_id) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG), :cityId) ") + abstract void insertWitId(@BindBean User user); + + @SqlQuery("SELECT * FROM users ORDER BY full_name, email LIMIT :it") +@@ -55,7 +55,7 @@ + public abstract void clean(); + + // https://habrahabr.ru/post/264281/ +- @SqlBatch("INSERT INTO users (id, full_name, email, flag) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG))" + ++ @SqlBatch("INSERT INTO users (id, full_name, email, flag, city_id) VALUES (:id, :fullName, :email, CAST(:flag AS USER_FLAG), :cityId)" + + "ON CONFLICT DO NOTHING") + // "ON CONFLICT (email) DO UPDATE SET full_name=:fullName, flag=CAST(:flag AS USER_FLAG)") + public abstract int[] insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); +Index: persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (date 1491594064000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/model/User.java (revision ) +@@ -13,9 +13,11 @@ + private @NonNull String fullName; + private @NonNull String email; + private @NonNull UserFlag flag; ++ @Column("city_id") ++ private @NonNull Integer cityId; + +- public User(Integer id, String fullName, String email, UserFlag flag) { +- this(fullName, email, flag); ++ public User(Integer id, String fullName, String email, UserFlag flag, Integer cityId) { ++ this(fullName, email, flag, cityId); + this.id=id; + } + } +\ No newline at end of file +Index: persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java (date 1491594064000) ++++ persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java (revision ) +@@ -1,17 +1,32 @@ + package ru.javaops.masterjava.persist.dao; + ++import lombok.extern.slf4j.Slf4j; ++import org.junit.Rule; ++import org.junit.rules.TestRule; ++import org.junit.rules.TestWatcher; ++import org.junit.runner.Description; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.DBITestProvider; + +-/** +- * gkislin +- * 27.10.2016 +- */ ++@Slf4j + public abstract class AbstractDaoTest { + static { + DBITestProvider.initDBI(); + } + ++ @Rule ++ public TestRule testWatcher = new TestWatcher() { ++ @Override ++ protected void starting(Description description) { ++ log.info("\n\n+++ Start " + description.getDisplayName()); ++ } ++ ++ @Override ++ protected void finished(Description description) { ++ log.info("\n+++ Finish " + description.getDisplayName() + '\n'); ++ } ++ }; ++ + protected DAO dao; + + protected AbstractDaoTest(Class daoClass) { +Index: persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java (date 1491594064000) ++++ persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java (revision ) +@@ -7,6 +7,8 @@ + + import java.util.List; + ++import static ru.javaops.masterjava.persist.CityTestData.*; ++ + /** + * gkislin + * 14.11.2016 +@@ -21,12 +23,13 @@ + public static List FIST5_USERS; + + public static void init() { +- ADMIN = new User("Admin", "admin@javaops.ru", UserFlag.superuser); +- DELETED = new User("Deleted", "deleted@yandex.ru", UserFlag.deleted); +- FULL_NAME = new User("Full Name", "gmail@gmail.com", UserFlag.active); +- USER1 = new User("User1", "user1@gmail.com", UserFlag.active); +- USER2 = new User("User2", "user2@yandex.ru", UserFlag.active); +- USER3 = new User("User3", "user3@yandex.ru", UserFlag.active); ++ CityTestData.setUp(); ++ ADMIN = new User("Admin", "admin@javaops.ru", UserFlag.superuser, SPB.getId()); ++ DELETED = new User("Deleted", "deleted@yandex.ru", UserFlag.deleted, SPB.getId()); ++ FULL_NAME = new User("Full Name", "gmail@gmail.com", UserFlag.active, KIEV.getId()); ++ USER1 = new User("User1", "user1@gmail.com", UserFlag.active, MOSCOW.getId()); ++ USER2 = new User("User2", "user2@yandex.ru", UserFlag.active, KIEV.getId()); ++ USER3 = new User("User3", "user3@yandex.ru", UserFlag.active, MINSK.getId()); + FIST5_USERS = ImmutableList.of(ADMIN, DELETED, FULL_NAME, USER1, USER2); + } + +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1491594064000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (revision ) +@@ -70,7 +70,7 @@ + final String email = processor.getAttribute("email"); + final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); + final String fullName = processor.getReader().getElementText(); +- final User user = new User(id++, fullName, email, flag); ++ final User user = new User(id++, fullName, email, flag, null); + chunk.add(user); + if (chunk.size() == chunkSize) { + futures.add(submit(chunk)); diff --git a/patches/lesson06/6_3_HW5_add_PayloadImporter.patch b/patches/lesson06/6_3_HW5_add_PayloadImporter.patch new file mode 100644 index 000000000..86f672e71 --- /dev/null +++ b/patches/lesson06/6_3_HW5_add_PayloadImporter.patch @@ -0,0 +1,134 @@ +Index: web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (revision 87cf39b88559e43665cc79d2acb9c0b41bc15328) ++++ web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (revision 87cf39b88559e43665cc79d2acb9c0b41bc15328) +@@ -0,0 +1,28 @@ ++package ru.javaops.masterjava.export; ++ ++import lombok.Value; ++import ru.javaops.masterjava.xml.util.StaxStreamProcessor; ++ ++import javax.xml.stream.XMLStreamException; ++import java.io.InputStream; ++import java.util.List; ++ ++public class PayloadImporter { ++ private final UserImporter userImporter = new UserImporter(); ++ ++ @Value ++ public static class FailedEmail { ++ public String emailOrRange; ++ public String reason; ++ ++ @Override ++ public String toString() { ++ return emailOrRange + " : " + reason; ++ } ++ } ++ ++ public List process(InputStream is, int chunkSize) throws XMLStreamException { ++ final StaxStreamProcessor processor = new StaxStreamProcessor(is); ++ return userImporter.process(processor, chunkSize); ++ } ++} +Index: web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1491596252000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java (date 1491596439000) +@@ -23,7 +23,7 @@ + public class UploadServlet extends HttpServlet { + private static final int CHUNK_SIZE = 2000; + +- private final UserExport userExport = new UserExport(); ++ private final PayloadImporter payloadImporter = new PayloadImporter(); + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { +@@ -42,7 +42,7 @@ + } else { + Part filePart = req.getPart("fileToUpload"); + try (InputStream is = filePart.getInputStream()) { +- List failed = userExport.process(is, chunkSize); ++ List failed = payloadImporter.process(is, chunkSize); + log.info("Failed users: " + failed); + final WebContext webContext = + new WebContext(req, resp, req.getServletContext(), req.getLocale(), +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java (date 1491596252000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (date 1491596439000) +@@ -1,8 +1,8 @@ + package ru.javaops.masterjava.export; + +-import lombok.Value; + import lombok.extern.slf4j.Slf4j; + import one.util.streamex.StreamEx; ++import ru.javaops.masterjava.export.PayloadImporter.FailedEmail; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.User; +@@ -11,7 +11,6 @@ + + import javax.xml.stream.XMLStreamException; + import javax.xml.stream.events.XMLEvent; +-import java.io.InputStream; + import java.util.ArrayList; + import java.util.List; + import java.util.concurrent.Callable; +@@ -24,24 +23,13 @@ + * 14.10.2016 + */ + @Slf4j +-public class UserExport { ++public class UserImporter { + + private static final int NUMBER_THREADS = 4; + private final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + private final UserDao userDao = DBIProvider.getDao(UserDao.class); + +- @Value +- public static class FailedEmail { +- public String emailOrRange; +- public String reason; +- +- @Override +- public String toString() { +- return emailOrRange + " : " + reason; +- } +- } +- +- public List process(final InputStream is, int chunkSize) throws XMLStreamException { ++ public List process(StaxStreamProcessor processor, int chunkSize) throws XMLStreamException { + log.info("Start proseccing with chunkSize=" + chunkSize); + + return new Callable>() { +@@ -64,7 +52,6 @@ + + int id = userDao.getSeqAndSkip(chunkSize); + List chunk = new ArrayList<>(chunkSize); +- final StaxStreamProcessor processor = new StaxStreamProcessor(is); + + while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { + final String email = processor.getAttribute("email"); +Index: web/export/src/main/webapp/WEB-INF/templates/result.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/webapp/WEB-INF/templates/result.html (date 1491596252000) ++++ web/export/src/main/webapp/WEB-INF/templates/result.html (date 1491596439000) +@@ -7,7 +7,7 @@ +

Export XML

+

Failed users

+
    +- ++ +
  • +
+ diff --git a/patches/lesson06/6_4_HW5_add_CityImporter.patch b/patches/lesson06/6_4_HW5_add_CityImporter.patch new file mode 100644 index 000000000..fb97385ed --- /dev/null +++ b/patches/lesson06/6_4_HW5_add_CityImporter.patch @@ -0,0 +1,152 @@ +Index: web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java (revision ) +@@ -0,0 +1,38 @@ ++package ru.javaops.masterjava.export; ++ ++import lombok.extern.slf4j.Slf4j; ++import lombok.val; ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.persist.dao.CityDao; ++import ru.javaops.masterjava.persist.model.City; ++import ru.javaops.masterjava.xml.util.StaxStreamProcessor; ++ ++import javax.xml.stream.XMLStreamException; ++import javax.xml.stream.events.XMLEvent; ++import java.util.ArrayList; ++import java.util.Map; ++ ++/** ++ * gkislin ++ * 15.11.2016 ++ */ ++@Slf4j ++public class CityImporter { ++ private final CityDao cityDao = DBIProvider.getDao(CityDao.class); ++ public Map process(StaxStreamProcessor processor) throws XMLStreamException { ++ val map = cityDao.getAsMap(); ++ val newCities = new ArrayList(); ++ String element; ++ ++ while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, "City", "Users")) != null) { ++ if (element.equals("Users")) break; ++ val ref = processor.getAttribute("id"); ++ if (!map.containsKey(ref)) { ++ newCities.add(new City(null, ref, processor.getText())); ++ } ++ } ++ log.info("Insert batch " + newCities); ++ cityDao.insertBatch(newCities); ++ return cityDao.getAsMap(); ++ } ++} +\ No newline at end of file +Index: web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (date 1491596439000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (revision ) +@@ -1,6 +1,7 @@ + package ru.javaops.masterjava.export; + + import lombok.Value; ++import lombok.val; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; + + import javax.xml.stream.XMLStreamException; +@@ -8,6 +9,7 @@ + import java.util.List; + + public class PayloadImporter { ++ private final CityImporter cityImporter = new CityImporter(); + private final UserImporter userImporter = new UserImporter(); + + @Value +@@ -23,6 +25,7 @@ + + public List process(InputStream is, int chunkSize) throws XMLStreamException { + final StaxStreamProcessor processor = new StaxStreamProcessor(is); +- return userImporter.process(processor, chunkSize); ++ val cities = cityImporter.process(processor); ++ return userImporter.process(processor, cities, chunkSize); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (date 1491596439000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (revision ) +@@ -5,6 +5,7 @@ + import ru.javaops.masterjava.export.PayloadImporter.FailedEmail; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; ++import ru.javaops.masterjava.persist.model.City; + import ru.javaops.masterjava.persist.model.User; + import ru.javaops.masterjava.persist.model.UserFlag; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; +@@ -13,6 +14,7 @@ + import javax.xml.stream.events.XMLEvent; + import java.util.ArrayList; + import java.util.List; ++import java.util.Map; + import java.util.concurrent.Callable; + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; +@@ -29,7 +31,7 @@ + private final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + private final UserDao userDao = DBIProvider.getDao(UserDao.class); + +- public List process(StaxStreamProcessor processor, int chunkSize) throws XMLStreamException { ++ public List process(StaxStreamProcessor processor, Map cities, int chunkSize) throws XMLStreamException { + log.info("Start proseccing with chunkSize=" + chunkSize); + + return new Callable>() { +@@ -52,17 +54,24 @@ + + int id = userDao.getSeqAndSkip(chunkSize); + List chunk = new ArrayList<>(chunkSize); ++ List failed = new ArrayList<>(); + + while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { + final String email = processor.getAttribute("email"); +- final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); +- final String fullName = processor.getReader().getElementText(); +- final User user = new User(id++, fullName, email, flag, null); +- chunk.add(user); +- if (chunk.size() == chunkSize) { +- futures.add(submit(chunk)); +- chunk = new ArrayList<>(chunkSize); +- id = userDao.getSeqAndSkip(chunkSize); ++ String cityRef = processor.getAttribute("city"); ++ City city = cities.get(cityRef); ++ if (city == null) { ++ failed.add(new FailedEmail(email, "City '" + cityRef + "' is not present in DB")); ++ } else { ++ final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); ++ final String fullName = processor.getReader().getElementText(); ++ final User user = new User(id++, fullName, email, flag, city.getId()); ++ chunk.add(user); ++ if (chunk.size() == chunkSize) { ++ futures.add(submit(chunk)); ++ chunk = new ArrayList<>(chunkSize); ++ id = userDao.getSeqAndSkip(chunkSize); ++ } + } + } + +@@ -70,7 +79,6 @@ + futures.add(submit(chunk)); + } + +- List failed = new ArrayList<>(); + futures.forEach(cf -> { + try { + failed.addAll(StreamEx.of(cf.future.get()).map(email -> new FailedEmail(email, "already present")).toList()); diff --git a/patches/lesson06/6_5_web_services.patch b/patches/lesson06/6_5_web_services.patch new file mode 100644 index 000000000..8e54a2711 --- /dev/null +++ b/patches/lesson06/6_5_web_services.patch @@ -0,0 +1,171 @@ +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -0,0 +1,21 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import javax.jws.WebMethod; ++import javax.jws.WebParam; ++import javax.jws.WebService; ++import java.util.List; ++ ++/** ++ * gkislin ++ * 15.11.2016 ++ */ ++@WebService ++public interface MailService { ++ ++ @WebMethod ++ void sendMail( ++ @WebParam(name = "to") List to, ++ @WebParam(name = "cc") List cc, ++ @WebParam(name = "subject") String subject, ++ @WebParam(name = "body") String body); ++} +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -0,0 +1,25 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import com.google.common.collect.ImmutableList; ++ ++import javax.xml.namespace.QName; ++import javax.xml.ws.Service; ++import java.net.MalformedURLException; ++import java.net.URL; ++ ++/** ++ * User: gkislin ++ * Date: 28.05.2014 ++ */ ++public class MailServiceClient { ++ ++ public static void main(String[] args) throws MalformedURLException { ++ QName qname = new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService"); ++ Service service = Service.create( ++ new URL("http://localhost:8080/mail/mailService?wsdl"), ++ new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService")); ++ ++ MailService mailService = service.getPort(MailService.class); ++ mailService.sendMail(ImmutableList.of(new Addressee("gkislin@yandex.ru", null)), null, "Subject", "Body"); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -0,0 +1,15 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import javax.jws.WebService; ++import java.util.List; ++ ++/** ++ * gkislin ++ * 15.11.2016 ++ */ ++@WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService") ++public class MailServiceImpl implements MailService { ++ public void sendMail(List to, List cc, String subject, String body) { ++ MailSender.sendMail(to, cc, subject, body); ++ } ++} +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -0,0 +1,17 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++import lombok.Data; ++import lombok.NoArgsConstructor; ++ ++/** ++ * gkislin ++ * 15.11.2016 ++ */ ++@Data ++@AllArgsConstructor ++@NoArgsConstructor ++public class Addressee { ++ private String email; ++ private String name; ++} +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) +@@ -0,0 +1,14 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import javax.xml.ws.Endpoint; ++ ++/** ++ * User: gkislin ++ * Date: 28.05.2014 ++ */ ++public class MailServicePublisher { ++ ++ public static void main(String[] args) { ++ Endpoint.publish("http://localhost:8080/mail/mailService", new MailServiceImpl()); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -0,0 +1,16 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.extern.slf4j.Slf4j; ++ ++import java.util.List; ++ ++/** ++ * gkislin ++ * 15.11.2016 ++ */ ++@Slf4j ++public class MailSender { ++ static void sendMail(List to, List cc, String subject, String body) { ++ log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled()?"\nbody=" + body:"")); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1491596768000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (revision ) +@@ -6,7 +6,7 @@ + import java.util.concurrent.*; + import java.util.stream.Collectors; + +-public class MailService { ++public class MailServiceExecutor { + private static final String OK = "OK"; + + private static final String INTERRUPTED_BY_FAULTS_NUMBER = "+++ Interrupted by faults number"; diff --git a/patches/lesson07/7_10_send_group_bulk.patch b/patches/lesson07/7_10_send_group_bulk.patch new file mode 100644 index 000000000..986d3305b --- /dev/null +++ b/patches/lesson07/7_10_send_group_bulk.patch @@ -0,0 +1,238 @@ +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision ) +@@ -0,0 +1,22 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++import lombok.NoArgsConstructor; ++ ++@AllArgsConstructor ++@NoArgsConstructor ++public class MailResult { ++ public static final String OK = "OK"; ++ ++ private String email; ++ private String result; ++ ++ public boolean isOk() { ++ return OK.equals(result); ++ } ++ ++ @Override ++ public String toString() { ++ return '(' + email + ',' + result + ')'; ++ } ++} +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) +@@ -0,0 +1,21 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++import lombok.NoArgsConstructor; ++ ++import java.util.List; ++ ++@AllArgsConstructor ++@NoArgsConstructor ++public class GroupResult { ++ private int success; // number of successfully sent email ++ private List failed; // failed emails with causes ++ private String failedCause; // global fail cause ++ ++ @Override ++ public String toString() { ++ return "Success: " + success + '\n' + ++ "Failed: " + failed.toString() + '\n' + ++ (failedCause == null ? "" : "Failed cause" + failedCause); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (date 1492276985000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (revision ) +@@ -15,13 +15,13 @@ + private static final String INTERRUPTED_BY_TIMEOUT = "+++ Interrupted by timeout"; + private static final String INTERRUPTED_EXCEPTION = "+++ InterruptedException"; + +- private final ExecutorService mailExecutor = Executors.newFixedThreadPool(8); ++ private static final ExecutorService mailExecutor = Executors.newFixedThreadPool(8); + +- public GroupResult sendIndividual(final Set addressees, final String subject, final String body) throws Exception { ++ public static GroupResult sendBulk(final Set addressees, final String subject, final String body) { + final CompletionService completionService = new ExecutorCompletionService<>(mailExecutor); + + List> futures = StreamEx.of(addressees) +- .map(addressee -> completionService.submit(() -> MailSender.sendBulk(addressee, subject, body))) ++ .map(addressee -> completionService.submit(() -> MailSender.sendTo(addressee, subject, body))) + .toList(); + + return new Callable() { +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (date 1492276985000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) +@@ -1,14 +1,16 @@ + package ru.javaops.masterjava.service.mail; + + import lombok.AllArgsConstructor; ++import lombok.NoArgsConstructor; + + import java.util.List; + + @AllArgsConstructor ++@NoArgsConstructor + public class GroupResult { +- private final int success; // number of successfully sent email +- private final List failed; // failed emails with causes +- private final String failedCause; // global fail cause ++ private int success; // number of successfully sent email ++ private List failed; // failed emails with causes ++ private String failedCause; // global fail cause + + @Override + public String toString() { +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (date 1492276985000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -19,12 +19,12 @@ + public class MailSender { + private static final MailCaseDao MAIL_CASE_DAO = DBIProvider.getDao(MailCaseDao.class); + +- static MailResult sendBulk(Addressee to, String subject, String body) { +- val state = sendBulk(ImmutableSet.of(to), ImmutableSet.of(), subject, body); ++ static MailResult sendTo(Addressee to, String subject, String body) { ++ val state = sendToGroup(ImmutableSet.of(to), ImmutableSet.of(), subject, body); + return new MailResult(to.getEmail(), state); + } + +- static String sendBulk(Set to, Set cc, String subject, String body) { ++ static String sendToGroup(Set to, Set cc, String subject, String body) { + log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String state = MailResult.OK; + try { +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1492276985000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -7,7 +7,14 @@ + // , wsdlLocation = "WEB-INF/wsdl/mailService.wsdl" + ) + public class MailServiceImpl implements MailService { +- public void sendMail(Set to, Set cc, String subject, String body) { +- MailSender.sendBulk(to, cc, subject, body); ++ ++ @Override ++ public String sendToGroup(Set to, Set cc, String subject, String body) { ++ return MailSender.sendToGroup(to, cc, subject, body); ++ } ++ ++ @Override ++ public GroupResult sendBulk(Set to, String subject, String body) { ++ return MailServiceExecutor.sendBulk(to, subject, body); + } + } +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492276985000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -16,11 +16,11 @@ + + MailService mailService = service.getPort(MailService.class); + +- mailService.sendMail(ImmutableSet.of( ++ mailService.sendToGroup(ImmutableSet.of( + new Addressee("gkislin@javaops.ru"), + new Addressee("Bad Email ")), ImmutableSet.of(), "Subject", "Body"); + +- mailService.sendMail( ++ mailService.sendToGroup( + ImmutableSet.of(new Addressee("Григорий Кислин ")), + ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); + } +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (date 1492276985000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -4,10 +4,6 @@ + import lombok.Data; + import lombok.NoArgsConstructor; + +-/** +- * gkislin +- * 15.11.2016 +- */ + @Data + @AllArgsConstructor + @NoArgsConstructor +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1492276985000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -13,9 +13,16 @@ + public interface MailService { + + @WebMethod +- void sendMail( ++ String sendToGroup( + @WebParam(name = "to") Set to, + @WebParam(name = "cc") Set cc, + @WebParam(name = "subject") String subject, + @WebParam(name = "body") String body); ++ ++ @WebMethod ++ GroupResult sendBulk( ++ @WebParam(name = "to") Set to, ++ @WebParam(name = "subject") String subject, ++ @WebParam(name = "body") String body); ++ + } +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1492276985000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -22,6 +22,6 @@ + + public static void sendMail(final Set to, final Set cc, final String subject, final String body) { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); +- WS_CLIENT.getPort().sendMail(to, cc, subject, body); ++ WS_CLIENT.getPort().sendToGroup(to, cc, subject, body); + } + } diff --git a/patches/lesson07/7_1_HW6_MailSender.patch b/patches/lesson07/7_1_HW6_MailSender.patch new file mode 100644 index 000000000..04851754d --- /dev/null +++ b/patches/lesson07/7_1_HW6_MailSender.patch @@ -0,0 +1,203 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java (revision ) +@@ -0,0 +1,67 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import com.typesafe.config.Config; ++import org.apache.commons.mail.DefaultAuthenticator; ++import org.apache.commons.mail.Email; ++import org.apache.commons.mail.EmailException; ++import org.apache.commons.mail.HtmlEmail; ++import ru.javaops.masterjava.config.Configs; ++ ++import javax.mail.Authenticator; ++import java.nio.charset.StandardCharsets; ++ ++public class MailConfig { ++ private static final MailConfig INSTANCE = ++ new MailConfig(Configs.getConfig("mail.conf", "mail")); ++ ++ final private String host; ++ final private int port; ++ final private boolean useSSL; ++ final private boolean useTLS; ++ final private boolean debug; ++ final private String username; ++ final private Authenticator auth; ++ final private String fromName; ++ ++ private MailConfig(Config conf) { ++ host = conf.getString("host"); ++ port = conf.getInt("port"); ++ username = conf.getString("username"); ++ auth = new DefaultAuthenticator(username, conf.getString("password")); ++ useSSL = conf.getBoolean("useSSL"); ++ useTLS = conf.getBoolean("useTLS"); ++ debug = conf.getBoolean("debug"); ++ fromName = conf.getString("fromName"); ++ } ++ ++ public T prepareEmail(T email) throws EmailException { ++ email.setFrom(username, fromName); ++ email.setHostName(host); ++ if (useSSL) { ++ email.setSslSmtpPort(String.valueOf(port)); ++ } else { ++ email.setSmtpPort(port); ++ } ++ email.setSSLOnConnect(useSSL); ++ email.setStartTLSEnabled(useTLS); ++ email.setDebug(debug); ++ email.setAuthenticator(auth); ++ email.setCharset(StandardCharsets.UTF_8.name()); ++ return email; ++ } ++ ++ public static HtmlEmail createHtmlEmail() throws EmailException { ++ return INSTANCE.prepareEmail(new HtmlEmail()); ++ } ++ ++ @Override ++ public String toString() { ++ return "\nhost='" + host + '\'' + ++ "\nport=" + port + ++ "\nuseSSL=" + useSSL + ++ "\nuseTLS=" + useTLS + ++ "\ndebug=" + debug + ++ "\nusername='" + username + '\'' + ++ "\nfromName='" + fromName + '\''; ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision a7629a2af7944dae58b0e9fee486346e71097c17) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -1,6 +1,9 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.collect.ImmutableMap; + import lombok.extern.slf4j.Slf4j; ++import lombok.val; ++import org.apache.commons.mail.EmailException; + + import java.util.List; + +@@ -12,5 +15,23 @@ + public class MailSender { + static void sendMail(List to, List cc, String subject, String body) { + log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled()?"\nbody=" + body:"")); ++ try { ++ val email = MailConfig.createHtmlEmail(); ++ email.setSubject(subject); ++ email.setHtmlMsg(body); ++ for (Addressee addressee : to) { ++ email.addTo(addressee.getEmail(), addressee.getName()); ++ } ++ for (Addressee addressee : cc) { ++ email.addCc(addressee.getEmail(), addressee.getName()); ++ } ++ ++ // https://yandex.ru/blog/company/66296 ++ email.setHeaders(ImmutableMap.of("List-Unsubscribe", "")); ++ ++ email.send(); ++ } catch (EmailException e) { ++ log.error(e.getMessage(), e); ++ } + } + } +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision a7629a2af7944dae58b0e9fee486346e71097c17) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -14,12 +14,11 @@ + public class MailServiceClient { + + public static void main(String[] args) throws MalformedURLException { +- QName qname = new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService"); + Service service = Service.create( + new URL("http://localhost:8080/mail/mailService?wsdl"), + new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService")); + + MailService mailService = service.getPort(MailService.class); +- mailService.sendMail(ImmutableList.of(new Addressee("gkislin@yandex.ru", null)), null, "Subject", "Body"); ++ mailService.sendMail(ImmutableList.of(new Addressee("gkislin@javaops.ru")), ImmutableList.of(), "Subject", "Body"); + } + } +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision a7629a2af7944dae58b0e9fee486346e71097c17) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -14,4 +14,8 @@ + public class Addressee { + private String email; + private String name; ++ ++ public Addressee(String email) { ++ this(email, null); ++ } + } +Index: services/mail-service/src/main/resources/mail.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/resources/mail.conf (revision ) ++++ services/mail-service/src/main/resources/mail.conf (revision ) +@@ -0,0 +1,12 @@ ++mail { ++ host: smtp.yandex.ru ++ port: 465 ++ username: "user@yandex.ru" ++ password: password ++ useSSL: true ++ useTLS: false ++ debug: true ++ fromName: MasterJava ++} ++ ++include required(file("/apps/masterjava/config/mail.conf")) +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (revision a7629a2af7944dae58b0e9fee486346e71097c17) ++++ services/mail-service/pom.xml (revision ) +@@ -22,5 +22,21 @@ + mail-api + ${project.version} +
++ ++ org.apache.commons ++ commons-email ++ 1.4 ++ ++ ++ javax.activation ++ activation ++ ++ ++ ++ ++ javax.activation ++ activation ++ 1.1.1 ++ + + +\ No newline at end of file diff --git a/patches/lesson07/7_2_HW6_mail_history.patch b/patches/lesson07/7_2_HW6_mail_history.patch new file mode 100644 index 000000000..33508649f --- /dev/null +++ b/patches/lesson07/7_2_HW6_mail_history.patch @@ -0,0 +1,396 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java (revision ) +@@ -0,0 +1,24 @@ ++package ru.javaops.masterjava.service.mail.persist; ++ ++import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; ++import org.skife.jdbi.v2.sqlobject.*; ++import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; ++import ru.javaops.masterjava.persist.dao.AbstractDao; ++ ++import java.util.Date; ++import java.util.List; ++ ++@RegisterMapperFactory(EntityMapperFactory.class) ++public abstract class MailCaseDao implements AbstractDao { ++ ++ @SqlUpdate("TRUNCATE mail_hist") ++ @Override ++ public abstract void clean(); ++ ++ @SqlQuery("SELECT * FROM mail_hist WHERE date>=:after ORDER BY date DESC") ++ public abstract List getAfter(@Bind("after") Date date); ++ ++ @SqlUpdate("INSERT INTO mail_hist (list_to, list_cc, subject, body, state, date) VALUES (:listTo, :listCc, :subject, :body, :state, :date)") ++ @GetGeneratedKeys ++ public abstract int insert(@BindBean MailCase mails); ++} +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java (revision ) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java (revision ) +@@ -0,0 +1,47 @@ ++package ru.javaops.masterjava.service.mail.persist; ++ ++import com.google.common.collect.ImmutableList; ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.service.mail.Addressee; ++ ++import java.time.Duration; ++import java.time.Instant; ++import java.util.Date; ++import java.util.List; ++ ++/** ++ * gkislin ++ * 26.11.2016 ++ */ ++public class MailCaseTestData { ++ private static final Instant now = Instant.now(); ++ static final Date DATE_FROM = Date.from(now.minus(Duration.ofDays(1))); ++ ++ static final List MAIL_CASES = ImmutableList.of( ++ MailCase.of( ++ ImmutableList.of( ++ new Addressee("ИмяTo1 Фамилия1 "), ++ new Addressee("Имя2 Фамилия2 ")), ++ ImmutableList.of( ++ new Addressee("ИмяCc1 Фамилия1 "), ++ new Addressee("ИмяCc2 Фамилия2 ")), ++ "subject1", "body1", "state1" ++ ), ++ new MailCase("toMail2@ya.ru", null, "subject2", "body2", "state2", ++ Date.from(now.minus(Duration.ofMinutes(1)))), ++ new MailCase(null, "ccMail3@ya.ru", "subject3", "body3", "state3", DATE_FROM) ++ ); ++ ++ static final MailCase MAIL_CASE_EXCLUDED = ++ new MailCase("toMail4@ya.ru", "ccMail4@ya.ru", "subject4", "body4", "state4", ++ Date.from(now.minus(Duration.ofDays(2)))); ++ ++ public static void setUp() { ++ MailCaseDao dao = DBIProvider.getDao(MailCaseDao.class); ++ dao.clean(); ++ DBIProvider.getDBI().useTransaction((conn, status) -> { ++ MAIL_CASES.forEach(dao::insert); ++ dao.insert(MAIL_CASE_EXCLUDED); ++ }); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java (revision ) +@@ -0,0 +1,28 @@ ++package ru.javaops.masterjava.service.mail.persist; ++ ++import com.bertoncelj.jdbi.entitymapper.Column; ++import com.google.common.base.Joiner; ++import lombok.*; ++import ru.javaops.masterjava.persist.model.BaseEntity; ++import ru.javaops.masterjava.service.mail.Addressee; ++ ++import java.util.Date; ++import java.util.List; ++ ++@Data ++@AllArgsConstructor ++@NoArgsConstructor ++@EqualsAndHashCode // compare without id ++@ToString ++public class MailCase extends BaseEntity { ++ private @Column("list_to") String listTo; ++ private @Column("list_cc") String listCc; ++ private String subject; ++ private String body; ++ private String state; ++ private Date date; ++ ++ public static MailCase of(List to, List cc, String subject, String body, String state){ ++ return new MailCase(Joiner.on(", ").join(to), Joiner.on(", ").join(cc), subject, body, state, new Date()); ++ } ++} +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java (revision ) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java (revision ) +@@ -0,0 +1,22 @@ ++package ru.javaops.masterjava.service.mail.persist; ++ ++import org.junit.Assert; ++import org.junit.Before; ++import org.junit.Test; ++import ru.javaops.masterjava.persist.dao.AbstractDaoTest; ++ ++public class MailCaseDaoTest extends AbstractDaoTest { ++ public MailCaseDaoTest() { ++ super(MailCaseDao.class); ++ } ++ ++ @Before ++ public void setUp() throws Exception { ++ MailCaseTestData.setUp(); ++ } ++ ++ @Test ++ public void getAll() throws Exception { ++ Assert.assertEquals(MailCaseTestData.MAIL_CASES, dao.getAfter(MailCaseTestData.DATE_FROM)); ++ } ++} +\ No newline at end of file +Index: config_templates/sql/databaseChangeLog.sql +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/sql/databaseChangeLog.sql (date 1492186474000) ++++ config_templates/sql/databaseChangeLog.sql (revision ) +@@ -33,3 +33,17 @@ + group_id INTEGER NOT NULL REFERENCES groups (id), + CONSTRAINT users_group_idx UNIQUE (user_id, group_id) + ); ++ ++--changeset gkislin:3 ++CREATE TABLE mail_hist ( ++ id SERIAL PRIMARY KEY, ++ list_to TEXT NULL, ++ list_cc TEXT NULL, ++ subject TEXT NULL, ++ body TEXT NULL, ++ state TEXT NOT NULL, ++ date TIMESTAMP NOT NULL ++); ++ ++COMMENT ON TABLE mail_hist IS 'История отправки email'; ++COMMENT ON COLUMN mail_hist.date IS 'Время отправки'; +\ No newline at end of file +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (date 1492186474000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -4,6 +4,9 @@ + import lombok.extern.slf4j.Slf4j; + import lombok.val; + import org.apache.commons.mail.EmailException; ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.service.mail.persist.MailCase; ++import ru.javaops.masterjava.service.mail.persist.MailCaseDao; + + import java.util.List; + +@@ -13,8 +16,11 @@ + */ + @Slf4j + public class MailSender { ++ private static final MailCaseDao MAIL_CASE_DAO = DBIProvider.getDao(MailCaseDao.class); ++ + static void sendMail(List to, List cc, String subject, String body) { + log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled()?"\nbody=" + body:"")); ++ String state = "OK"; + try { + val email = MailConfig.createHtmlEmail(); + email.setSubject(subject); +@@ -28,10 +34,12 @@ + + // https://yandex.ru/blog/company/66296 + email.setHeaders(ImmutableMap.of("List-Unsubscribe", "")); +- + email.send(); + } catch (EmailException e) { + log.error(e.getMessage(), e); ++ state = e.getMessage(); + } ++ MAIL_CASE_DAO.insert(MailCase.of(to, cc, subject, body, state)); ++ log.info("Sent with state: " + state); + } + } +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492186474000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -19,6 +19,13 @@ + new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService")); + + MailService mailService = service.getPort(MailService.class); +- mailService.sendMail(ImmutableList.of(new Addressee("gkislin@javaops.ru")), ImmutableList.of(), "Subject", "Body"); ++ ++ mailService.sendMail(ImmutableList.of( ++ new Addressee("gkislin@javaops.ru"), ++ new Addressee("Bad Email ")), ImmutableList.of(), "Subject", "Body"); ++ ++ mailService.sendMail( ++ ImmutableList.of(new Addressee("Григорий Кислин ")), ++ ImmutableList.of(new Addressee("Мастер Java ")), "Subject", "Body"); + } + } +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (date 1492186474000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) +@@ -1,5 +1,7 @@ + package ru.javaops.masterjava.service.mail; + ++import ru.javaops.masterjava.persist.DBITestProvider; ++ + import javax.xml.ws.Endpoint; + + /** +@@ -9,6 +11,7 @@ + public class MailServicePublisher { + + public static void main(String[] args) { ++ DBITestProvider.initDBI(); + Endpoint.publish("http://localhost:8080/mail/mailService", new MailServiceImpl()); + } + } +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (date 1492186474000) ++++ services/mail-service/pom.xml (revision ) +@@ -38,5 +38,17 @@ + activation + 1.1.1 + ++ ++ ${project.groupId} ++ persist ++ ${project.version} ++ ++ ++ ${project.groupId} ++ persist ++ ${project.version} ++ test-jar ++ test ++ + + +\ No newline at end of file +Index: config_templates/sql/002_add_projects.sql +=================================================================== +--- config_templates/sql/002_add_projects.sql (date 1492186474000) ++++ config_templates/sql/002_add_projects.sql (date 1492186474000) +@@ -1,20 +0,0 @@ +-CREATE TABLE project ( +- id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), +- name TEXT NOT NULL UNIQUE, +- description TEXT +-); +- +-CREATE TYPE group_type AS ENUM ('REGISTERING', 'CURRENT', 'FINISHED'); +- +-CREATE TABLE groups ( +- id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), +- name TEXT NOT NULL UNIQUE, +- type group_type NOT NULL, +- project_id INTEGER NOT NULL REFERENCES project (id) +-); +- +-CREATE TABLE user_group ( +- user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, +- group_id INTEGER NOT NULL REFERENCES groups (id), +- CONSTRAINT users_group_idx UNIQUE (user_id, group_id) +-); +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (date 1492186474000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -16,6 +16,18 @@ + private String name; + + public Addressee(String email) { +- this(email, null); ++ email = email.trim(); ++ int idx = email.indexOf('<'); ++ if (idx == -1) { ++ this.email = email; ++ } else { ++ this.name = email.substring(0, idx).trim(); ++ this.email = email.substring(idx + 1, email.length() - 1).trim(); ++ } ++ } ++ ++ @Override ++ public String toString() { ++ return name == null ? email : name + " <" + email + '>'; + } + } +Index: config_templates/sql/001_add_city.sql +=================================================================== +--- config_templates/sql/001_add_city.sql (date 1492186474000) ++++ config_templates/sql/001_add_city.sql (date 1492186474000) +@@ -1,10 +0,0 @@ +-CREATE SEQUENCE common_seq START 100000; +- +-CREATE TABLE city ( +- id INTEGER PRIMARY KEY DEFAULT nextval('common_seq'), +- ref TEXT UNIQUE, +- name TEXT NOT NULL +-); +- +-ALTER TABLE users +- ADD COLUMN city_id INTEGER REFERENCES city (id); +\ No newline at end of file +Index: persist/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/pom.xml (date 1492186474000) ++++ persist/pom.xml (revision ) +@@ -15,6 +15,25 @@ + 1.0-SNAPSHOT + Persist + ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-jar-plugin ++ 3.0.2 ++ ++ ++ ++ test-jar ++ ++ ++ ++ ++ ++ ++ + + + ${project.groupId} diff --git a/patches/lesson07/7_3_HW6_ProjectGroupImporter.patch b/patches/lesson07/7_3_HW6_ProjectGroupImporter.patch new file mode 100644 index 000000000..f4c4450de --- /dev/null +++ b/patches/lesson07/7_3_HW6_ProjectGroupImporter.patch @@ -0,0 +1,141 @@ +Index: web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java (revision ) ++++ web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java (revision ) +@@ -0,0 +1,53 @@ ++package ru.javaops.masterjava.export; ++ ++import lombok.extern.slf4j.Slf4j; ++import lombok.val; ++import ru.javaops.masterjava.persist.DBIProvider; ++import ru.javaops.masterjava.persist.dao.GroupDao; ++import ru.javaops.masterjava.persist.dao.ProjectDao; ++import ru.javaops.masterjava.persist.model.Group; ++import ru.javaops.masterjava.persist.model.GroupType; ++import ru.javaops.masterjava.persist.model.Project; ++import ru.javaops.masterjava.xml.util.StaxStreamProcessor; ++ ++import javax.xml.stream.XMLStreamException; ++import javax.xml.stream.events.XMLEvent; ++import java.util.ArrayList; ++import java.util.Map; ++ ++@Slf4j ++public class ProjectGroupImporter { ++ private final ProjectDao projectDao = DBIProvider.getDao(ProjectDao.class); ++ private final GroupDao groupDao = DBIProvider.getDao(GroupDao.class); ++ ++ public Map process(StaxStreamProcessor processor) throws XMLStreamException { ++ val projectMap = projectDao.getAsMap(); ++ val groupMap = groupDao.getAsMap(); ++ String element; ++ ++ val newGroups = new ArrayList(); ++ Project project = null; ++ while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, "Project", "Group", "Cities")) != null) { ++ if (element.equals("Cities")) break; ++ if (element.equals("Project")) { ++ val name = processor.getAttribute("name"); ++ val description = processor.getElementValue("description"); ++ project = projectMap.get(name); ++ if (project == null) { ++ project = new Project(name, description); ++ log.info("Insert project " + project); ++ projectDao.insert(project); ++ } ++ } else { ++ val name = processor.getAttribute("name"); ++ if (!groupMap.containsKey(name)) { ++ // project here already assigned, as it located in xml before Group ++ newGroups.add(new Group(name, GroupType.valueOf(processor.getAttribute("type")), project.getId())); ++ } ++ } ++ } ++ log.info("Insert groups " + newGroups); ++ groupDao.insertBatch(newGroups); ++ return groupDao.getAsMap(); ++ } ++} +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java (date 1492187817000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java (revision ) +@@ -2,13 +2,11 @@ + + import com.bertoncelj.jdbi.entitymapper.EntityMapperFactory; + import one.util.streamex.StreamEx; +-import org.skife.jdbi.v2.sqlobject.BindBean; +-import org.skife.jdbi.v2.sqlobject.GetGeneratedKeys; +-import org.skife.jdbi.v2.sqlobject.SqlQuery; +-import org.skife.jdbi.v2.sqlobject.SqlUpdate; ++import org.skife.jdbi.v2.sqlobject.*; + import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapperFactory; + import ru.javaops.masterjava.persist.model.Group; + ++import java.util.Collection; + import java.util.List; + import java.util.Map; + +@@ -34,4 +32,7 @@ + int id = insertGeneratedId(groups); + groups.setId(id); + } ++ ++ @SqlBatch("INSERT INTO groups (name, type, project_id) VALUES (:name, CAST(:type AS group_type), :projectId)") ++ public abstract void insertBatch(@BindBean Collection groups); + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (date 1492187817000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java (revision ) +@@ -9,6 +9,7 @@ + import java.util.List; + + public class PayloadImporter { ++ private final ProjectGroupImporter projectGroupImporter = new ProjectGroupImporter(); + private final CityImporter cityImporter = new CityImporter(); + private final UserImporter userImporter = new UserImporter(); + +@@ -25,7 +26,8 @@ + + public List process(InputStream is, int chunkSize) throws XMLStreamException { + final StaxStreamProcessor processor = new StaxStreamProcessor(is); ++ val groups = projectGroupImporter.process(processor); + val cities = cityImporter.process(processor); +- return userImporter.process(processor, cities, chunkSize); ++ return userImporter.process(processor, groups, cities, chunkSize); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (date 1492187817000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (revision ) +@@ -6,6 +6,7 @@ + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; + import ru.javaops.masterjava.persist.model.City; ++import ru.javaops.masterjava.persist.model.Group; + import ru.javaops.masterjava.persist.model.User; + import ru.javaops.masterjava.persist.model.UserFlag; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; +@@ -31,7 +32,7 @@ + private final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + private final UserDao userDao = DBIProvider.getDao(UserDao.class); + +- public List process(StaxStreamProcessor processor, Map cities, int chunkSize) throws XMLStreamException { ++ public List process(StaxStreamProcessor processor, Map groups, Map cities, int chunkSize) throws XMLStreamException { + log.info("Start proseccing with chunkSize=" + chunkSize); + + return new Callable>() { diff --git a/patches/lesson07/7_4_HW6_refactor_UserImporter.patch b/patches/lesson07/7_4_HW6_refactor_UserImporter.patch new file mode 100644 index 000000000..35ce01445 --- /dev/null +++ b/patches/lesson07/7_4_HW6_refactor_UserImporter.patch @@ -0,0 +1,154 @@ +Index: persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (date 1492203480000) ++++ persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java (revision ) +@@ -61,11 +61,11 @@ + public abstract int[] insertBatch(@BindBean List users, @BatchChunkSize int chunkSize); + + +- public List insertAndGetConflictEmails(List users) { ++ public List insertAndGetConflictEmails(List users) { + int[] result = insertBatch(users, users.size()); + return IntStreamEx.range(0, users.size()) + .filter(i -> result[i] == 0) +- .mapToObj(index -> users.get(index).getEmail()) ++ .mapToObj(users::get) + .toList(); + } + } +Index: web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (date 1492203480000) ++++ web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java (revision ) +@@ -1,40 +1,42 @@ + package ru.javaops.masterjava.export; + ++import com.google.common.base.Splitter; ++import lombok.Value; + import lombok.extern.slf4j.Slf4j; ++import lombok.val; + import one.util.streamex.StreamEx; + import ru.javaops.masterjava.export.PayloadImporter.FailedEmail; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.persist.dao.UserDao; +-import ru.javaops.masterjava.persist.model.City; +-import ru.javaops.masterjava.persist.model.Group; +-import ru.javaops.masterjava.persist.model.User; +-import ru.javaops.masterjava.persist.model.UserFlag; ++import ru.javaops.masterjava.persist.dao.UserGroupDao; ++import ru.javaops.masterjava.persist.model.*; + import ru.javaops.masterjava.xml.util.StaxStreamProcessor; + + import javax.xml.stream.XMLStreamException; + import javax.xml.stream.events.XMLEvent; +-import java.util.ArrayList; +-import java.util.List; +-import java.util.Map; ++import java.util.*; + import java.util.concurrent.Callable; + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + import java.util.concurrent.Future; + +-/** +- * gkislin +- * 14.10.2016 +- */ + @Slf4j + public class UserImporter { + + private static final int NUMBER_THREADS = 4; + private final ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_THREADS); + private final UserDao userDao = DBIProvider.getDao(UserDao.class); ++ private UserGroupDao userGroupDao = DBIProvider.getDao(UserGroupDao.class); + + public List process(StaxStreamProcessor processor, Map groups, Map cities, int chunkSize) throws XMLStreamException { + log.info("Start proseccing with chunkSize=" + chunkSize); + ++ @Value ++ class ChunkItem { ++ private User user; ++ private StreamEx userGroups; ++ } ++ + return new Callable>() { + class ChunkFuture { + String emailRange; +@@ -51,11 +53,10 @@ + + @Override + public List call() throws XMLStreamException { +- List futures = new ArrayList<>(); +- ++ val futures = new ArrayList(); + int id = userDao.getSeqAndSkip(chunkSize); +- List chunk = new ArrayList<>(chunkSize); +- List failed = new ArrayList<>(); ++ List chunk = new ArrayList<>(chunkSize); ++ val failed = new ArrayList(); + + while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { + final String email = processor.getAttribute("email"); +@@ -64,14 +65,24 @@ + if (city == null) { + failed.add(new FailedEmail(email, "City '" + cityRef + "' is not present in DB")); + } else { +- final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); +- final String fullName = processor.getReader().getElementText(); +- final User user = new User(id++, fullName, email, flag, city.getId()); +- chunk.add(user); +- if (chunk.size() == chunkSize) { +- futures.add(submit(chunk)); +- chunk = new ArrayList<>(chunkSize); +- id = userDao.getSeqAndSkip(chunkSize); ++ val groupRefs = processor.getAttribute("groupRefs"); ++ List groupNames = (groupRefs == null) ? ++ Collections.emptyList() : ++ Splitter.on(' ').splitToList(groupRefs); ++ ++ if (!groups.keySet().containsAll(groupNames)) { ++ failed.add(new FailedEmail(email, "One of group from '" + groupRefs + "' is not present in DB")); ++ } else { ++ final UserFlag flag = UserFlag.valueOf(processor.getAttribute("flag")); ++ final String fullName = processor.getText(); ++ final User user = new User(id++, fullName, email, flag, city.getId()); ++ StreamEx userGroups = StreamEx.of(groupNames).map(name -> new UserGroup(user.getId(), groups.get(name).getId())); ++ chunk.add(new ChunkItem(user, userGroups)); ++ if (chunk.size() == chunkSize) { ++ futures.add(submit(chunk)); ++ chunk = new ArrayList<>(chunkSize); ++ id = userDao.getSeqAndSkip(chunkSize); ++ } + } + } + } +@@ -92,9 +103,20 @@ + return failed; + } + +- private ChunkFuture submit(List chunk) { +- ChunkFuture chunkFuture = new ChunkFuture(chunk, +- executorService.submit(() -> userDao.insertAndGetConflictEmails(chunk)) ++ private ChunkFuture submit(List chunk) { ++ val users = StreamEx.of(chunk).map(ChunkItem::getUser).toList(); ++ ChunkFuture chunkFuture = new ChunkFuture( ++ users, ++ executorService.submit(() -> { ++ List alreadyPresents = userDao.insertAndGetConflictEmails(users); ++ Set alreadyPresentsIds = StreamEx.of(alreadyPresents).map(User::getId).toSet(); ++ userGroupDao.insertBatch( ++ StreamEx.of(chunk).flatMap(ChunkItem::getUserGroups) ++ .filter(ug -> !alreadyPresentsIds.contains(ug.getUserId())) ++ .toList() ++ ); ++ return StreamEx.of(alreadyPresents).map(User::getEmail).toList(); ++ }) + ); + log.info("Submit " + chunkFuture.emailRange); + return chunkFuture; diff --git a/patches/lesson07/7_5_customize_WSDL.patch b/patches/lesson07/7_5_customize_WSDL.patch new file mode 100644 index 000000000..1714c5db9 --- /dev/null +++ b/patches/lesson07/7_5_customize_WSDL.patch @@ -0,0 +1,74 @@ +Index: services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl (revision ) ++++ services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl (revision ) +@@ -0,0 +1,65 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file diff --git a/patches/lesson07/7_6_publish_customizedWSDL.patch b/patches/lesson07/7_6_publish_customizedWSDL.patch new file mode 100644 index 000000000..0bfeddbed --- /dev/null +++ b/patches/lesson07/7_6_publish_customizedWSDL.patch @@ -0,0 +1,109 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1492206400000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -3,11 +3,9 @@ + import javax.jws.WebService; + import java.util.List; + +-/** +- * gkislin +- * 15.11.2016 +- */ +-@WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService") ++@WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" ++// , wsdlLocation = "WEB-INF/wsdl/mailService.wsdl" ++) + public class MailServiceImpl implements MailService { + public void sendMail(List to, List cc, String subject, String body) { + MailSender.sendMail(to, cc, subject, body); +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492206400000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -7,16 +7,12 @@ + import java.net.MalformedURLException; + import java.net.URL; + +-/** +- * User: gkislin +- * Date: 28.05.2014 +- */ + public class MailServiceClient { + + public static void main(String[] args) throws MalformedURLException { + Service service = Service.create( + new URL("http://localhost:8080/mail/mailService?wsdl"), +- new QName("http://mail.service.masterjava.javaops.ru/", "MailServiceImplService")); ++ new QName("http://mail.javaops.ru/", "MailServiceImplService")); + + MailService mailService = service.getPort(MailService.class); + +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1492206400000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -5,11 +5,11 @@ + import javax.jws.WebService; + import java.util.List; + +-/** +- * gkislin +- * 15.11.2016 +- */ +-@WebService ++@WebService(targetNamespace = "http://mail.javaops.ru/") ++//@SOAPBinding( ++// style = SOAPBinding.Style.DOCUMENT, ++// use= SOAPBinding.Use.LITERAL, ++// parameterStyle = SOAPBinding.ParameterStyle.WRAPPED) + public interface MailService { + + @WebMethod +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (date 1492206400000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) +@@ -1,17 +1,25 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.collect.ImmutableList; + import ru.javaops.masterjava.persist.DBITestProvider; + ++import javax.xml.transform.Source; ++import javax.xml.transform.stream.StreamSource; + import javax.xml.ws.Endpoint; ++import java.io.File; ++import java.util.List; + +-/** +- * User: gkislin +- * Date: 28.05.2014 +- */ + public class MailServicePublisher { + + public static void main(String[] args) { + DBITestProvider.initDBI(); +- Endpoint.publish("http://localhost:8080/mail/mailService", new MailServiceImpl()); ++ ++ Endpoint endpoint = Endpoint.create(new MailServiceImpl()); ++ List metadata = ImmutableList.of( ++ new StreamSource( ++ new File("services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl"))); ++ ++ endpoint.setMetadata(metadata); ++ endpoint.publish("http://localhost:8080/mail/mailService"); + } + } diff --git a/patches/lesson07/7_7_deploy_Tomcat.patch b/patches/lesson07/7_7_deploy_Tomcat.patch new file mode 100644 index 000000000..f08c15efb --- /dev/null +++ b/patches/lesson07/7_7_deploy_Tomcat.patch @@ -0,0 +1,66 @@ +Index: services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml (revision ) ++++ services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml (revision ) +@@ -0,0 +1,5 @@ ++ ++ ++ ++ +\ No newline at end of file +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (date 1492207315000) ++++ services/mail-service/pom.xml (revision ) +@@ -50,5 +50,43 @@ + test-jar + test + ++ ++ com.sun.xml.ws ++ jaxws-rt ++ 2.2.10 ++ ++ ++ org.jvnet.mimepull ++ mimepull ++ ++ ++ javax.xml.bind ++ jaxb-api ++ ++ ++ javax.annotation ++ javax.annotation-api ++ ++ ++ org.jvnet.staxex ++ stax-ex ++ ++ ++ javax.xml.soap ++ javax.xml.soap-api ++ ++ ++ ++ ++ org.jvnet.staxex ++ stax-ex ++ 1.7.8 ++ ++ ++ javax.activation ++ activation ++ ++ ++ + + +\ No newline at end of file diff --git a/patches/lesson07/7_8_create_client.patch b/patches/lesson07/7_8_create_client.patch new file mode 100644 index 000000000..96d3ee019 --- /dev/null +++ b/patches/lesson07/7_8_create_client.patch @@ -0,0 +1,189 @@ +Index: common/src/main/java/ru/javaops/masterjava/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/web/WsClient.java (revision ) ++++ common/src/main/java/ru/javaops/masterjava/web/WsClient.java (revision ) +@@ -0,0 +1,40 @@ ++package ru.javaops.masterjava.web; ++ ++import com.typesafe.config.Config; ++import ru.javaops.masterjava.config.Configs; ++ ++import javax.xml.namespace.QName; ++import javax.xml.ws.BindingProvider; ++import javax.xml.ws.Service; ++import java.net.URL; ++import java.util.Map; ++ ++public class WsClient { ++ private static Config HOSTS; ++ ++ private final Class serviceClass; ++ private final Service service; ++ private String endpointAddress; ++ ++ static { ++ HOSTS = Configs.getConfig("hosts.conf", "hosts"); ++ } ++ ++ public WsClient(URL wsdlUrl, QName qname, Class serviceClass) { ++ this.serviceClass = serviceClass; ++ this.service = Service.create(wsdlUrl, qname); ++ } ++ ++ public void init(String host, String endpointAddress) { ++ this.endpointAddress = HOSTS.getString(host) + endpointAddress; ++ } ++ ++ // Post is not thread-safe (http://stackoverflow.com/a/10601916/548473) ++ public T getPort() { ++ T port = service.getPort(serviceClass); ++ BindingProvider bp = (BindingProvider) port; ++ Map requestContext = bp.getRequestContext(); ++ requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); ++ return port; ++ } ++} +Index: services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) ++++ services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) +@@ -0,0 +1,11 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import com.google.common.collect.ImmutableList; ++ ++public class MailWSClientMain { ++ public static void main(String[] args) { ++ MailWSClient.sendMail( ++ ImmutableList.of(new Addressee("Григорий Кислин ")), ++ ImmutableList.of(new Addressee("Мастер Java ")), "Subject", "Body"); ++ } ++} +\ No newline at end of file +Index: common/src/main/resources/hosts.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/resources/hosts.conf (revision ) ++++ common/src/main/resources/hosts.conf (revision ) +@@ -0,0 +1,4 @@ ++hosts { ++ mail = "http://localhost:8080" ++} ++include file("/apps/masterjava/config/hosts.conf") +Index: services/mail-api/src/test/resources/wsdl/mailService.wsdl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/resources/wsdl/mailService.wsdl (revision ) ++++ services/mail-api/src/test/resources/wsdl/mailService.wsdl (revision ) +@@ -0,0 +1,65 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -0,0 +1,27 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import com.google.common.io.Resources; ++import lombok.extern.slf4j.Slf4j; ++import ru.javaops.masterjava.web.WsClient; ++ ++import javax.xml.namespace.QName; ++import java.util.List; ++ ++@Slf4j ++public class MailWSClient { ++ private static final WsClient WS_CLIENT; ++ ++ static { ++ WS_CLIENT = new WsClient(Resources.getResource("wsdl/mailService.wsdl"), ++ new QName("http://mail.javaops.ru/", "MailServiceImplService"), ++ MailService.class); ++ ++ WS_CLIENT.init("mail", "/mail/mailService?wsdl"); ++ } ++ ++ ++ public static void sendMail(final List to, final List cc, final String subject, final String body) { ++ log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); ++ WS_CLIENT.getPort().sendMail(to, cc, subject, body); ++ } ++} diff --git a/patches/lesson07/7_9_refactoring.patch b/patches/lesson07/7_9_refactoring.patch new file mode 100644 index 000000000..642ce015b --- /dev/null +++ b/patches/lesson07/7_9_refactoring.patch @@ -0,0 +1,454 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) +@@ -0,0 +1,19 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++ ++import java.util.List; ++ ++@AllArgsConstructor ++public class GroupResult { ++ private final int success; // number of successfully sent email ++ private final List failed; // failed emails with causes ++ private final String failedCause; // global fail cause ++ ++ @Override ++ public String toString() { ++ return "Success: " + success + '\n' + ++ "Failed: " + failed.toString() + '\n' + ++ (failedCause == null ? "" : "Failed cause" + failedCause); ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision ) +@@ -0,0 +1,20 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++ ++@AllArgsConstructor ++public class MailResult { ++ public static final String OK = "OK"; ++ ++ private final String email; ++ private final String result; ++ ++ public boolean isOk() { ++ return OK.equals(result); ++ } ++ ++ @Override ++ public String toString() { ++ return '(' + email + ',' + result + ')'; ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (date 1492212779000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (revision ) +@@ -1,13 +1,15 @@ + package ru.javaops.masterjava.service.mail; + ++import lombok.extern.slf4j.Slf4j; ++import one.util.streamex.StreamEx; ++ + import java.util.ArrayList; + import java.util.List; + import java.util.Set; + import java.util.concurrent.*; +-import java.util.stream.Collectors; + ++@Slf4j + public class MailServiceExecutor { +- private static final String OK = "OK"; + + private static final String INTERRUPTED_BY_FAULTS_NUMBER = "+++ Interrupted by faults number"; + private static final String INTERRUPTED_BY_TIMEOUT = "+++ Interrupted by timeout"; +@@ -15,12 +17,12 @@ + + private final ExecutorService mailExecutor = Executors.newFixedThreadPool(8); + +- public GroupResult sendToList(final String template, final Set emails) throws Exception { ++ public GroupResult sendIndividual(final Set addressees, final String subject, final String body) throws Exception { + final CompletionService completionService = new ExecutorCompletionService<>(mailExecutor); + +- List> futures = emails.stream() +- .map(email -> completionService.submit(() -> sendToUser(template, email))) +- .collect(Collectors.toList()); ++ List> futures = StreamEx.of(addressees) ++ .map(addressee -> completionService.submit(() -> MailSender.sendBulk(addressee, subject, body))) ++ .toList(); + + return new Callable() { + private int success = 0; +@@ -50,29 +52,9 @@ + return cancelWithFail(INTERRUPTED_EXCEPTION); + } + } +-/* +- for (Future future : futures) { +- MailResult mailResult; +- try { +- mailResult = future.get(10, TimeUnit.SECONDS); +- } catch (InterruptedException e) { +- return cancelWithFail(INTERRUPTED_EXCEPTION); +- } catch (ExecutionException e) { +- return cancelWithFail(e.getCause().toString()); +- } catch (TimeoutException e) { +- return cancelWithFail(INTERRUPTED_BY_TIMEOUT); +- } +- if (mailResult.isOk()) { +- success++; +- } else { +- failed.add(mailResult); +- if (failed.size() >= 5) { +- return cancelWithFail(INTERRUPTED_BY_FAULTS_NUMBER); +- } +- } +- } +-*/ +- return new GroupResult(success, failed, null); ++ GroupResult groupResult = new GroupResult(success, failed, null); ++ log.info("groupResult: {}", groupResult); ++ return groupResult; + } + + private GroupResult cancelWithFail(String cause) { +@@ -81,61 +63,4 @@ + } + }.call(); + } +- +- // dummy realization +- public MailResult sendToUser(String template, String email) throws Exception { +- try { +- Thread.sleep(500); //delay +- } catch (InterruptedException e) { +- // log cancel; +- return null; +- } +- return Math.random() < 0.7 ? MailResult.ok(email) : MailResult.error(email, "Error"); +- } +- +- public static class MailResult { +- private final String email; +- private final String result; +- +- private static MailResult ok(String email) { +- return new MailResult(email, OK); +- } +- +- private static MailResult error(String email, String error) { +- return new MailResult(email, error); +- } +- +- public boolean isOk() { +- return OK.equals(result); +- } +- +- private MailResult(String email, String cause) { +- this.email = email; +- this.result = cause; +- } +- +- @Override +- public String toString() { +- return '(' + email + ',' + result + ')'; +- } +- } +- +- public static class GroupResult { +- private final int success; // number of successfully sent email +- private final List failed; // failed emails with causes +- private final String failedCause; // global fail cause +- +- public GroupResult(int success, List failed, String failedCause) { +- this.success = success; +- this.failed = failed; +- this.failedCause = failedCause; +- } +- +- @Override +- public String toString() { +- return "Success: " + success + '\n' + +- "Failed: " + failed.toString() + '\n' + +- (failedCause == null ? "" : "Failed cause" + failedCause); +- } +- } + } +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492212779000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -1,6 +1,6 @@ + package ru.javaops.masterjava.service.mail; + +-import com.google.common.collect.ImmutableList; ++import com.google.common.collect.ImmutableSet; + + import javax.xml.namespace.QName; + import javax.xml.ws.Service; +@@ -16,12 +16,12 @@ + + MailService mailService = service.getPort(MailService.class); + +- mailService.sendMail(ImmutableList.of( ++ mailService.sendMail(ImmutableSet.of( + new Addressee("gkislin@javaops.ru"), +- new Addressee("Bad Email ")), ImmutableList.of(), "Subject", "Body"); ++ new Addressee("Bad Email ")), ImmutableSet.of(), "Subject", "Body"); + + mailService.sendMail( +- ImmutableList.of(new Addressee("Григорий Кислин ")), +- ImmutableList.of(new Addressee("Мастер Java ")), "Subject", "Body"); ++ ImmutableSet.of(new Addressee("Григорий Кислин ")), ++ ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); + } + } +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1492212779000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -1,13 +1,13 @@ + package ru.javaops.masterjava.service.mail; + + import javax.jws.WebService; +-import java.util.List; ++import java.util.Set; + + @WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" + // , wsdlLocation = "WEB-INF/wsdl/mailService.wsdl" + ) + public class MailServiceImpl implements MailService { +- public void sendMail(List to, List cc, String subject, String body) { +- MailSender.sendMail(to, cc, subject, body); ++ public void sendMail(Set to, Set cc, String subject, String body) { ++ MailSender.sendBulk(to, cc, subject, body); + } + } +\ No newline at end of file +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (date 1492212779000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -1,6 +1,7 @@ + package ru.javaops.masterjava.service.mail; + + import com.google.common.collect.ImmutableMap; ++import com.google.common.collect.ImmutableSet; + import lombok.extern.slf4j.Slf4j; + import lombok.val; + import org.apache.commons.mail.EmailException; +@@ -8,7 +9,7 @@ + import ru.javaops.masterjava.service.mail.persist.MailCase; + import ru.javaops.masterjava.service.mail.persist.MailCaseDao; + +-import java.util.List; ++import java.util.Set; + + /** + * gkislin +@@ -18,9 +19,14 @@ + public class MailSender { + private static final MailCaseDao MAIL_CASE_DAO = DBIProvider.getDao(MailCaseDao.class); + +- static void sendMail(List to, List cc, String subject, String body) { +- log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled()?"\nbody=" + body:"")); +- String state = "OK"; ++ static MailResult sendBulk(Addressee to, String subject, String body) { ++ val state = sendBulk(ImmutableSet.of(to), ImmutableSet.of(), subject, body); ++ return new MailResult(to.getEmail(), state); ++ } ++ ++ static String sendBulk(Set to, Set cc, String subject, String body) { ++ log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); ++ String state = MailResult.OK; + try { + val email = MailConfig.createHtmlEmail(); + email.setSubject(subject); +@@ -41,5 +47,6 @@ + } + MAIL_CASE_DAO.insert(MailCase.of(to, cc, subject, body, state)); + log.info("Sent with state: " + state); ++ return state; + } + } +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java (date 1492212779000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java (revision ) +@@ -1,6 +1,7 @@ + package ru.javaops.masterjava.service.mail.persist; + + import com.google.common.collect.ImmutableList; ++import com.google.common.collect.ImmutableSet; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.service.mail.Addressee; + +@@ -19,10 +20,10 @@ + + static final List MAIL_CASES = ImmutableList.of( + MailCase.of( +- ImmutableList.of( ++ ImmutableSet.of( + new Addressee("ИмяTo1 Фамилия1 "), + new Addressee("Имя2 Фамилия2 ")), +- ImmutableList.of( ++ ImmutableSet.of( + new Addressee("ИмяCc1 Фамилия1 "), + new Addressee("ИмяCc2 Фамилия2 ")), + "subject1", "body1", "state1" +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1492212779000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -3,7 +3,7 @@ + import javax.jws.WebMethod; + import javax.jws.WebParam; + import javax.jws.WebService; +-import java.util.List; ++import java.util.Set; + + @WebService(targetNamespace = "http://mail.javaops.ru/") + //@SOAPBinding( +@@ -14,8 +14,8 @@ + + @WebMethod + void sendMail( +- @WebParam(name = "to") List to, +- @WebParam(name = "cc") List cc, ++ @WebParam(name = "to") Set to, ++ @WebParam(name = "cc") Set cc, + @WebParam(name = "subject") String subject, + @WebParam(name = "body") String body); + } +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (date 1492212779000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -30,4 +30,17 @@ + public String toString() { + return name == null ? email : name + " <" + email + '>'; + } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ Addressee addressee = (Addressee) o; ++ return email.equals(addressee.email); ++ } ++ ++ @Override ++ public int hashCode() { ++ return email.hashCode(); ++ } + } +Index: services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (date 1492212779000) ++++ services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) +@@ -1,11 +1,11 @@ + package ru.javaops.masterjava.service.mail; + +-import com.google.common.collect.ImmutableList; ++import com.google.common.collect.ImmutableSet; + + public class MailWSClientMain { + public static void main(String[] args) { + MailWSClient.sendMail( +- ImmutableList.of(new Addressee("Григорий Кислин ")), +- ImmutableList.of(new Addressee("Мастер Java ")), "Subject", "Body"); ++ ImmutableSet.of(new Addressee("Григорий Кислин ")), ++ ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); + } + } +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1492212779000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -5,7 +5,7 @@ + import ru.javaops.masterjava.web.WsClient; + + import javax.xml.namespace.QName; +-import java.util.List; ++import java.util.Set; + + @Slf4j + public class MailWSClient { +@@ -20,7 +20,7 @@ + } + + +- public static void sendMail(final List to, final List cc, final String subject, final String body) { ++ public static void sendMail(final Set to, final Set cc, final String subject, final String body) { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + WS_CLIENT.getPort().sendMail(to, cc, subject, body); + } +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java (date 1492212779000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java (revision ) +@@ -7,7 +7,7 @@ + import ru.javaops.masterjava.service.mail.Addressee; + + import java.util.Date; +-import java.util.List; ++import java.util.Set; + + @Data + @AllArgsConstructor +@@ -22,7 +22,7 @@ + private String state; + private Date date; + +- public static MailCase of(List to, List cc, String subject, String body, String state){ ++ public static MailCase of(Set to, Set cc, String subject, String body, String state) { + return new MailCase(Joiner.on(", ").join(to), Joiner.on(", ").join(cc), subject, body, state, new Date()); + } + } +\ No newline at end of file diff --git a/patches/lesson08/8_0_fix.patch b/patches/lesson08/8_0_fix.patch new file mode 100644 index 000000000..6caf4f8dc --- /dev/null +++ b/patches/lesson08/8_0_fix.patch @@ -0,0 +1,118 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) +@@ -1,21 +0,0 @@ +-package ru.javaops.masterjava.service.mail; +- +-import lombok.AllArgsConstructor; +-import lombok.NoArgsConstructor; +- +-import java.util.List; +- +-@AllArgsConstructor +-@NoArgsConstructor +-public class GroupResult { +- private int success; // number of successfully sent email +- private List failed; // failed emails with causes +- private String failedCause; // global fail cause +- +- @Override +- public String toString() { +- return "Success: " + success + '\n' + +- "Failed: " + failed.toString() + '\n' + +- (failedCause == null ? "" : "Failed cause" + failedCause); +- } +-} +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision ) +@@ -1,14 +1,18 @@ + package ru.javaops.masterjava.service.mail; + + import lombok.AllArgsConstructor; ++import lombok.Data; + import lombok.NoArgsConstructor; ++import lombok.NonNull; + ++@Data + @AllArgsConstructor + @NoArgsConstructor + public class MailResult { + public static final String OK = "OK"; + +- private String email; ++ private @NonNull ++ String email; + private String result; + + public boolean isOk() { +@@ -17,6 +21,6 @@ + + @Override + public String toString() { +- return '(' + email + ',' + result + ')'; ++ return '\'' + email + "' result '" + result + '\''; + } + } +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) +@@ -1,20 +0,0 @@ +-package ru.javaops.masterjava.service.mail; +- +-import lombok.AllArgsConstructor; +- +-@AllArgsConstructor +-public class MailResult { +- public static final String OK = "OK"; +- +- private final String email; +- private final String result; +- +- public boolean isOk() { +- return OK.equals(result); +- } +- +- @Override +- public String toString() { +- return '(' + email + ',' + result + ')'; +- } +-} +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) +@@ -1,10 +1,12 @@ + package ru.javaops.masterjava.service.mail; + + import lombok.AllArgsConstructor; ++import lombok.Data; + import lombok.NoArgsConstructor; + + import java.util.List; + ++@Data + @AllArgsConstructor + @NoArgsConstructor + public class GroupResult { +@@ -15,7 +17,7 @@ + @Override + public String toString() { + return "Success: " + success + '\n' + +- "Failed: " + failed.toString() + '\n' + +- (failedCause == null ? "" : "Failed cause" + failedCause); ++ (failed == null ? "" : "Failed: " + failed.toString() + '\n') + ++ (failedCause == null ? "" : "Failed cause: " + failedCause); + } +-} ++} +\ No newline at end of file diff --git a/patches/lesson08/8_1_HW7_wsdl_share.patch b/patches/lesson08/8_1_HW7_wsdl_share.patch new file mode 100644 index 000000000..df30967ee --- /dev/null +++ b/patches/lesson08/8_1_HW7_wsdl_share.patch @@ -0,0 +1,153 @@ +Index: parent/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent/pom.xml (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ parent/pom.xml (revision ) +@@ -18,6 +18,7 @@ + 1.2.2 + 1.7.25 + ++ + /apps/masterjava/config/ + false + +Index: services/mail-api/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/pom.xml (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-api/pom.xml (revision ) +@@ -15,6 +15,17 @@ + 1.0-SNAPSHOT + Mail API + ++ ++ ++ ++ ${masterjava.config} ++ ++ wsdl/mailService.wsdl ++ ++ ++ ++ ++ + + + ${project.groupId} +Index: services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl +=================================================================== +--- services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) +@@ -1,65 +0,0 @@ +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +\ No newline at end of file +Index: services/mail-api/src/test/resources/wsdl/mailService.wsdl +=================================================================== +--- services/mail-api/src/test/resources/wsdl/mailService.wsdl (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ config_templates/wsdl/mailService.wsdl (revision ) +@@ -1,0 +1,0 @@ +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (revision 81d5845b6318233faf1de8ae95f3d325ca2b13ff) ++++ services/mail-service/pom.xml (revision ) +@@ -16,6 +16,29 @@ + war + Mail Service + ++ ++ mail ++ ++ ++ org.apache.maven.plugins ++ maven-war-plugin ++ 3.0.0 ++ ++ false ++ ++ ++ ${masterjava.config} ++ ++ wsdl/mailService.wsdl ++ ++ WEB-INF ++ ++ ++ ++ ++ ++ ++ + + + ${project.groupId} diff --git a/patches/lesson08/8_2_app_conf.patch b/patches/lesson08/8_2_app_conf.patch new file mode 100644 index 000000000..2d0644c92 --- /dev/null +++ b/patches/lesson08/8_2_app_conf.patch @@ -0,0 +1,156 @@ +Index: config_templates/app.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/app.conf (revision ) ++++ config_templates/app.conf (revision ) +@@ -0,0 +1,6 @@ ++app { ++ groupId = ${project.groupId} ++ projectName = ${project.name} ++ version = ${project.version} ++ configDir = "${masterjava.config}" ++} +\ No newline at end of file +Index: config_templates/version.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/version.html (revision ) ++++ config_templates/version.html (revision ) +@@ -0,0 +1,11 @@ ++ ++ ++ ++ ${project.name} ++ ++ ++${project.groupId}:${project.name}:${project.version}
++configDir=${masterjava.config}
++Многопоточность. Maven. XML. Веб сервисы. ++ ++ +Index: common/src/main/java/ru/javaops/masterjava/config/Configs.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/config/Configs.java (date 1492825787000) ++++ common/src/main/java/ru/javaops/masterjava/config/Configs.java (revision ) +@@ -3,10 +3,8 @@ + import com.typesafe.config.Config; + import com.typesafe.config.ConfigFactory; + +-/** +- * gkislin +- * 01.11.2016 +- */ ++import java.io.File; ++ + public class Configs { + + public static Config getConfig(String resource) { +@@ -16,4 +14,12 @@ + public static Config getConfig(String resource, String domain) { + return getConfig(resource).getConfig(domain); + } ++ ++ public static File getConfigFile(String path) { ++ return new File(AppConfig.APP_CONFIG.getString("configDir"), path); ++ } ++ ++ private static class AppConfig { ++ private static final Config APP_CONFIG = getConfig("app.conf", "app"); ++ } + } +Index: parent-web/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- parent-web/pom.xml (date 1492825787000) ++++ parent-web/pom.xml (revision ) +@@ -24,6 +24,18 @@ + 3.0.0 + + false ++ ++ ++ src/main/webapp ++ ++ ++ ${masterjava.config} ++ ++ version.html ++ ++ true ++ ++ + + + +@@ -75,6 +87,7 @@ + true + + logback.xml ++ app.conf + + + +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (date 1492825787000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) +@@ -1,12 +1,12 @@ + package ru.javaops.masterjava.service.mail; + + import com.google.common.collect.ImmutableList; ++import ru.javaops.masterjava.config.Configs; + import ru.javaops.masterjava.persist.DBITestProvider; + + import javax.xml.transform.Source; + import javax.xml.transform.stream.StreamSource; + import javax.xml.ws.Endpoint; +-import java.io.File; + import java.util.List; + + public class MailServicePublisher { +@@ -16,8 +16,7 @@ + + Endpoint endpoint = Endpoint.create(new MailServiceImpl()); + List metadata = ImmutableList.of( +- new StreamSource( +- new File("services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl"))); ++ new StreamSource(Configs.getConfigFile("wsdl/mailService.wsdl"))); + + endpoint.setMetadata(metadata); + endpoint.publish("http://localhost:8080/mail/mailService"); +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (date 1492825787000) ++++ services/mail-service/pom.xml (revision ) +@@ -27,6 +27,16 @@ + false + + ++ src/main/webapp ++ ++ ++ ${masterjava.config} ++ ++ version.html ++ ++ true ++ ++ + ${masterjava.config} + + wsdl/mailService.wsdl diff --git a/patches/lesson08/8_3_HW7_update_wsdl.patch b/patches/lesson08/8_3_HW7_update_wsdl.patch new file mode 100644 index 000000000..78be5afff --- /dev/null +++ b/patches/lesson08/8_3_HW7_update_wsdl.patch @@ -0,0 +1,175 @@ +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492828867000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -16,12 +16,15 @@ + + MailService mailService = service.getPort(MailService.class); + +- mailService.sendToGroup(ImmutableSet.of( ++ ImmutableSet addressees = ImmutableSet.of( + new Addressee("gkislin@javaops.ru"), +- new Addressee("Bad Email ")), ImmutableSet.of(), "Subject", "Body"); ++ new Addressee("Мастер Java "), ++ new Addressee("Bad Email ")); + +- mailService.sendToGroup( +- ImmutableSet.of(new Addressee("Григорий Кислин ")), +- ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); ++ String status = mailService.sendToGroup(addressees, ImmutableSet.of(), "Bulk email subject", "Bulk email body"); ++ System.out.println(status); ++ ++ GroupResult groupResult = mailService.sendBulk(addressees, "Individual mail subject", "Individual mail body"); ++ System.out.println(groupResult); + } + } +Index: config_templates/wsdl/mailService.wsdl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/wsdl/mailService.wsdl (date 1492828867000) ++++ config_templates/wsdl/mailService.wsdl (revision ) +@@ -8,10 +8,12 @@ + name="MailServiceImplService"> + + +- +- ++ ++ ++ ++ + +- ++ + + + +@@ -19,6 +21,39 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +@@ -33,21 +68,43 @@ + + + +- +- ++ ++ + +- +- ++ ++ ++ ++ ++ ++ ++ ++ + + +- +- +- ++ ++ ++ ++ ++ ++ ++ + + + + +- ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +Index: services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (date 1492828867000) ++++ services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) +@@ -4,7 +4,7 @@ + + public class MailWSClientMain { + public static void main(String[] args) { +- MailWSClient.sendMail( ++ MailWSClient.sendToGroup( + ImmutableSet.of(new Addressee("Григорий Кислин ")), + ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); + } +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1492828867000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -20,7 +20,7 @@ + } + + +- public static void sendMail(final Set to, final Set cc, final String subject, final String body) { ++ public static void sendToGroup(final Set to, final Set cc, final String subject, final String body) { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + WS_CLIENT.getPort().sendToGroup(to, cc, subject, body); + } diff --git a/patches/lesson08/8_4_HW7_webapp.patch b/patches/lesson08/8_4_HW7_webapp.patch new file mode 100644 index 000000000..39edba5c3 --- /dev/null +++ b/patches/lesson08/8_4_HW7_webapp.patch @@ -0,0 +1,225 @@ +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (revision ) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (revision ) +@@ -0,0 +1,27 @@ ++package ru.javaops.masterjava.webapp; ++ ++import lombok.extern.slf4j.Slf4j; ++import ru.javaops.masterjava.service.mail.GroupResult; ++import ru.javaops.masterjava.service.mail.MailWSClient; ++ ++import javax.servlet.ServletException; ++import javax.servlet.annotation.WebServlet; ++import javax.servlet.http.HttpServlet; ++import javax.servlet.http.HttpServletRequest; ++import javax.servlet.http.HttpServletResponse; ++import java.io.IOException; ++ ++@WebServlet("/send") ++@Slf4j ++public class SendServlet extends HttpServlet { ++ @Override ++ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ++ req.setCharacterEncoding("UTF-8"); ++ resp.setCharacterEncoding("UTF-8"); ++ String users = req.getParameter("users"); ++ String subject = req.getParameter("subject"); ++ String body = req.getParameter("body"); ++ GroupResult groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body); ++ resp.getWriter().write(groupResult.toString()); ++ } ++} +Index: web/webapp/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/pom.xml (date 1492825936000) ++++ web/webapp/pom.xml (revision ) +@@ -26,5 +26,10 @@ + persist + ${project.version} +
++ ++ ${project.groupId} ++ mail-api ++ ${project.version} ++ +
+ +\ No newline at end of file +Index: web/webapp/src/main/webapp/WEB-INF/templates/users.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/webapp/WEB-INF/templates/users.html (date 1492825936000) ++++ web/webapp/src/main/webapp/WEB-INF/templates/users.html (revision ) +@@ -3,25 +3,65 @@ + + Users + ++ ++ ++ + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
Full NameEmailFlag
++ ++ ++
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
#Full NameEmailFlag ++
++
++

++ ++

++

++
++

++

++ ++

++
++
++ + + +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1492825936000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -1,5 +1,8 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.base.Splitter; ++import com.google.common.collect.ImmutableSet; ++import com.google.common.collect.Iterables; + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; + import ru.javaops.masterjava.web.WsClient; +@@ -20,8 +23,34 @@ + } + + +- public static void sendToGroup(final Set to, final Set cc, final String subject, final String body) { ++ public static String sendToGroup(final Set to, final Set cc, final String subject, final String body) { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); +- WS_CLIENT.getPort().sendToGroup(to, cc, subject, body); ++ String status; ++ try { ++ status = WS_CLIENT.getPort().sendToGroup(to, cc, subject, body); ++ log.info("Sent with status: " + status); ++ } catch (Exception e) { ++ log.error("sendToGroup failed", e); ++ status = e.toString(); ++ } ++ return status; ++ } ++ ++ public static GroupResult sendBulk(final Set to, final String subject, final String body) { ++ log.info("Send mail to '" + to + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); ++ GroupResult result; ++ try { ++ result = WS_CLIENT.getPort().sendBulk(to, subject, body); ++ } catch (Exception e) { ++ log.error("sendIndividualMails failed", e); ++ result = new GroupResult(e); ++ } ++ log.info("Sent with result: " + result); ++ return result; ++ } ++ ++ public static Set split(String addressees) { ++ Iterable split = Splitter.on(',').trimResults().omitEmptyStrings().split(addressees); ++ return ImmutableSet.copyOf(Iterables.transform(split, Addressee::new)); + } + } +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (date 1492825936000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java (revision ) +@@ -1,5 +1,6 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.base.Throwables; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -14,6 +15,10 @@ + private List failed; // failed emails with causes + private String failedCause; // global fail cause + ++ public GroupResult(Exception e) { ++ this(-1, null, Throwables.getRootCause(e).toString()); ++ } ++ + @Override + public String toString() { + return "Success: " + success + '\n' + diff --git a/patches/lesson08/8_5_soap_exceptions.patch b/patches/lesson08/8_5_soap_exceptions.patch new file mode 100644 index 000000000..b643941f1 --- /dev/null +++ b/patches/lesson08/8_5_soap_exceptions.patch @@ -0,0 +1,719 @@ +Index: services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java (revision ) +@@ -0,0 +1,19 @@ ++package ru.javaops.web; ++ ++import lombok.Data; ++import lombok.NoArgsConstructor; ++import lombok.NonNull; ++import lombok.RequiredArgsConstructor; ++import ru.javaops.masterjava.ExceptionType; ++ ++@Data ++@RequiredArgsConstructor ++@NoArgsConstructor ++public class FaultInfo { ++ private @NonNull ExceptionType type; ++ ++ @Override ++ public String toString() { ++ return type.toString(); ++ } ++} +Index: common/src/main/java/ru/javaops/masterjava/ExceptionType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/ExceptionType.java (revision ) ++++ common/src/main/java/ru/javaops/masterjava/ExceptionType.java (revision ) +@@ -0,0 +1,34 @@ ++package ru.javaops.masterjava; ++ ++public enum ExceptionType { ++ SYSTEM("Системная ошибка"), ++ DATA_BASE("Ошибка базы данных"), ++ STATE("Неверное состояние приложения"), ++ AUTHORIZATION("Ошибка авторизации"), ++ CONFIGURATION("Ошибка конфигурирования"), ++ ILLEGAL_ARGUMENT("Неверный аргумент"), ++ BPM("Ошибка бизнес-процесса"), ++ FILE("Ошибка при работе с файловой системой"), ++ REPORTS("Ошибка в отчете"), ++ EMAIL("Ошибка при отправке почты"), ++ TEMPLATE("Ошибка в шаблонах"), ++ ONE_C("Ошибка в системе 1C"), ++ ATTACH("Ошибка вложенного файла"), ++ LDAP("Ошибка соединения с LDAP"), ++ NETWORK("Сетевая Ошибка"); ++ ++ final private String descr; ++ ++ ExceptionType(String title) { ++ this.descr = title; ++ } ++ ++ public String getDescr() { ++ return descr; ++ } ++ ++ @Override ++ public String toString() { ++ return name() + " (" + descr + ')'; ++ } ++} +Index: config_templates/wsdl/common.xsd +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/wsdl/common.xsd (revision ) ++++ config_templates/wsdl/common.xsd (revision ) +@@ -0,0 +1,32 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/WebStateException.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WebStateException.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/WebStateException.java (revision ) +@@ -0,0 +1,35 @@ ++package ru.javaops.web; ++ ++ ++import com.google.common.base.Throwables; ++import ru.javaops.masterjava.ExceptionType; ++ ++import javax.xml.ws.WebFault; ++ ++@WebFault(name = "webStateException", targetNamespace = "http://common.javaops.ru/") ++public class WebStateException extends Exception { ++ private FaultInfo faultInfo; ++ ++ public WebStateException(String message, FaultInfo faultInfo) { ++ super(message); ++ this.faultInfo = faultInfo; ++ } ++ ++ public WebStateException(Exception e) { ++ this(ExceptionType.SYSTEM, e); ++ } ++ ++ public WebStateException(ExceptionType type, Throwable cause) { ++ super(Throwables.getRootCause(cause).toString(), cause); ++ this.faultInfo = new FaultInfo(type); ++ } ++ ++ public FaultInfo getFaultInfo() { ++ return faultInfo; ++ } ++ ++ @Override ++ public String toString() { ++ return faultInfo.toString() + '\n' + super.toString(); ++ } ++} +Index: services/common-ws/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/pom.xml (revision ) ++++ services/common-ws/pom.xml (revision ) +@@ -0,0 +1,77 @@ ++ ++ ++ 4.0.0 ++ ++ ++ ru.javaops ++ parent ++ ../../parent/pom.xml ++ 1.0-SNAPSHOT ++ ++ ++ common-ws ++ 1.0-SNAPSHOT ++ Common Web Services ++ ++ ++ ++ ${project.groupId} ++ common ++ ${project.version} ++ ++ ++ ++ com.sun.xml.ws ++ jaxws-rt ++ 2.2.10 ++ ++ ++ org.jvnet.mimepull ++ mimepull ++ ++ ++ javax.xml.bind ++ jaxb-api ++ ++ ++ javax.annotation ++ javax.annotation-api ++ ++ ++ org.jvnet.staxex ++ stax-ex ++ ++ ++ javax.xml.soap ++ javax.xml.soap-api ++ ++ ++ ++ ++ ++ javax.activation ++ activation ++ 1.1.1 ++ ++ ++ org.jvnet.staxex ++ stax-ex ++ 1.7.7 ++ ++ ++ javax.activation ++ activation ++ ++ ++ ++ ++ ++ javax.servlet ++ javax.servlet-api ++ 3.1.0 ++ provided ++ ++ ++ +\ No newline at end of file +Index: services/mail-api/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/pom.xml (date 1492826050000) ++++ services/mail-api/pom.xml (revision ) +@@ -21,6 +21,7 @@ + ${masterjava.config} + + wsdl/mailService.wsdl ++ wsdl/common.xsd + + + +@@ -29,7 +30,7 @@ + + + ${project.groupId} +- common ++ common-ws + ${project.version} + + +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (date 1492826050000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -5,9 +5,11 @@ + import lombok.extern.slf4j.Slf4j; + import lombok.val; + import org.apache.commons.mail.EmailException; ++import ru.javaops.masterjava.ExceptionType; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.service.mail.persist.MailCase; + import ru.javaops.masterjava.service.mail.persist.MailCaseDao; ++import ru.javaops.web.WebStateException; + + import java.util.Set; + +@@ -19,12 +21,12 @@ + public class MailSender { + private static final MailCaseDao MAIL_CASE_DAO = DBIProvider.getDao(MailCaseDao.class); + +- static MailResult sendTo(Addressee to, String subject, String body) { ++ static MailResult sendTo(Addressee to, String subject, String body) throws WebStateException { + val state = sendToGroup(ImmutableSet.of(to), ImmutableSet.of(), subject, body); + return new MailResult(to.getEmail(), state); + } + +- static String sendToGroup(Set to, Set cc, String subject, String body) { ++ static String sendToGroup(Set to, Set cc, String subject, String body) throws WebStateException { + log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String state = MailResult.OK; + try { +@@ -45,7 +47,12 @@ + log.error(e.getMessage(), e); + state = e.getMessage(); + } +- MAIL_CASE_DAO.insert(MailCase.of(to, cc, subject, body, state)); ++ try { ++ MAIL_CASE_DAO.insert(MailCase.of(to, cc, subject, body, state)); ++ } catch (Exception e) { ++ log.error("Mail history saving exception", e); ++ throw new WebStateException(ExceptionType.DATA_BASE, e); ++ } + log.info("Sent with state: " + state); + return state; + } +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1492826050000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -1,5 +1,7 @@ + package ru.javaops.masterjava.service.mail; + ++import ru.javaops.web.WebStateException; ++ + import javax.jws.WebService; + import java.util.Set; + +@@ -9,12 +11,12 @@ + public class MailServiceImpl implements MailService { + + @Override +- public String sendToGroup(Set to, Set cc, String subject, String body) { ++ public String sendToGroup(Set to, Set cc, String subject, String body) throws WebStateException { + return MailSender.sendToGroup(to, cc, subject, body); + } + + @Override +- public GroupResult sendBulk(Set to, String subject, String body) { ++ public GroupResult sendBulk(Set to, String subject, String body) throws WebStateException { + return MailServiceExecutor.sendBulk(to, subject, body); + } + } +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1492826050000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -1,6 +1,7 @@ + package ru.javaops.masterjava.service.mail; + + import com.google.common.collect.ImmutableSet; ++import ru.javaops.web.WebStateException; + + import javax.xml.namespace.QName; + import javax.xml.ws.Service; +@@ -21,10 +22,14 @@ + new Addressee("Мастер Java "), + new Addressee("Bad Email ")); + +- String status = mailService.sendToGroup(addressees, ImmutableSet.of(), "Bulk email subject", "Bulk email body"); +- System.out.println(status); ++ try { ++ String status = mailService.sendToGroup(addressees, ImmutableSet.of(), "Bulk email subject", "Bulk email body"); ++ System.out.println(status); + +- GroupResult groupResult = mailService.sendBulk(addressees, "Individual mail subject", "Individual mail body"); +- System.out.println(groupResult); ++ GroupResult groupResult = mailService.sendBulk(addressees, "Individual mail subject", "Individual mail body"); ++ System.out.println(groupResult); ++ } catch (WebStateException e) { ++ System.out.println(e); ++ } + } + } +Index: config_templates/wsdl/mailService.wsdl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/wsdl/mailService.wsdl (date 1492826050000) ++++ config_templates/wsdl/mailService.wsdl (revision ) +@@ -3,11 +3,14 @@ + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:tns="http://mail.javaops.ru/" + xmlns:xs="http://www.w3.org/2001/XMLSchema" ++ xmlns:common="http://common.javaops.ru/" + xmlns="http://schemas.xmlsoap.org/wsdl/" + targetNamespace="http://mail.javaops.ru/" + name="MailServiceImplService"> + + ++ ++ + + + +@@ -80,17 +83,25 @@ + + + ++ ++ ++ ++ + + + + ++ + + + + ++ + + + +@@ -103,6 +114,9 @@ + + + ++ ++ ++ + + + +@@ -112,6 +126,9 @@ + + + ++ ++ ++ + + + +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1492826050000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -1,5 +1,7 @@ + package ru.javaops.masterjava.service.mail; + ++import ru.javaops.web.WebStateException; ++ + import javax.jws.WebMethod; + import javax.jws.WebParam; + import javax.jws.WebService; +@@ -17,12 +19,12 @@ + @WebParam(name = "to") Set to, + @WebParam(name = "cc") Set cc, + @WebParam(name = "subject") String subject, +- @WebParam(name = "body") String body); ++ @WebParam(name = "body") String body) throws WebStateException; + + @WebMethod + GroupResult sendBulk( + @WebParam(name = "to") Set to, + @WebParam(name = "subject") String subject, +- @WebParam(name = "body") String body); ++ @WebParam(name = "body") String body) throws WebStateException; + + } +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (date 1492826050000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java (revision ) +@@ -16,7 +16,8 @@ + + Endpoint endpoint = Endpoint.create(new MailServiceImpl()); + List metadata = ImmutableList.of( +- new StreamSource(Configs.getConfigFile("wsdl/mailService.wsdl"))); ++ new StreamSource(Configs.getConfigFile("wsdl/mailService.wsdl")), ++ new StreamSource(Configs.getConfigFile("wsdl/common.xsd"))); + + endpoint.setMetadata(metadata); + endpoint.publish("http://localhost:8080/mail/mailService"); +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (date 1492826050000) ++++ services/mail-service/pom.xml (revision ) +@@ -40,6 +40,7 @@ + ${masterjava.config} + + wsdl/mailService.wsdl ++ wsdl/common.xsd + + WEB-INF + +@@ -66,11 +67,7 @@ + + +
+- +- javax.activation +- activation +- 1.1.1 +- ++ + + ${project.groupId} + persist +@@ -82,44 +79,6 @@ + ${project.version} + test-jar + test +- +- +- com.sun.xml.ws +- jaxws-rt +- 2.2.10 +- +- +- org.jvnet.mimepull +- mimepull +- +- +- javax.xml.bind +- jaxb-api +- +- +- javax.annotation +- javax.annotation-api +- +- +- org.jvnet.staxex +- stax-ex +- +- +- javax.xml.soap +- javax.xml.soap-api +- +- +- +- +- org.jvnet.staxex +- stax-ex +- 1.7.8 +- +- +- javax.activation +- activation +- +- + +
+ +\ No newline at end of file +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (date 1492826050000) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (revision ) +@@ -1,8 +1,8 @@ + package ru.javaops.masterjava.webapp; + + import lombok.extern.slf4j.Slf4j; +-import ru.javaops.masterjava.service.mail.GroupResult; + import ru.javaops.masterjava.service.mail.MailWSClient; ++import ru.javaops.web.WebStateException; + + import javax.servlet.ServletException; + import javax.servlet.annotation.WebServlet; +@@ -21,7 +21,12 @@ + String users = req.getParameter("users"); + String subject = req.getParameter("subject"); + String body = req.getParameter("body"); +- GroupResult groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body); +- resp.getWriter().write(groupResult.toString()); ++ String groupResult; ++ try { ++ groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body).toString(); ++ } catch (WebStateException e) { ++ groupResult = e.toString(); ++ } ++ resp.getWriter().write(groupResult); + } + } +Index: common/src/main/java/ru/javaops/masterjava/web/WsClient.java +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/web/WsClient.java (date 1492826050000) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -1,6 +1,7 @@ +-package ru.javaops.masterjava.web; ++package ru.javaops.web; + + import com.typesafe.config.Config; ++import ru.javaops.masterjava.ExceptionType; + import ru.javaops.masterjava.config.Configs; + + import javax.xml.namespace.QName; +@@ -37,4 +38,9 @@ + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); + return port; + } ++ ++ public static WebStateException getWebStateException(Exception e) { ++ return (e instanceof WebStateException) ? ++ (WebStateException) e : new WebStateException(ExceptionType.NETWORK, e); ++ } + } +Index: services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (date 1492826050000) ++++ services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) +@@ -1,11 +1,20 @@ + package ru.javaops.masterjava.service.mail; + + import com.google.common.collect.ImmutableSet; ++import lombok.extern.slf4j.Slf4j; + ++@Slf4j + public class MailWSClientMain { + public static void main(String[] args) { +- MailWSClient.sendToGroup( +- ImmutableSet.of(new Addressee("Григорий Кислин ")), +- ImmutableSet.of(new Addressee("Мастер Java ")), "Subject", "Body"); ++ ImmutableSet addressees = ImmutableSet.of( ++ new Addressee("gkislin@javaops.ru"), ++ new Addressee("Мастер Java "), ++ new Addressee("Bad Email ")); ++ try { ++ String state = MailWSClient.sendToGroup(addressees, ImmutableSet.of(), "Subject", "Body"); ++ System.out.println(state); ++ } catch (Throwable e) { ++ log.error(e.toString(), e); ++ } + } + } +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1492826050000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -5,7 +5,8 @@ + import com.google.common.collect.Iterables; + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; +-import ru.javaops.masterjava.web.WsClient; ++import ru.javaops.web.WebStateException; ++import ru.javaops.web.WsClient; + + import javax.xml.namespace.QName; + import java.util.Set; +@@ -23,7 +24,7 @@ + } + + +- public static String sendToGroup(final Set to, final Set cc, final String subject, final String body) { ++ public static String sendToGroup(final Set to, final Set cc, final String subject, final String body) throws WebStateException { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String status; + try { +@@ -31,19 +32,19 @@ + log.info("Sent with status: " + status); + } catch (Exception e) { + log.error("sendToGroup failed", e); +- status = e.toString(); ++ throw WsClient.getWebStateException(e); + } + return status; + } + +- public static GroupResult sendBulk(final Set to, final String subject, final String body) { ++ public static GroupResult sendBulk(final Set to, final String subject, final String body) throws WebStateException { + log.info("Send mail to '" + to + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + GroupResult result; + try { + result = WS_CLIENT.getPort().sendBulk(to, subject, body); +- } catch (Exception e) { +- log.error("sendIndividualMails failed", e); +- result = new GroupResult(e); ++ } catch (WebStateException e) { ++ log.error("sendBulk failed", e); ++ throw WsClient.getWebStateException(e); + } + log.info("Sent with result: " + result); + return result; +Index: services/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/pom.xml (date 1492826050000) ++++ services/pom.xml (revision ) +@@ -9,6 +9,7 @@ + + MasterJava Services + ++ common-ws + mail-api + mail-service + diff --git a/patches/lesson08/8_6_fix_wsdl_and_schema.patch b/patches/lesson08/8_6_fix_wsdl_and_schema.patch new file mode 100644 index 000000000..dc95b543e --- /dev/null +++ b/patches/lesson08/8_6_fix_wsdl_and_schema.patch @@ -0,0 +1,92 @@ +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (date 1492820861000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java (revision ) +@@ -1,14 +1,22 @@ + package ru.javaops.masterjava.service.mail; + + import lombok.AllArgsConstructor; +-import lombok.Data; ++import lombok.Getter; + import lombok.NoArgsConstructor; + +-@Data ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlValue; ++ ++@Getter + @AllArgsConstructor + @NoArgsConstructor ++@XmlAccessorType(XmlAccessType.FIELD) + public class Addressee { ++ @XmlAttribute + private String email; ++ @XmlValue + private String name; + + public Addressee(String email) { +Index: common/src/main/java/ru/javaops/masterjava/ExceptionType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/java/ru/javaops/masterjava/ExceptionType.java (date 1492820861000) ++++ common/src/main/java/ru/javaops/masterjava/ExceptionType.java (revision ) +@@ -1,5 +1,8 @@ + package ru.javaops.masterjava; + ++import javax.xml.bind.annotation.XmlType; ++ ++@XmlType(namespace = "http://common.javaops.ru/") + public enum ExceptionType { + SYSTEM("Системная ошибка"), + DATA_BASE("Ошибка базы данных"), +Index: config_templates/wsdl/common.xsd +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/wsdl/common.xsd (date 1492820861000) ++++ config_templates/wsdl/common.xsd (revision ) +@@ -1,12 +1,14 @@ + ++ + + +- ++ + + + +- ++ + + + +Index: services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java (date 1492820861000) ++++ services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java (revision ) +@@ -6,9 +6,12 @@ + import lombok.RequiredArgsConstructor; + import ru.javaops.masterjava.ExceptionType; + ++import javax.xml.bind.annotation.XmlType; ++ + @Data + @RequiredArgsConstructor + @NoArgsConstructor ++@XmlType(namespace = "http://common.javaops.ru/") + public class FaultInfo { + private @NonNull ExceptionType type; + diff --git a/patches/lesson09/9_0_mvn_plugins.patch b/patches/lesson09/9_0_mvn_plugins.patch new file mode 100644 index 000000000..35538eade --- /dev/null +++ b/patches/lesson09/9_0_mvn_plugins.patch @@ -0,0 +1,110 @@ +Index: persist/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- persist/pom.xml (revision 9aba595804472679d75fe4f3ce2016e9ecec46ed) ++++ persist/pom.xml (revision c744f3ea11c0a6d871ad0ee3629dcfabdf1613f9) +@@ -31,6 +31,30 @@ + + + ++ ++ ++ ++ org.liquibase ++ liquibase-maven-plugin ++ 3.5.3 ++ ++ ../sql/databaseChangeLog.sql ++ org.postgresql.Driver ++ jdbc:postgresql://localhost:5432/masterjava ++ user ++ password ++ ++ ++ ++ ++ ++ process-resources ++ ++ update ++ ++ ++ ++ + + + +Index: services/mail-service/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/pom.xml (revision 9aba595804472679d75fe4f3ce2016e9ecec46ed) ++++ services/mail-service/pom.xml (revision c744f3ea11c0a6d871ad0ee3629dcfabdf1613f9) +@@ -21,31 +21,24 @@ + + + org.apache.maven.plugins +- maven-war-plugin +- 3.0.0 +- +- false +- +- +- src/main/webapp +- +- +- ${masterjava.config} +- +- version.html +- +- true +- +- +- ${masterjava.config} +- +- wsdl/mailService.wsdl +- wsdl/common.xsd +- +- WEB-INF +- +- +- ++ maven-antrun-plugin ++ 1.8 ++ ++ ++ prepare-package ++ ++ run ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +Index: config_templates/sql/databaseChangeLog.sql +=================================================================== +--- config_templates/sql/databaseChangeLog.sql (revision 9aba595804472679d75fe4f3ce2016e9ecec46ed) ++++ sql/databaseChangeLog.sql (revision c744f3ea11c0a6d871ad0ee3629dcfabdf1613f9) +@@ -1,0 +1,0 @@ +Index: config_templates/sql/initDB.sql +=================================================================== +--- config_templates/sql/initDB.sql (revision 9aba595804472679d75fe4f3ce2016e9ecec46ed) ++++ sql/initDB.sql (revision c744f3ea11c0a6d871ad0ee3629dcfabdf1613f9) +@@ -1,0 +1,0 @@ +Index: config_templates/sql/lb_apply.bat +=================================================================== +--- config_templates/sql/lb_apply.bat (revision 9aba595804472679d75fe4f3ce2016e9ecec46ed) ++++ sql/lb_apply.bat (revision c744f3ea11c0a6d871ad0ee3629dcfabdf1613f9) +@@ -1,0 +1,0 @@ diff --git a/patches/lesson09/9_1_HW8_service_attach.patch b/patches/lesson09/9_1_HW8_service_attach.patch new file mode 100644 index 000000000..86b245bfe --- /dev/null +++ b/patches/lesson09/9_1_HW8_service_attach.patch @@ -0,0 +1,278 @@ +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java (revision ) +@@ -0,0 +1,22 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import lombok.AllArgsConstructor; ++import lombok.Getter; ++import lombok.NoArgsConstructor; ++ ++import javax.activation.DataHandler; ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlMimeType; ++ ++@Getter ++@AllArgsConstructor ++@NoArgsConstructor ++@XmlAccessorType(XmlAccessType.FIELD) ++public class Attach { ++ // http://stackoverflow.com/questions/12250423/jax-ws-datahandler-getname-is-blank-when-called-from-client-side ++ protected String name; ++ ++ @XmlMimeType("application/octet-stream") ++ private DataHandler dataHandler; ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1493398337000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -3,6 +3,7 @@ + import ru.javaops.web.WebStateException; + + import javax.jws.WebService; ++import java.util.List; + import java.util.Set; + + @WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" +@@ -11,12 +12,12 @@ + public class MailServiceImpl implements MailService { + + @Override +- public String sendToGroup(Set to, Set cc, String subject, String body) throws WebStateException { ++ public String sendToGroup(Set to, Set cc, String subject, String body, List attaches) throws WebStateException { + return MailSender.sendToGroup(to, cc, subject, body); + } + + @Override +- public GroupResult sendBulk(Set to, String subject, String body) throws WebStateException { ++ public GroupResult sendBulk(Set to, String subject, String body, List attaches) throws WebStateException { + return MailServiceExecutor.sendBulk(to, subject, body); + } + } +\ No newline at end of file +Index: services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (date 1493398337000) ++++ services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java (revision ) +@@ -1,12 +1,16 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableSet; + import ru.javaops.web.WebStateException; + ++import javax.activation.DataHandler; + import javax.xml.namespace.QName; + import javax.xml.ws.Service; ++import java.io.File; + import java.net.MalformedURLException; + import java.net.URL; ++import java.util.List; + + public class MailServiceClient { + +@@ -18,15 +22,16 @@ + MailService mailService = service.getPort(MailService.class); + + ImmutableSet addressees = ImmutableSet.of( +- new Addressee("gkislin@javaops.ru"), +- new Addressee("Мастер Java "), +- new Addressee("Bad Email ")); ++ new Addressee("Мастер Java ")); ++ ++ List attaches = ImmutableList.of( ++ new Attach("version.html", new DataHandler(new File("config_templates/version.html").toURI().toURL()))); + + try { +- String status = mailService.sendToGroup(addressees, ImmutableSet.of(), "Bulk email subject", "Bulk email body"); ++ String status = mailService.sendToGroup(addressees, ImmutableSet.of(), "Bulk email subject", "Bulk email body", attaches); + System.out.println(status); + +- GroupResult groupResult = mailService.sendBulk(addressees, "Individual mail subject", "Individual mail body"); ++ GroupResult groupResult = mailService.sendBulk(addressees, "Individual mail subject", "Individual mail body", attaches); + System.out.println(groupResult); + } catch (WebStateException e) { + System.out.println(e); +Index: config_templates/wsdl/mailService.wsdl +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- config_templates/wsdl/mailService.wsdl (date 1493398337000) ++++ config_templates/wsdl/mailService.wsdl (revision ) +@@ -4,6 +4,7 @@ + xmlns:tns="http://mail.javaops.ru/" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:common="http://common.javaops.ru/" ++ xmlns:xmime="http://www.w3.org/2005/05/xmlmime" + xmlns="http://schemas.xmlsoap.org/wsdl/" + targetNamespace="http://mail.javaops.ru/" + name="MailServiceImplService"> +@@ -22,6 +23,7 @@ + + + ++ + + + +@@ -35,6 +37,7 @@ + + + ++ + + + +@@ -69,6 +72,13 @@ + + + ++ ++ ++ ++ ++ ++ ++ + + + +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (date 1493398337000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision ) +@@ -5,6 +5,7 @@ + import javax.jws.WebMethod; + import javax.jws.WebParam; + import javax.jws.WebService; ++import java.util.List; + import java.util.Set; + + @WebService(targetNamespace = "http://mail.javaops.ru/") +@@ -19,12 +20,14 @@ + @WebParam(name = "to") Set to, + @WebParam(name = "cc") Set cc, + @WebParam(name = "subject") String subject, +- @WebParam(name = "body") String body) throws WebStateException; ++ @WebParam(name = "body") String body, ++ @WebParam(name = "attaches") List attaches) throws WebStateException; + + @WebMethod + GroupResult sendBulk( + @WebParam(name = "to") Set to, + @WebParam(name = "subject") String subject, +- @WebParam(name = "body") String body) throws WebStateException; ++ @WebParam(name = "body") String body, ++ @WebParam(name = "attaches") List attaches) throws WebStateException; + + } +\ No newline at end of file +Index: services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (date 1493398337000) ++++ services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java (revision ) +@@ -1,17 +1,22 @@ + package ru.javaops.masterjava.service.mail; + ++import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableSet; + import lombok.extern.slf4j.Slf4j; + ++import javax.activation.DataHandler; ++import java.io.File; ++ + @Slf4j + public class MailWSClientMain { + public static void main(String[] args) { + ImmutableSet addressees = ImmutableSet.of( +- new Addressee("gkislin@javaops.ru"), +- new Addressee("Мастер Java "), +- new Addressee("Bad Email ")); ++ new Addressee("Мастер Java ")); ++ + try { +- String state = MailWSClient.sendToGroup(addressees, ImmutableSet.of(), "Subject", "Body"); ++ String state = MailWSClient.sendToGroup(addressees, ImmutableSet.of(), "Subject", "Body", ImmutableList.of( ++ new Attach("version.html", new DataHandler(new File("config_templates/version.html").toURI().toURL())) ++ )); + System.out.println(state); + } catch (Throwable e) { + log.error(e.toString(), e); +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1493398337000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -9,6 +9,7 @@ + import ru.javaops.web.WsClient; + + import javax.xml.namespace.QName; ++import java.util.List; + import java.util.Set; + + @Slf4j +@@ -24,11 +25,11 @@ + } + + +- public static String sendToGroup(final Set to, final Set cc, final String subject, final String body) throws WebStateException { ++ public static String sendToGroup(final Set to, final Set cc, final String subject, final String body, List attaches) throws WebStateException { + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String status; + try { +- status = WS_CLIENT.getPort().sendToGroup(to, cc, subject, body); ++ status = WS_CLIENT.getPort().sendToGroup(to, cc, subject, body, attaches); + log.info("Sent with status: " + status); + } catch (Exception e) { + log.error("sendToGroup failed", e); +@@ -37,11 +38,11 @@ + return status; + } + +- public static GroupResult sendBulk(final Set to, final String subject, final String body) throws WebStateException { ++ public static GroupResult sendBulk(final Set to, final String subject, final String body, List attaches) throws WebStateException { + log.info("Send mail to '" + to + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + GroupResult result; + try { +- result = WS_CLIENT.getPort().sendBulk(to, subject, body); ++ result = WS_CLIENT.getPort().sendBulk(to, subject, body, attaches); + } catch (WebStateException e) { + log.error("sendBulk failed", e); + throw WsClient.getWebStateException(e); +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (date 1493398337000) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (revision ) +@@ -23,7 +23,7 @@ + String body = req.getParameter("body"); + String groupResult; + try { +- groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body).toString(); ++ groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body, null).toString(); + } catch (WebStateException e) { + groupResult = e.toString(); + } diff --git a/patches/lesson09/9_2_HW8_MTOM.patch b/patches/lesson09/9_2_HW8_MTOM.patch new file mode 100644 index 000000000..df4100583 --- /dev/null +++ b/patches/lesson09/9_2_HW8_MTOM.patch @@ -0,0 +1,106 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1493406326000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -9,6 +9,8 @@ + @WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" + // , wsdlLocation = "WEB-INF/wsdl/mailService.wsdl" + ) ++//@StreamingAttachment(parseEagerly=true, memoryThreshold=40000L) ++//@MTOM + public class MailServiceImpl implements MailService { + + @Override +Index: services/common-ws/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/pom.xml (date 1493406326000) ++++ services/common-ws/pom.xml (revision ) +@@ -50,6 +50,12 @@ + + + ++ ++ org.jvnet.mimepull ++ mimepull ++ 1.9.4 ++ ++ + + javax.activation + activation +Index: services/common-ws/src/main/java/ru/javaops/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WsClient.java (date 1493406326000) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -7,6 +7,7 @@ + import javax.xml.namespace.QName; + import javax.xml.ws.BindingProvider; + import javax.xml.ws.Service; ++import javax.xml.ws.WebServiceFeature; + import java.net.URL; + import java.util.Map; + +@@ -31,8 +32,8 @@ + } + + // Post is not thread-safe (http://stackoverflow.com/a/10601916/548473) +- public T getPort() { +- T port = service.getPort(serviceClass); ++ public T getPort(WebServiceFeature... features) { ++ T port = service.getPort(serviceClass, features); + BindingProvider bp = (BindingProvider) port; + Map requestContext = bp.getRequestContext(); + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1493406326000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -9,6 +9,7 @@ + import ru.javaops.web.WsClient; + + import javax.xml.namespace.QName; ++import javax.xml.ws.soap.MTOMFeature; + import java.util.List; + import java.util.Set; + +@@ -29,7 +30,7 @@ + log.info("Send mail to '" + to + "' cc '" + cc + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String status; + try { +- status = WS_CLIENT.getPort().sendToGroup(to, cc, subject, body, attaches); ++ status = getPort().sendToGroup(to, cc, subject, body, attaches); + log.info("Sent with status: " + status); + } catch (Exception e) { + log.error("sendToGroup failed", e); +@@ -42,7 +43,7 @@ + log.info("Send mail to '" + to + "' subject '" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + GroupResult result; + try { +- result = WS_CLIENT.getPort().sendBulk(to, subject, body, attaches); ++ result = getPort().sendBulk(to, subject, body, attaches); + } catch (WebStateException e) { + log.error("sendBulk failed", e); + throw WsClient.getWebStateException(e); +@@ -51,6 +52,10 @@ + return result; + } + ++ private static MailService getPort() { ++ return WS_CLIENT.getPort(new MTOMFeature(1024)); ++ } ++ + public static Set split(String addressees) { + Iterable split = Splitter.on(',').trimResults().omitEmptyStrings().split(addressees); + return ImmutableSet.copyOf(Iterables.transform(split, Addressee::new)); diff --git a/patches/lesson09/9_3_HW8_webapp_attach.patch b/patches/lesson09/9_3_HW8_webapp_attach.patch new file mode 100644 index 000000000..2ec1346ed --- /dev/null +++ b/patches/lesson09/9_3_HW8_webapp_attach.patch @@ -0,0 +1,174 @@ +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java (revision ) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java (revision ) +@@ -0,0 +1,47 @@ ++package ru.javaops.masterjava.service.mail.util; ++ ++import lombok.AllArgsConstructor; ++import ru.javaops.masterjava.service.mail.Attach; ++ ++import javax.activation.DataHandler; ++import javax.activation.DataSource; ++import java.io.IOException; ++import java.io.InputStream; ++import java.io.OutputStream; ++ ++public class Attachments { ++ public static Attach getAttach(String name, InputStream inputStream) { ++ return new Attach(name, new DataHandler(new InputStreamDataSource(inputStream))); ++ } ++ ++ // http://stackoverflow.com/a/10783565/548473 ++ @AllArgsConstructor ++ private static class InputStreamDataSource implements DataSource { ++ private InputStream inputStream; ++ ++ @Override ++ public InputStream getInputStream() throws IOException { ++ if (inputStream == null) { ++ throw new IOException("Second getInputStream() call is not supported"); ++ } ++ InputStream res = inputStream; ++ inputStream = null; ++ return res; ++ } ++ ++ @Override ++ public OutputStream getOutputStream() throws IOException { ++ throw new UnsupportedOperationException("Not implemented"); ++ } ++ ++ @Override ++ public String getContentType() { ++ return "application/octet-stream"; ++ } ++ ++ @Override ++ public String getName() { ++ return ""; ++ } ++ } ++} +Index: web/webapp/src/main/webapp/WEB-INF/templates/users.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/webapp/WEB-INF/templates/users.html (date 1493408188000) ++++ web/webapp/src/main/webapp/WEB-INF/templates/users.html (revision ) +@@ -31,36 +31,37 @@ + + + +- ++ + + + +
+-

+- +-

+-

+-
+-

+-

+- +-

+-
++ ++ ++ ++ ++

++ ++

++

++
++

++

++ ++

++

++ ++

++ + + + +Index: web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (date 1493408188000) ++++ web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java (revision ) +@@ -1,29 +1,44 @@ + package ru.javaops.masterjava.webapp; + ++import com.google.common.collect.ImmutableList; + import lombok.extern.slf4j.Slf4j; ++import ru.javaops.masterjava.service.mail.Attach; + import ru.javaops.masterjava.service.mail.MailWSClient; ++import ru.javaops.masterjava.service.mail.util.Attachments; + import ru.javaops.web.WebStateException; + + import javax.servlet.ServletException; ++import javax.servlet.annotation.MultipartConfig; + import javax.servlet.annotation.WebServlet; + import javax.servlet.http.HttpServlet; + import javax.servlet.http.HttpServletRequest; + import javax.servlet.http.HttpServletResponse; ++import javax.servlet.http.Part; + import java.io.IOException; ++import java.util.List; + + @WebServlet("/send") + @Slf4j ++@MultipartConfig + public class SendServlet extends HttpServlet { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.setCharacterEncoding("UTF-8"); + resp.setCharacterEncoding("UTF-8"); ++ + String users = req.getParameter("users"); + String subject = req.getParameter("subject"); + String body = req.getParameter("body"); ++ List attaches; ++ Part filePart = req.getPart("attach"); ++ if (filePart == null) { ++ attaches = ImmutableList.of(); ++ } else { ++ attaches = ImmutableList.of(Attachments.getAttach(filePart.getName(), filePart.getInputStream())); ++ } + String groupResult; + try { +- groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body, null).toString(); ++ groupResult = MailWSClient.sendBulk(MailWSClient.split(users), subject, body, attaches).toString(); + } catch (WebStateException e) { + groupResult = e.toString(); + } diff --git a/patches/lesson09/9_4_HW8_mail_attach.patch b/patches/lesson09/9_4_HW8_mail_attach.patch new file mode 100644 index 000000000..683558d11 --- /dev/null +++ b/patches/lesson09/9_4_HW8_mail_attach.patch @@ -0,0 +1,115 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (date 1493414685000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java (revision ) +@@ -17,11 +17,11 @@ + + private static final ExecutorService mailExecutor = Executors.newFixedThreadPool(8); + +- public static GroupResult sendBulk(final Set addressees, final String subject, final String body) { ++ public static GroupResult sendBulk(final Set addressees, final String subject, final String body, List attaches) { + final CompletionService completionService = new ExecutorCompletionService<>(mailExecutor); + + List> futures = StreamEx.of(addressees) +- .map(addressee -> completionService.submit(() -> MailSender.sendTo(addressee, subject, body))) ++ .map(addressee -> completionService.submit(() -> MailSender.sendTo(addressee, subject, body, attaches))) + .toList(); + + return new Callable() { +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1493414685000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -15,11 +15,11 @@ + + @Override + public String sendToGroup(Set to, Set cc, String subject, String body, List attaches) throws WebStateException { +- return MailSender.sendToGroup(to, cc, subject, body); ++ return MailSender.sendToGroup(to, cc, subject, body, attaches); + } + + @Override + public GroupResult sendBulk(Set to, String subject, String body, List attaches) throws WebStateException { +- return MailServiceExecutor.sendBulk(to, subject, body); ++ return MailServiceExecutor.sendBulk(to, subject, body, attaches); + } + } +\ No newline at end of file +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (date 1493414685000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java (revision ) +@@ -4,29 +4,28 @@ + import com.google.common.collect.ImmutableSet; + import lombok.extern.slf4j.Slf4j; + import lombok.val; +-import org.apache.commons.mail.EmailException; + import ru.javaops.masterjava.ExceptionType; + import ru.javaops.masterjava.persist.DBIProvider; + import ru.javaops.masterjava.service.mail.persist.MailCase; + import ru.javaops.masterjava.service.mail.persist.MailCaseDao; + import ru.javaops.web.WebStateException; + ++import javax.mail.internet.MimeUtility; ++import java.io.UnsupportedEncodingException; ++import java.nio.charset.StandardCharsets; ++import java.util.List; + import java.util.Set; + +-/** +- * gkislin +- * 15.11.2016 +- */ + @Slf4j + public class MailSender { + private static final MailCaseDao MAIL_CASE_DAO = DBIProvider.getDao(MailCaseDao.class); + +- static MailResult sendTo(Addressee to, String subject, String body) throws WebStateException { +- val state = sendToGroup(ImmutableSet.of(to), ImmutableSet.of(), subject, body); ++ static MailResult sendTo(Addressee to, String subject, String body, List attaches) throws WebStateException { ++ val state = sendToGroup(ImmutableSet.of(to), ImmutableSet.of(), subject, body, attaches); + return new MailResult(to.getEmail(), state); + } + +- static String sendToGroup(Set to, Set cc, String subject, String body) throws WebStateException { ++ static String sendToGroup(Set to, Set cc, String subject, String body, List attaches) throws WebStateException { + log.info("Send mail to \'" + to + "\' cc \'" + cc + "\' subject \'" + subject + (log.isDebugEnabled() ? "\nbody=" + body : "")); + String state = MailResult.OK; + try { +@@ -39,11 +38,14 @@ + for (Addressee addressee : cc) { + email.addCc(addressee.getEmail(), addressee.getName()); + } ++ for (Attach attach : attaches) { ++ email.attach(attach.getDataHandler().getDataSource(), encodeWord(attach.getName()), null); ++ } + + // https://yandex.ru/blog/company/66296 + email.setHeaders(ImmutableMap.of("List-Unsubscribe", "")); + email.send(); +- } catch (EmailException e) { ++ } catch (Exception e) { + log.error(e.getMessage(), e); + state = e.getMessage(); + } +@@ -56,4 +58,11 @@ + log.info("Sent with state: " + state); + return state; + } ++ ++ public static String encodeWord(String word) throws UnsupportedEncodingException { ++ if (word == null) { ++ return null; ++ } ++ return MimeUtility.encodeWord(word, StandardCharsets.UTF_8.name(), null); ++ } + } diff --git a/patches/lesson09/9_5_msg_ctx_auth.patch b/patches/lesson09/9_5_msg_ctx_auth.patch new file mode 100644 index 000000000..be4c33b98 --- /dev/null +++ b/patches/lesson09/9_5_msg_ctx_auth.patch @@ -0,0 +1,142 @@ +Index: services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java (revision ) +@@ -0,0 +1,32 @@ ++package ru.javaops.web; ++ ++import lombok.extern.slf4j.Slf4j; ++ ++import javax.servlet.http.HttpServletResponse; ++import javax.xml.bind.DatatypeConverter; ++import java.util.List; ++import java.util.Map; ++ ++@Slf4j ++public class AuthUtil { ++ private static final String AUTHORIZATION = "Authorization"; ++ ++ public static String encodeBasicAuthHeader(String name, String passw) { ++ String authString = name + ":" + passw; ++ return "Basic " + DatatypeConverter.printBase64Binary(authString.getBytes()); ++ } ++ ++ public static int checkBasicAuth(Map> headers, String basicAuthCredentials) { ++ List autHeaders = headers.get(AUTHORIZATION); ++ if ((autHeaders == null || autHeaders.isEmpty())) { ++ log.warn("Unauthorized access"); ++ return HttpServletResponse.SC_UNAUTHORIZED; ++ } else { ++ if (!autHeaders.get(0).equals(basicAuthCredentials)) { ++ log.warn("Wrong password access"); ++ return HttpServletResponse.SC_FORBIDDEN; ++ } ++ return 0; ++ } ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1493415590000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -1,9 +1,14 @@ + package ru.javaops.masterjava.service.mail; + ++import ru.javaops.web.AuthUtil; + import ru.javaops.web.WebStateException; + ++import javax.annotation.Resource; + import javax.jws.WebService; ++import javax.xml.ws.WebServiceContext; ++import javax.xml.ws.handler.MessageContext; + import java.util.List; ++import java.util.Map; + import java.util.Set; + + @WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" +@@ -13,8 +18,22 @@ + //@MTOM + public class MailServiceImpl implements MailService { + ++ @Resource ++ private WebServiceContext wsContext; ++ + @Override + public String sendToGroup(Set to, Set cc, String subject, String body, List attaches) throws WebStateException { ++ MessageContext mCtx = wsContext.getMessageContext(); ++ Map> headers = (Map>) mCtx.get(MessageContext.HTTP_REQUEST_HEADERS); ++ ++// HttpServletRequest request = (HttpServletRequest) mCtx.get(MessageContext.SERVLET_REQUEST); ++// HttpServletResponse response = (HttpServletResponse) mCtx.get(MessageContext.SERVLET_RESPONSE); ++ ++ int code = AuthUtil.checkBasicAuth(headers, MailWSClient.AUTH_HEADER); ++ if (code != 0) { ++ mCtx.put(MessageContext.HTTP_RESPONSE_CODE, code); ++ throw new SecurityException(); ++ } + return MailSender.sendToGroup(to, cc, subject, body, attaches); + } + +Index: services/common-ws/src/main/java/ru/javaops/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WsClient.java (date 1493415590000) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -40,6 +40,12 @@ + return port; + } + ++ public static void setAuth(T port, String user, String password) { ++ Map requestContext = ((BindingProvider) port).getRequestContext(); ++ requestContext.put(BindingProvider.USERNAME_PROPERTY, user); ++ requestContext.put(BindingProvider.PASSWORD_PROPERTY, password); ++ } ++ + public static WebStateException getWebStateException(Exception e) { + return (e instanceof WebStateException) ? + (WebStateException) e : new WebStateException(ExceptionType.NETWORK, e); +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1493415590000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -5,6 +5,7 @@ + import com.google.common.collect.Iterables; + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; ++import ru.javaops.web.AuthUtil; + import ru.javaops.web.WebStateException; + import ru.javaops.web.WsClient; + +@@ -16,6 +17,10 @@ + @Slf4j + public class MailWSClient { + private static final WsClient WS_CLIENT; ++ public static final String USER = "user"; ++ public static final String PASSWORD = "password"; ++ ++ public static String AUTH_HEADER = AuthUtil.encodeBasicAuthHeader(USER, PASSWORD); + + static { + WS_CLIENT = new WsClient(Resources.getResource("wsdl/mailService.wsdl"), +@@ -53,7 +58,9 @@ + } + + private static MailService getPort() { +- return WS_CLIENT.getPort(new MTOMFeature(1024)); ++ MailService port = WS_CLIENT.getPort(new MTOMFeature(1024)); ++ WsClient.setAuth(port, USER, PASSWORD); ++ return port; + } + + public static Set split(String addressees) { diff --git a/patches/lesson09/9_6_logging_handlers.patch b/patches/lesson09/9_6_logging_handlers.patch new file mode 100644 index 000000000..32bef70f3 --- /dev/null +++ b/patches/lesson09/9_6_logging_handlers.patch @@ -0,0 +1,377 @@ +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java (revision ) +@@ -0,0 +1,23 @@ ++package ru.javaops.web.handler; ++ ++import com.sun.xml.ws.api.handler.MessageHandler; ++import com.sun.xml.ws.api.handler.MessageHandlerContext; ++ ++import javax.xml.namespace.QName; ++import javax.xml.ws.handler.MessageContext; ++import java.util.Set; ++ ++public abstract class SoapBaseHandler implements MessageHandler { ++ ++ public Set getHeaders() { ++ return null; ++ } ++ ++ @Override ++ public void close(MessageContext context) { ++ } ++ ++ protected static boolean isOutbound(MessageHandlerContext context) { ++ return (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); ++ } ++} +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java (revision ) +@@ -0,0 +1,120 @@ ++package ru.javaops.web.handler; ++ ++ ++import com.sun.xml.txw2.output.IndentingXMLStreamWriter; ++import com.sun.xml.ws.api.handler.MessageHandlerContext; ++import com.sun.xml.ws.api.message.Message; ++import com.sun.xml.ws.api.streaming.XMLStreamWriterFactory; ++import lombok.extern.slf4j.Slf4j; ++import org.slf4j.event.Level; ++ ++import javax.xml.stream.XMLStreamWriter; ++import java.io.ByteArrayOutputStream; ++import java.nio.charset.StandardCharsets; ++import java.util.EnumMap; ++import java.util.Map; ++ ++/** ++ * Refactored from: ++ * ++ * @see {http://weblogs.java.net/blog/ramapulavarthi/archive/2007/12/extend_your_web.html ++ * http://fisheye5.cenqua.com/browse/jax-ws-sources/jaxws-ri/samples/efficient_handler/src/efficient_handler/common/LoggingHandler.java?r=MAIN} ++ *

++ * This simple LoggingHandler will log the contents of incoming ++ * and outgoing messages. This is implemented as a MessageHandler ++ * for better performance over SOAPHandler. ++ */ ++@Slf4j ++public abstract class SoapLoggingHandler extends SoapBaseHandler { ++ ++ private final Level loggingLevel; ++ ++ protected SoapLoggingHandler(Level loggingLevel) { ++ this.loggingLevel = loggingLevel; ++ } ++ ++ private static final Map HANDLER_MAP = new EnumMap(Level.class) { ++ { ++ put(Level.TRACE, HANDLER.DEBUG); ++ put(Level.DEBUG, HANDLER.DEBUG); ++ put(Level.INFO, HANDLER.INFO); ++ put(Level.WARN, HANDLER.ERROR); ++ put(Level.ERROR, HANDLER.ERROR); ++ } ++ }; ++ ++ protected enum HANDLER { ++ NONE { ++ @Override ++ public void handleFault(MessageHandlerContext mhc) { ++ } ++ ++ @Override ++ public void handleMessage(MessageHandlerContext mhc, boolean isRequest) { ++ } ++ }, ++ ERROR { ++ private static final String REQUEST_MSG = "REQUEST_MSG"; ++ ++ public void handleFault(MessageHandlerContext context) { ++ log.error("Fault SOAP request:\n" + getMessageText(((Message) context.get(REQUEST_MSG)))); ++ } ++ ++ public void handleMessage(MessageHandlerContext context, boolean isRequest) { ++ if (isRequest) { ++ context.put(REQUEST_MSG, context.getMessage().copy()); ++ } ++ } ++ }, ++ INFO { ++ public void handleFault(MessageHandlerContext context) { ++ ERROR.handleFault(context); ++ } ++ ++ public void handleMessage(MessageHandlerContext context, boolean isRequest) { ++ ERROR.handleMessage(context, isRequest); ++ log.info((isRequest ? "SOAP request: " : "SOAP response: ") + context.getMessage().getPayloadLocalPart()); ++ } ++ }, ++ DEBUG { ++ public void handleFault(MessageHandlerContext context) { ++ log.error("Fault SOAP message:\n" + getMessageText(context.getMessage().copy())); ++ } ++ ++ public void handleMessage(MessageHandlerContext context, boolean isRequest) { ++ log.info((isRequest ? "SOAP request:\n" : "SOAP response:\n") + getMessageText(context.getMessage().copy())); ++ } ++ }; ++ ++ public abstract void handleMessage(MessageHandlerContext mhc, boolean isRequest); ++ ++ public abstract void handleFault(MessageHandlerContext mhc); ++ ++ protected static String getMessageText(Message msg) { ++ try { ++ ByteArrayOutputStream out = new ByteArrayOutputStream(); ++ XMLStreamWriter writer = XMLStreamWriterFactory.create(out, "UTF-8"); ++ IndentingXMLStreamWriter wrap = new IndentingXMLStreamWriter(writer); ++ msg.writeTo(wrap); ++ return out.toString(StandardCharsets.UTF_8.name()); ++ } catch (Exception e) { ++ log.warn("Coudn't get SOAP message for logging", e); ++ return null; ++ } ++ } ++ } ++ ++ abstract protected boolean isRequest(boolean isOutbound); ++ ++ @Override ++ public boolean handleMessage(MessageHandlerContext mhc) { ++ HANDLER_MAP.get(loggingLevel).handleMessage(mhc, isRequest(isOutbound(mhc))); ++ return true; ++ } ++ ++ @Override ++ public boolean handleFault(MessageHandlerContext mhc) { ++ HANDLER_MAP.get(loggingLevel).handleFault(mhc); ++ return true; ++ } ++} +Index: services/mail-service/src/main/resources/mailWsHandlers.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/resources/mailWsHandlers.xml (revision ) ++++ services/mail-service/src/main/resources/mailWsHandlers.xml (revision ) +@@ -0,0 +1,8 @@ ++ ++ ++ ++ SoapLoggingHandler ++ ru.javaops.web.handler.SoapServerLoggingHandler ++ ++ ++ +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java (revision ) +@@ -0,0 +1,15 @@ ++package ru.javaops.web.handler; ++ ++ ++import org.slf4j.event.Level; ++ ++public class SoapClientLoggingHandler extends SoapLoggingHandler { ++ public SoapClientLoggingHandler(Level loggingLevel) { ++ super(loggingLevel); ++ } ++ ++ @Override ++ protected boolean isRequest(boolean isOutbound) { ++ return isOutbound; ++ } ++} +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java (revision ) +@@ -0,0 +1,16 @@ ++package ru.javaops.web.handler; ++ ++ ++import org.slf4j.event.Level; ++ ++public class SoapServerLoggingHandler extends SoapLoggingHandler { ++ ++ public SoapServerLoggingHandler() { ++ super(Level.INFO); ++ } ++ ++ @Override ++ protected boolean isRequest(boolean isOutbound) { ++ return !isOutbound; ++ } ++} +\ No newline at end of file +Index: services/mail-api/pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/pom.xml (date 1493417251000) ++++ services/mail-api/pom.xml (revision ) +@@ -33,6 +33,11 @@ + common-ws + ${project.version} + ++ ++ commons-io ++ commons-io ++ 2.5 ++ + + + +\ No newline at end of file +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (date 1493417251000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -4,6 +4,7 @@ + import ru.javaops.web.WebStateException; + + import javax.annotation.Resource; ++import javax.jws.HandlerChain; + import javax.jws.WebService; + import javax.xml.ws.WebServiceContext; + import javax.xml.ws.handler.MessageContext; +@@ -16,6 +17,7 @@ + ) + //@StreamingAttachment(parseEagerly=true, memoryThreshold=40000L) + //@MTOM ++@HandlerChain(file = "mailWsHandlers.xml") + public class MailServiceImpl implements MailService { + + @Resource +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java (date 1493417251000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java (revision ) +@@ -1,6 +1,7 @@ + package ru.javaops.masterjava.service.mail.util; + + import lombok.AllArgsConstructor; ++import org.apache.commons.io.input.CloseShieldInputStream; + import ru.javaops.masterjava.service.mail.Attach; + + import javax.activation.DataHandler; +@@ -14,19 +15,16 @@ + return new Attach(name, new DataHandler(new InputStreamDataSource(inputStream))); + } + +- // http://stackoverflow.com/a/10783565/548473 ++ // http://stackoverflow.com/questions/2830561/how-to-convert-an-inputstream-to-a-datahandler ++ // http://stackoverflow.com/a/5924019/548473 ++ + @AllArgsConstructor + private static class InputStreamDataSource implements DataSource { + private InputStream inputStream; + + @Override + public InputStream getInputStream() throws IOException { +- if (inputStream == null) { +- throw new IOException("Second getInputStream() call is not supported"); +- } +- InputStream res = inputStream; +- inputStream = null; +- return res; ++ return new CloseShieldInputStream(inputStream); + } + + @Override +Index: services/common-ws/src/main/java/ru/javaops/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WsClient.java (date 1493417251000) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -5,10 +5,13 @@ + import ru.javaops.masterjava.config.Configs; + + import javax.xml.namespace.QName; ++import javax.xml.ws.Binding; + import javax.xml.ws.BindingProvider; + import javax.xml.ws.Service; + import javax.xml.ws.WebServiceFeature; ++import javax.xml.ws.handler.Handler; + import java.net.URL; ++import java.util.List; + import java.util.Map; + + public class WsClient { +@@ -46,6 +49,13 @@ + requestContext.put(BindingProvider.PASSWORD_PROPERTY, password); + } + ++ public static void setHandler(T port, Handler handler) { ++ Binding binding = ((BindingProvider) port).getBinding(); ++ List handlerList = binding.getHandlerChain(); ++ handlerList.add(handler); ++ binding.setHandlerChain(handlerList); ++ } ++ + public static WebStateException getWebStateException(Exception e) { + return (e instanceof WebStateException) ? + (WebStateException) e : new WebStateException(ExceptionType.NETWORK, e); +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1493417251000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -5,9 +5,11 @@ + import com.google.common.collect.Iterables; + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; ++import org.slf4j.event.Level; + import ru.javaops.web.AuthUtil; + import ru.javaops.web.WebStateException; + import ru.javaops.web.WsClient; ++import ru.javaops.web.handler.SoapClientLoggingHandler; + + import javax.xml.namespace.QName; + import javax.xml.ws.soap.MTOMFeature; +@@ -19,6 +21,7 @@ + private static final WsClient WS_CLIENT; + public static final String USER = "user"; + public static final String PASSWORD = "password"; ++ private static final SoapClientLoggingHandler LOGGING_HANDLER = new SoapClientLoggingHandler(Level.DEBUG); + + public static String AUTH_HEADER = AuthUtil.encodeBasicAuthHeader(USER, PASSWORD); + +@@ -60,6 +63,7 @@ + private static MailService getPort() { + MailService port = WS_CLIENT.getPort(new MTOMFeature(1024)); + WsClient.setAuth(port, USER, PASSWORD); ++ WsClient.setHandler(port, LOGGING_HANDLER); + return port; + } + diff --git a/patches/lesson09/9_7_prepare_HW9.patch b/patches/lesson09/9_7_prepare_HW9.patch new file mode 100644 index 000000000..1b87c6409 --- /dev/null +++ b/patches/lesson09/9_7_prepare_HW9.patch @@ -0,0 +1,50 @@ +Index: common/src/main/resources/hosts.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/resources/hosts.conf (revision dcac6c076c28383c7afcd0621bba01a6789b858d) ++++ common/src/main/resources/hosts.conf (revision 3c63fd8640d75a6787c8a3d25f9fc941db55ecd5) +@@ -1,4 +1,10 @@ + hosts { +- mail = "http://localhost:8080" ++ mail { ++ endpoint = "http://localhost:8080" ++ debug.client = DEBUG ++ debug.server = INFO ++ user = "user" ++ password = "password" ++ } + } + include file("/apps/masterjava/config/hosts.conf") +Index: services/common-ws/src/main/java/ru/javaops/web/Statistics.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/Statistics.java (revision 3c63fd8640d75a6787c8a3d25f9fc941db55ecd5) ++++ services/common-ws/src/main/java/ru/javaops/web/Statistics.java (revision 3c63fd8640d75a6787c8a3d25f9fc941db55ecd5) +@@ -0,0 +1,23 @@ ++package ru.javaops.web; ++ ++import lombok.extern.slf4j.Slf4j; ++ ++/** ++ * gkislin ++ * 09.01.2017 ++ */ ++@Slf4j ++public class Statistics { ++ public enum RESULT { ++ SUCCESS, FAIL ++ } ++ ++ public static void count(String payload, long startTime, RESULT result) { ++ long now = System.currentTimeMillis(); ++ int ms = (int) (now - startTime); ++ log.info(payload + " " + result.name() + " execution time(ms): " + ms); ++ // place for statistics staff ++ ++ } ++ ++} diff --git a/patches/lesson10/10_1_HW9_handlers.patch b/patches/lesson10/10_1_HW9_handlers.patch new file mode 100644 index 000000000..a6b0d11d6 --- /dev/null +++ b/patches/lesson10/10_1_HW9_handlers.patch @@ -0,0 +1,345 @@ +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandlers.java (revision ) +@@ -25,11 +25,11 @@ + * for better performance over SOAPHandler. + */ + @Slf4j +-public abstract class SoapLoggingHandler extends SoapBaseHandler { ++public abstract class SoapLoggingHandlers extends SoapBaseHandler { + + private final Level loggingLevel; + +- protected SoapLoggingHandler(Level loggingLevel) { ++ protected SoapLoggingHandlers(Level loggingLevel) { + this.loggingLevel = loggingLevel; + } + +@@ -117,4 +117,27 @@ + HANDLER_MAP.get(loggingLevel).handleFault(mhc); + return true; + } ++ ++ public static class ClientHandler extends SoapLoggingHandlers { ++ public ClientHandler(Level loggingLevel) { ++ super(loggingLevel); ++ } ++ ++ @Override ++ protected boolean isRequest(boolean isOutbound) { ++ return isOutbound; ++ } ++ } ++ ++ public static class ServerHandler extends SoapLoggingHandlers { ++ ++ public ServerHandler() { ++ super(Level.INFO); ++ } ++ ++ @Override ++ protected boolean isRequest(boolean isOutbound) { ++ return !isOutbound; ++ } ++ } + } +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java (revision ) +@@ -0,0 +1,11 @@ ++package ru.javaops.masterjava.service.mail; ++ ++import ru.javaops.web.handler.SoapServerSecurityHandler; ++ ++public class MailHandlers { ++ public static class SecurityHandler extends SoapServerSecurityHandler { ++ public SecurityHandler() { ++ super(MailWSClient.USER, MailWSClient.PASSWORD); ++ } ++ } ++} +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java (revision ) +@@ -1,41 +1,39 @@ + package ru.javaops.masterjava.service.mail; + +-import ru.javaops.web.AuthUtil; + import ru.javaops.web.WebStateException; + +-import javax.annotation.Resource; + import javax.jws.HandlerChain; + import javax.jws.WebService; +-import javax.xml.ws.WebServiceContext; +-import javax.xml.ws.handler.MessageContext; ++import javax.xml.ws.soap.MTOM; + import java.util.List; +-import java.util.Map; + import java.util.Set; + + @WebService(endpointInterface = "ru.javaops.masterjava.service.mail.MailService", targetNamespace = "http://mail.javaops.ru/" + // , wsdlLocation = "WEB-INF/wsdl/mailService.wsdl" + ) + //@StreamingAttachment(parseEagerly=true, memoryThreshold=40000L) +-//@MTOM ++@MTOM + @HandlerChain(file = "mailWsHandlers.xml") + public class MailServiceImpl implements MailService { + +- @Resource +- private WebServiceContext wsContext; ++// @Resource ++// private WebServiceContext wsContext; + + @Override + public String sendToGroup(Set to, Set cc, String subject, String body, List attaches) throws WebStateException { ++/* + MessageContext mCtx = wsContext.getMessageContext(); + Map> headers = (Map>) mCtx.get(MessageContext.HTTP_REQUEST_HEADERS); + +-// HttpServletRequest request = (HttpServletRequest) mCtx.get(MessageContext.SERVLET_REQUEST); +-// HttpServletResponse response = (HttpServletResponse) mCtx.get(MessageContext.SERVLET_RESPONSE); ++ HttpServletRequest request = (HttpServletRequest) mCtx.get(MessageContext.SERVLET_REQUEST); ++ HttpServletResponse response = (HttpServletResponse) mCtx.get(MessageContext.SERVLET_RESPONSE); + + int code = AuthUtil.checkBasicAuth(headers, MailWSClient.AUTH_HEADER); + if (code != 0) { + mCtx.put(MessageContext.HTTP_RESPONSE_CODE, code); + throw new SecurityException(); + } ++*/ + return MailSender.sendToGroup(to, cc, subject, body, attaches); + } + +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) +@@ -1,15 +0,0 @@ +-package ru.javaops.web.handler; +- +- +-import org.slf4j.event.Level; +- +-public class SoapClientLoggingHandler extends SoapLoggingHandler { +- public SoapClientLoggingHandler(Level loggingLevel) { +- super(loggingLevel); +- } +- +- @Override +- protected boolean isRequest(boolean isOutbound) { +- return isOutbound; +- } +-} +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) +@@ -1,16 +0,0 @@ +-package ru.javaops.web.handler; +- +- +-import org.slf4j.event.Level; +- +-public class SoapServerLoggingHandler extends SoapLoggingHandler { +- +- public SoapServerLoggingHandler() { +- super(Level.INFO); +- } +- +- @Override +- protected boolean isRequest(boolean isOutbound) { +- return !isOutbound; +- } +-} +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -31,7 +31,7 @@ + } + + public void init(String host, String endpointAddress) { +- this.endpointAddress = HOSTS.getString(host) + endpointAddress; ++ this.endpointAddress = HOSTS.getConfig(host).getString("endpoint") + endpointAddress; + } + + // Post is not thread-safe (http://stackoverflow.com/a/10601916/548473) +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapStatisticHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapStatisticHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapStatisticHandler.java (revision ) +@@ -0,0 +1,30 @@ ++package ru.javaops.web.handler; ++ ++import com.sun.xml.ws.api.handler.MessageHandlerContext; ++import ru.javaops.web.Statistics; ++ ++public class SoapStatisticHandler extends SoapBaseHandler { ++ ++ private static final String PAYLOAD = "PAYLOAD"; ++ private static final String START_TIME = "START_TIME"; ++ ++ public boolean handleMessage(MessageHandlerContext context) { ++ if (isOutbound(context)) { ++ count(context, Statistics.RESULT.SUCCESS); ++ } else { ++ String payload = context.getMessage().getPayloadLocalPart(); ++ context.put(PAYLOAD, payload); ++ context.put(START_TIME, System.currentTimeMillis()); ++ } ++ return true; ++ } ++ ++ public boolean handleFault(MessageHandlerContext context) { ++ count(context, Statistics.RESULT.FAIL); ++ return true; ++ } ++ ++ private void count(MessageHandlerContext context, Statistics.RESULT result) { ++ Statistics.count((String) context.get(PAYLOAD), (Long) context.get(START_TIME), result); ++ } ++} +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java (revision ) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java (revision ) +@@ -0,0 +1,43 @@ ++package ru.javaops.web.handler; ++ ++import com.sun.xml.ws.api.handler.MessageHandlerContext; ++import lombok.extern.slf4j.Slf4j; ++import ru.javaops.web.AuthUtil; ++ ++import javax.xml.ws.handler.MessageContext; ++import java.util.List; ++import java.util.Map; ++ ++import static ru.javaops.web.AuthUtil.encodeBasicAuthHeader; ++ ++@Slf4j ++abstract public class SoapServerSecurityHandler extends SoapBaseHandler { ++ ++ private String authHeader; ++ ++ public SoapServerSecurityHandler(String user, String password) { ++ this(encodeBasicAuthHeader(user, password)); ++ } ++ ++ public SoapServerSecurityHandler(String authHeader) { ++ this.authHeader = authHeader; ++ } ++ ++ @Override ++ public boolean handleMessage(MessageHandlerContext ctx) { ++ if (!isOutbound(ctx)) { ++ Map> headers = (Map>) ctx.get(MessageContext.HTTP_REQUEST_HEADERS); ++ int code = AuthUtil.checkBasicAuth(headers, authHeader); ++ if (code != 0) { ++ ctx.put(MessageContext.HTTP_RESPONSE_CODE, code); ++ throw new SecurityException(); ++ } ++ } ++ return true; ++ } ++ ++ @Override ++ public boolean handleFault(MessageHandlerContext context) { ++ return true; ++ } ++} +Index: services/mail-service/src/main/resources/mailWsHandlers.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/resources/mailWsHandlers.xml (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/mail-service/src/main/resources/mailWsHandlers.xml (revision ) +@@ -2,7 +2,15 @@ + + + SoapLoggingHandler +- ru.javaops.web.handler.SoapServerLoggingHandler ++ ru.javaops.web.handler.SoapLoggingHandlers$ServerHandler ++ ++ ++ SoapStatisticHandler ++ ru.javaops.web.handler.SoapStatisticHandler ++ ++ ++ SoapStatisticHandler ++ ru.javaops.masterjava.service.mail.MailHandlers$SecurityHandler + + + +\ No newline at end of file +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -6,10 +6,9 @@ + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; + import org.slf4j.event.Level; +-import ru.javaops.web.AuthUtil; + import ru.javaops.web.WebStateException; + import ru.javaops.web.WsClient; +-import ru.javaops.web.handler.SoapClientLoggingHandler; ++import ru.javaops.web.handler.SoapLoggingHandlers; + + import javax.xml.namespace.QName; + import javax.xml.ws.soap.MTOMFeature; +@@ -21,9 +20,7 @@ + private static final WsClient WS_CLIENT; + public static final String USER = "user"; + public static final String PASSWORD = "password"; +- private static final SoapClientLoggingHandler LOGGING_HANDLER = new SoapClientLoggingHandler(Level.DEBUG); +- +- public static String AUTH_HEADER = AuthUtil.encodeBasicAuthHeader(USER, PASSWORD); ++ private static final SoapLoggingHandlers.ClientHandler LOGGING_HANDLER = new SoapLoggingHandlers.ClientHandler(Level.DEBUG); + + static { + WS_CLIENT = new WsClient(Resources.getResource("wsdl/mailService.wsdl"), +Index: services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java (revision 52524e425e74665e0bda77f03f6ee2c565b7353c) ++++ services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java (revision ) +@@ -7,9 +7,10 @@ + import java.util.List; + import java.util.Map; + ++import static com.google.common.net.HttpHeaders.AUTHORIZATION; ++ + @Slf4j + public class AuthUtil { +- private static final String AUTHORIZATION = "Authorization"; + + public static String encodeBasicAuthHeader(String name, String passw) { + String authString = name + ":" + passw; diff --git a/patches/lesson10/10_2_HW9_host_config.patch b/patches/lesson10/10_2_HW9_host_config.patch new file mode 100644 index 000000000..999489882 --- /dev/null +++ b/patches/lesson10/10_2_HW9_host_config.patch @@ -0,0 +1,255 @@ +Index: common/src/main/resources/defaults.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/resources/defaults.conf (revision ) ++++ common/src/main/resources/defaults.conf (revision ) +@@ -0,0 +1,4 @@ ++client.debugLevel = INFO ++server.debugLevel = INFO ++user = null ++password = null +\ No newline at end of file +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java (date 1493987413000) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerSecurityHandler.java (revision ) +@@ -25,7 +25,7 @@ + + @Override + public boolean handleMessage(MessageHandlerContext ctx) { +- if (!isOutbound(ctx)) { ++ if (!isOutbound(ctx) && authHeader != null) { + Map> headers = (Map>) ctx.get(MessageContext.HTTP_REQUEST_HEADERS); + int code = AuthUtil.checkBasicAuth(headers, authHeader); + if (code != 0) { +Index: common/src/main/resources/hosts.conf +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- common/src/main/resources/hosts.conf (date 1493987413000) ++++ common/src/main/resources/hosts.conf (revision ) +@@ -1,10 +1,6 @@ + hosts { + mail { + endpoint = "http://localhost:8080" +- debug.client = DEBUG +- debug.server = INFO +- user = "user" +- password = "password" + } + } + include file("/apps/masterjava/config/hosts.conf") +Index: services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandlers.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandlers.java (date 1493987413000) ++++ services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandlers.java (revision ) +@@ -131,8 +131,8 @@ + + public static class ServerHandler extends SoapLoggingHandlers { + +- public ServerHandler() { +- super(Level.INFO); ++ public ServerHandler(Level loggingLevel) { ++ super(loggingLevel); + } + + @Override +Index: services/common-ws/src/main/java/ru/javaops/web/WsClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/common-ws/src/main/java/ru/javaops/web/WsClient.java (date 1493987413000) ++++ services/common-ws/src/main/java/ru/javaops/web/WsClient.java (revision ) +@@ -1,8 +1,10 @@ + package ru.javaops.web; + + import com.typesafe.config.Config; ++import org.slf4j.event.Level; + import ru.javaops.masterjava.ExceptionType; + import ru.javaops.masterjava.config.Configs; ++import ru.javaops.web.handler.SoapLoggingHandlers; + + import javax.xml.namespace.QName; + import javax.xml.ws.Binding; +@@ -19,7 +21,40 @@ + + private final Class serviceClass; + private final Service service; +- private String endpointAddress; ++ private HostConfig hostConfig; ++ ++ public static class HostConfig { ++ public final String endpoint; ++ public final Level serverDebugLevel; ++ public final String user; ++ public final String password; ++ public final String authHeader; ++ public final SoapLoggingHandlers.ClientHandler clientLoggingHandler; ++ ++ public HostConfig(Config config, String endpointAddress) { ++ endpoint = config.getString("endpoint") + endpointAddress; ++ serverDebugLevel = config.getEnum(Level.class, "server.debugLevel"); ++ ++// https://github.com/typesafehub/config/issues/282 ++ if (!config.getIsNull("user") && !config.getIsNull("password")) { ++ user = config.getString("user"); ++ password = config.getString("password"); ++ authHeader = AuthUtil.encodeBasicAuthHeader(user, password); ++ } else { ++ user = password = authHeader = null; ++ } ++ clientLoggingHandler = config.getIsNull("client.debugLevel") ? null : ++ new SoapLoggingHandlers.ClientHandler(config.getEnum(Level.class, "client.debugLevel")); ++ } ++ ++ public boolean hasAuthorization() { ++ return authHeader != null; ++ } ++ ++ public boolean hasHandler() { ++ return clientLoggingHandler != null; ++ } ++ } + + static { + HOSTS = Configs.getConfig("hosts.conf", "hosts"); +@@ -31,7 +66,12 @@ + } + + public void init(String host, String endpointAddress) { +- this.endpointAddress = HOSTS.getConfig(host).getString("endpoint") + endpointAddress; ++ this.hostConfig = new HostConfig( ++ HOSTS.getConfig(host).withFallback(Configs.getConfig("defaults.conf")), endpointAddress); ++ } ++ ++ public HostConfig getHostConfig() { ++ return hostConfig; + } + + // Post is not thread-safe (http://stackoverflow.com/a/10601916/548473) +@@ -39,7 +79,13 @@ + T port = service.getPort(serviceClass, features); + BindingProvider bp = (BindingProvider) port; + Map requestContext = bp.getRequestContext(); +- requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); ++ requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, hostConfig.endpoint); ++ if (hostConfig.hasAuthorization()) { ++ setAuth(port, hostConfig.user, hostConfig.password); ++ } ++ if (hostConfig.hasHandler()) { ++ setHandler(port, hostConfig.clientLoggingHandler); ++ } + return port; + } + +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java (date 1493987413000) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailHandlers.java (revision ) +@@ -1,11 +1,18 @@ + package ru.javaops.masterjava.service.mail; + ++import ru.javaops.web.handler.SoapLoggingHandlers; + import ru.javaops.web.handler.SoapServerSecurityHandler; + + public class MailHandlers { + public static class SecurityHandler extends SoapServerSecurityHandler { + public SecurityHandler() { +- super(MailWSClient.USER, MailWSClient.PASSWORD); ++ super(MailWSClient.getHostConfig().authHeader); ++ } ++ } ++ ++ public static class LoggingHandler extends SoapLoggingHandlers.ServerHandler { ++ public LoggingHandler() { ++ super(MailWSClient.getHostConfig().serverDebugLevel); + } + } + } +Index: services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (date 1493987413000) ++++ services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java (revision ) +@@ -5,10 +5,8 @@ + import com.google.common.collect.Iterables; + import com.google.common.io.Resources; + import lombok.extern.slf4j.Slf4j; +-import org.slf4j.event.Level; + import ru.javaops.web.WebStateException; + import ru.javaops.web.WsClient; +-import ru.javaops.web.handler.SoapLoggingHandlers; + + import javax.xml.namespace.QName; + import javax.xml.ws.soap.MTOMFeature; +@@ -18,9 +16,6 @@ + @Slf4j + public class MailWSClient { + private static final WsClient WS_CLIENT; +- public static final String USER = "user"; +- public static final String PASSWORD = "password"; +- private static final SoapLoggingHandlers.ClientHandler LOGGING_HANDLER = new SoapLoggingHandlers.ClientHandler(Level.DEBUG); + + static { + WS_CLIENT = new WsClient(Resources.getResource("wsdl/mailService.wsdl"), +@@ -58,14 +53,15 @@ + } + + private static MailService getPort() { +- MailService port = WS_CLIENT.getPort(new MTOMFeature(1024)); +- WsClient.setAuth(port, USER, PASSWORD); +- WsClient.setHandler(port, LOGGING_HANDLER); +- return port; ++ return WS_CLIENT.getPort(new MTOMFeature(1024)); + } + + public static Set split(String addressees) { + Iterable split = Splitter.on(',').trimResults().omitEmptyStrings().split(addressees); + return ImmutableSet.copyOf(Iterables.transform(split, Addressee::new)); + } ++ ++ public static WsClient.HostConfig getHostConfig() { ++ return WS_CLIENT.getHostConfig(); ++ } + } +Index: services/mail-service/src/main/resources/mailWsHandlers.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/resources/mailWsHandlers.xml (date 1493987413000) ++++ services/mail-service/src/main/resources/mailWsHandlers.xml (revision ) +@@ -1,15 +1,15 @@ + + + +- SoapLoggingHandler +- ru.javaops.web.handler.SoapLoggingHandlers$ServerHandler ++ MailLoggingHandler ++ ru.javaops.masterjava.service.mail.MailHandlers$LoggingHandler + + + SoapStatisticHandler + ru.javaops.web.handler.SoapStatisticHandler + + +- SoapStatisticHandler ++ MailSecurityHandler + ru.javaops.masterjava.service.mail.MailHandlers$SecurityHandler + + diff --git a/patches/lesson10/10_3_JAX_RS.patch b/patches/lesson10/10_3_JAX_RS.patch new file mode 100644 index 000000000..eb9500586 --- /dev/null +++ b/patches/lesson10/10_3_JAX_RS.patch @@ -0,0 +1,128 @@ +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRestConfig.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRestConfig.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRestConfig.java (revision ) +@@ -0,0 +1,12 @@ ++package ru.javaops.masterjava.service.mail.rest; ++ ++import org.glassfish.jersey.server.ResourceConfig; ++ ++import javax.ws.rs.ApplicationPath; ++ ++@ApplicationPath("rest") ++public class MailRestConfig extends ResourceConfig { ++ public MailRestConfig() { ++ packages("ru.javaops.masterjava.service.mail.rest"); ++ } ++} +\ No newline at end of file +Index: services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRS.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRS.java (revision ) ++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/rest/MailRS.java (revision ) +@@ -0,0 +1,32 @@ ++package ru.javaops.masterjava.service.mail.rest; ++ ++ ++import org.hibernate.validator.constraints.NotBlank; ++import ru.javaops.masterjava.service.mail.GroupResult; ++import ru.javaops.masterjava.service.mail.MailServiceExecutor; ++import ru.javaops.masterjava.service.mail.MailWSClient; ++import ru.javaops.web.WebStateException; ++ ++import javax.ws.rs.*; ++import javax.ws.rs.core.MediaType; ++import java.util.Collections; ++ ++@Path("/") ++public class MailRS { ++ @GET ++ @Path("test") ++ @Produces(MediaType.TEXT_PLAIN) ++ public String test() { ++ return "Test"; ++ } ++ ++ @POST ++ @Path("send") ++ @Produces(MediaType.APPLICATION_JSON) ++ public GroupResult send(@NotBlank @FormParam("users") String users, ++ @FormParam("subject") String subject, ++ @NotBlank @FormParam("body") String body) throws WebStateException { ++ ++ return MailServiceExecutor.sendBulk(MailWSClient.split(users), subject, body, Collections.emptyList()); ++ } ++} +\ No newline at end of file +Index: web/webapp/src/main/webapp/WEB-INF/templates/users.html +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- web/webapp/src/main/webapp/WEB-INF/templates/users.html (date 1493993350000) ++++ web/webapp/src/main/webapp/WEB-INF/templates/users.html (revision ) +@@ -36,6 +36,9 @@ + + +


++ SOAP
++ REST
++ +
+ +@@ -56,6 +59,17 @@ +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + +
#Full NameEmailFlag +
+
+
+ + + +

+ +

+

+
+

+

+ +

+

+ +

+
+
+ + + \ No newline at end of file