From 555e6c91e6fec1b76c008d390e4f6c9d50c15609 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Tue, 21 Feb 2017 17:32:43 +0300 Subject: [PATCH 01/97] Prepare to Matrix implementation --- .gitignore | 5 + README.md | 236 ++++++++++++------ pom.xml | 44 ++++ src/main/java/ru/javaops/masterjava/Main.java | 14 ++ .../javaops/masterjava/matrix/MainMatrix.java | 52 ++++ .../javaops/masterjava/matrix/MatrixUtil.java | 61 +++++ .../masterjava/service/MailService.java | 75 ++++++ 7 files changed, 409 insertions(+), 78 deletions(-) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/ru/javaops/masterjava/Main.java create mode 100644 src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java create mode 100644 src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java create mode 100644 src/main/java/ru/javaops/masterjava/service/MailService.java 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..553a75943 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,161 @@ -#### Написание с нуля полнофункционального многомодульного 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 многопоточная реализация была быстрее однопоточной + +----- +# Программа проекта + +## Занятие 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 Leeks + +## Занятие 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/pom.xml b/pom.xml new file mode 100644 index 000000000..39e811e08 --- /dev/null +++ b/pom.xml @@ -0,0 +1,44 @@ + + 4.0.0 + + ru.javaops + masterjava + jar + + 1.0-SNAPSHOT + + Master Java + https://github.com/JavaOPs/masterjava + + + 1.8 + UTF-8 + UTF-8 + + + + masterjava + install + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + + + + + + + + + + + + + + diff --git a/src/main/java/ru/javaops/masterjava/Main.java b/src/main/java/ru/javaops/masterjava/Main.java new file mode 100644 index 000000000..a849258c4 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/Main.java @@ -0,0 +1,14 @@ +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!"); + } +} diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java new file mode 100644 index 000000000..ec1c8a691 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -0,0 +1,52 @@ +package ru.javaops.masterjava.matrix; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * gkislin + * 03.07.2016 + */ +public class MainMatrix { + private static final int MATRIX_SIZE = 1000; + private static final int THREAD_NUMBER = 10; + + private final static ExecutorService executor = Executors.newFixedThreadPool(MainMatrix.THREAD_NUMBER); + + public static void main(String[] args) throws ExecutionException, InterruptedException { + final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE); + final int[][] matrixB = MatrixUtil.create(MATRIX_SIZE); + + double singleThreadSum = 0.; + double concurrentThreadSum = 0.; + int count = 1; + while (count < 6) { + System.out.println("Pass " + count); + long start = System.currentTimeMillis(); + final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); + double duration = (System.currentTimeMillis() - start) / 1000.; + out("Single thread time, sec: %.3f", duration); + singleThreadSum += duration; + + start = System.currentTimeMillis(); + final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); + duration = (System.currentTimeMillis() - start) / 1000.; + out("Concurrent thread time, sec: %.3f", duration); + concurrentThreadSum += duration; + + if (!MatrixUtil.compare(matrixC, concurrentMatrixC)) { + System.err.println("Comparison failed"); + break; + } + count++; + } + executor.shutdown(); + out("\nAverage single thread time, sec: %.3f", singleThreadSum / 5.); + out("Average concurrent thread time, sec: %.3f", concurrentThreadSum / 5.); + } + + private static void out(String format, double ms) { + System.out.println(String.format(format, ms)); + } +} diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java new file mode 100644 index 000000000..80a344ac2 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -0,0 +1,61 @@ +package ru.javaops.masterjava.matrix; + +import java.util.Random; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; + +/** + * gkislin + * 03.07.2016 + */ +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]; + + return matrixC; + } + + // TODO optimize by https://habrahabr.ru/post/114797/ + public static int[][] singleThreadMultiply(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++) { + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += matrixA[i][k] * matrixB[k][j]; + } + matrixC[i][j] = sum; + } + } + return matrixC; + } + + public static int[][] create(int size) { + int[][] matrix = new int[size][size]; + Random rn = new Random(); + + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + matrix[i][j] = rn.nextInt(10); + } + } + return matrix; + } + + public static boolean compare(int[][] matrixA, int[][] matrixB) { + final int matrixSize = matrixA.length; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + if (matrixA[i][j] != matrixB[i][j]) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/ru/javaops/masterjava/service/MailService.java b/src/main/java/ru/javaops/masterjava/service/MailService.java new file mode 100644 index 000000000..2b6aeb294 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/service/MailService.java @@ -0,0 +1,75 @@ +package ru.javaops.masterjava.service; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class MailService { + 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"; + private static final String INTERRUPTED_EXCEPTION = "+++ InterruptedException"; + + public GroupResult sendToList(final String template, final Set emails) throws Exception { + return new GroupResult(0, Collections.emptyList(), null); + } + + + // 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 From a7e872dcfd556758d75487529501d3046c7478ed Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 23 Feb 2017 00:45:35 +0300 Subject: [PATCH 02/97] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 553a75943..c22265384 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ - Maven. Поиск и разрешение конфликтов зависимостей - Логирование - Выбор lightweight JDBC helper library. JDBI -- Tomcat Class Loader. Memory Leeks +- Tomcat Class Loader. Memory Leaks ## Занятие 5 - Разбор ДЗ (реализуем модули persist, export и web) From f769412e77a9d873057b3f5e741d54cdc1a9c376 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 6 Mar 2017 13:00:07 +0300 Subject: [PATCH 03/97] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index c22265384..4d889899d 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,17 @@ - Количество дочерних потоков ограничено `MainMatrix.THREAD_NUMBER`. - Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной +----- +## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW0 +- не делайте 1000 000 тасок, лучше их сделать крупнее +- у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно +- наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply2`). Мои результаты: +``` +Benchmark (matrixSize) Mode Cnt Score Error Units +MatrixBenchmark.singleThreadMultiplyOpt 1000 ss 100 837,867 ± 25,530 ms/op +MatrixBenchmark.concurrentMultiply 1000 ss 100 394,294 ± 21,657 ms/op +MatrixBenchmark.concurrentMultiply2 1000 ss 100 186,827 ± 11,882 ms/op +``` ----- # Программа проекта From 448df867f52f7b113196e46e746b51a2790ae6de Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 6 Mar 2017 13:09:28 +0300 Subject: [PATCH 04/97] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d889899d..4adb55bfd 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ - Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной ----- -## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW0 +## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW1 - не делайте 1000 000 тасок, лучше их сделать крупнее - у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно - наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply2`). Мои результаты: From 71e338fe77986d52eb4c8ed5f39b375dbefd3ec3 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 6 Mar 2017 23:58:36 +0300 Subject: [PATCH 05/97] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4adb55bfd..de162e88f 100644 --- a/README.md +++ b/README.md @@ -91,12 +91,12 @@ ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW1 - не делайте 1000 000 тасок, лучше их сделать крупнее - у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно -- наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply2`). Мои результаты: +- наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply3`). Мои результаты: ``` Benchmark (matrixSize) Mode Cnt Score Error Units MatrixBenchmark.singleThreadMultiplyOpt 1000 ss 100 837,867 ± 25,530 ms/op -MatrixBenchmark.concurrentMultiply 1000 ss 100 394,294 ± 21,657 ms/op -MatrixBenchmark.concurrentMultiply2 1000 ss 100 186,827 ± 11,882 ms/op +MatrixBenchmark.concurrentMultiply2 1000 ss 100 394,294 ± 21,657 ms/op +MatrixBenchmark.concurrentMultiply3 1000 ss 100 186,827 ± 11,882 ms/op ``` ----- # Программа проекта From 3b5d09c40f84ec5a657ba2f0ca896b77904304c0 Mon Sep 17 00:00:00 2001 From: rolep Date: Wed, 15 Mar 2017 19:15:35 +0200 Subject: [PATCH 06/97] Tests of java concurrency 01 --- pom.xml | 8 ++ .../simplemaps/SimpleConcurrentHashMap.java | 96 +++++++++++++++++++ .../jpractice/singletons/SimpleSingleton.java | 31 ++++++ .../threads/AuthPropagationListener.java | 29 ++++++ .../jpractice/threads/ConcurrentDigits.java | 61 ++++++++++++ .../threads/DateAdapterThreadLocal.java | 36 +++++++ .../threads/SimpleSecutiryContextHolder.java | 17 ++++ .../rolep/jpractice/threads/SimpleUser.java | 7 ++ .../threads/countdownlatch/Race.java | 48 ++++++++++ .../threads/cyclicbarrier/Ferry.java | 51 ++++++++++ .../jpractice/threads/exchanger/Delivery.java | 51 ++++++++++ .../rolep/jpractice/threads/phaser/Bus.java | 84 ++++++++++++++++ .../jpractice/threads/semaphore/Parking.java | 70 ++++++++++++++ src/main/java/net/rolep/masterjava/Main.java | 14 +++ .../rolep/masterjava/matrix/MainMatrix.java | 52 ++++++++++ .../rolep/masterjava/matrix/MatrixUtil.java | 61 ++++++++++++ .../rolep/masterjava/service/MailService.java | 75 +++++++++++++++ 17 files changed, 791 insertions(+) create mode 100644 src/main/java/net/rolep/jpractice/simplemaps/SimpleConcurrentHashMap.java create mode 100644 src/main/java/net/rolep/jpractice/singletons/SimpleSingleton.java create mode 100644 src/main/java/net/rolep/jpractice/threads/AuthPropagationListener.java create mode 100644 src/main/java/net/rolep/jpractice/threads/ConcurrentDigits.java create mode 100644 src/main/java/net/rolep/jpractice/threads/DateAdapterThreadLocal.java create mode 100644 src/main/java/net/rolep/jpractice/threads/SimpleSecutiryContextHolder.java create mode 100644 src/main/java/net/rolep/jpractice/threads/SimpleUser.java create mode 100644 src/main/java/net/rolep/jpractice/threads/countdownlatch/Race.java create mode 100644 src/main/java/net/rolep/jpractice/threads/cyclicbarrier/Ferry.java create mode 100644 src/main/java/net/rolep/jpractice/threads/exchanger/Delivery.java create mode 100644 src/main/java/net/rolep/jpractice/threads/phaser/Bus.java create mode 100644 src/main/java/net/rolep/jpractice/threads/semaphore/Parking.java create mode 100644 src/main/java/net/rolep/masterjava/Main.java create mode 100644 src/main/java/net/rolep/masterjava/matrix/MainMatrix.java create mode 100644 src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java create mode 100644 src/main/java/net/rolep/masterjava/service/MailService.java diff --git a/pom.xml b/pom.xml index 39e811e08..55944d271 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,14 @@ + + + + javax.servlet + javax.servlet-api + 4.0.0-b03 + + diff --git a/src/main/java/net/rolep/jpractice/simplemaps/SimpleConcurrentHashMap.java b/src/main/java/net/rolep/jpractice/simplemaps/SimpleConcurrentHashMap.java new file mode 100644 index 000000000..11165ebeb --- /dev/null +++ b/src/main/java/net/rolep/jpractice/simplemaps/SimpleConcurrentHashMap.java @@ -0,0 +1,96 @@ +package net.rolep.jpractice.simplemaps; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.*; + +/** + * Created by rolep on 3/15/17. + */ +public class SimpleConcurrentHashMap { + + public static void main(String[] args) throws Exception { + // add this to jvm run config to set available parallel pools + // -Djava.util.concurrent.ForkJoinPool.common.parallelism=5 + System.out.println(ForkJoinPool.getCommonPoolParallelism()); + + ConcurrentHashMap map = new ConcurrentHashMap<>(); + map.put("foo", "bar"); + map.put("han", "solo"); + map.put("r2", "d2"); + map.put("c3", "p0"); + + map.forEach(1, (key, value) -> + System.out.printf("key: %s; value: %s; thread: %s\n", + key, value, Thread.currentThread().getName())); + + String result = map.search(1, (key, value) -> { + System.out.println(Thread.currentThread().getName()); + if ("foo".equals(key)) { + return value; + } + return null; + }); + + System.out.println(result); + + String result02 = map.searchValues(1, value -> { + System.out.println(Thread.currentThread().getName()); + if (value.length() > 3) { + return value; + } + return null; + }); + System.out.println(result02); + + String result03 = map.reduce(1, + (key, value) -> { + System.out.println("Transform: " + Thread.currentThread().getName()); + return key + "=" + value; + }, + (s1, s2) -> { + System.out.println("Reduce: " + Thread.currentThread().getName()); + return s1 + ", " + s2; + }); + System.out.println(result03); + + + ExecutorService executor02 = Executors.newWorkStealingPool(); + + List> callables = Arrays.asList( + () -> "task1", + () -> "task2", + () -> "task3"); + + executor02.invokeAll(callables) + .stream() + .map(future -> { + try { + return future.get(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }) + .forEach(System.out::println); + + + + ExecutorService executor03 = Executors.newWorkStealingPool(); + + List> callables02 = Arrays.asList( + callable01("task1", 2), + callable01("task2", 1), + callable01("task3", 3)); + + String result04 = executor03.invokeAny(callables02); + System.out.println("final result: " + result04); + + } + + public static Callable callable01(String result, long sleepSeconds) { + return () -> { + TimeUnit.SECONDS.sleep(sleepSeconds); + return result; + }; + } +} diff --git a/src/main/java/net/rolep/jpractice/singletons/SimpleSingleton.java b/src/main/java/net/rolep/jpractice/singletons/SimpleSingleton.java new file mode 100644 index 000000000..e39109f24 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/singletons/SimpleSingleton.java @@ -0,0 +1,31 @@ +package net.rolep.jpractice.singletons; + +/** + * Created by rolep on 3/15/17. + */ +public class SimpleSingleton { + + private static volatile SimpleSingleton instance; + + private SimpleSingleton() {} + + public static SimpleSingleton getInstance() { + +/* + if (instance==null) { + synchronized (SimpleSingleton.class) { + if (instance==null) { + instance = new SimpleSingleton(); + } + } + } + + return instance;*/ + + return SimpleSingletonHolder.INSTANCE; + } + + private static class SimpleSingletonHolder { + private static final SimpleSingleton INSTANCE = new SimpleSingleton(); + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/AuthPropagationListener.java b/src/main/java/net/rolep/jpractice/threads/AuthPropagationListener.java new file mode 100644 index 000000000..24ed30346 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/AuthPropagationListener.java @@ -0,0 +1,29 @@ +package net.rolep.jpractice.threads; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * Created by rolep on 3/15/17. + */ + +public class AuthPropagationListener implements ServletRequestListener { + + @Override + public void requestDestroyed(ServletRequestEvent sre) { + SimpleSecutiryContextHolder.setLoggedUser(null); + } + + @Override + public void requestInitialized(ServletRequestEvent sre) { + HttpServletRequest request = (HttpServletRequest) sre.getServletRequest(); + HttpSession session = request.getSession(false); + if (session == null) { + return; + } + SimpleUser user = (SimpleUser) request.getAttribute("logged_user"); + SimpleSecutiryContextHolder.setLoggedUser(user); + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/ConcurrentDigits.java b/src/main/java/net/rolep/jpractice/threads/ConcurrentDigits.java new file mode 100644 index 000000000..d989560e6 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/ConcurrentDigits.java @@ -0,0 +1,61 @@ +package net.rolep.jpractice.threads; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAccumulator; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.LongBinaryOperator; +import java.util.stream.IntStream; + +/** + * Created by rolep on 3/15/17. + */ +public class ConcurrentDigits { + + public static void main(String[] args) throws InterruptedException { + AtomicInteger atomicInt = new AtomicInteger(0); + LongAdder adder = new LongAdder(); + LongBinaryOperator op = (x, y) -> x + 2*y; + LongAccumulator accumulator = new LongAccumulator(op, 1L); + + ExecutorService executor = Executors.newFixedThreadPool(2); +/* + IntStream.range(0,1000).forEach(i -> executor.submit(atomicInt::incrementAndGet)); +*/ + +/* + IntStream.range(0, 1000).forEach(i -> { + Runnable task = () -> + atomicInt.updateAndGet(n -> n+2); + executor.submit(task); + }); +*/ + + IntStream.range(0, 1000) + .forEach(i -> { + Runnable task = () -> + atomicInt.accumulateAndGet(i, (n, m) -> n+m); + executor.submit(task); + }); + + IntStream.range(0, 1000) + .forEach(i -> executor.submit(adder::increment)); + + IntStream.range(0, 10) + .forEach(i -> executor.submit(() -> accumulator.accumulate(i))); + + executor.shutdown(); + + while (!executor.isTerminated()) Thread.sleep(50); + + System.out.println(atomicInt.get()); + + System.out.println(adder.sumThenReset()); + + System.out.println(accumulator.getThenReset()); + + System.out.println(ForkJoinPool.getCommonPoolParallelism()); + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/DateAdapterThreadLocal.java b/src/main/java/net/rolep/jpractice/threads/DateAdapterThreadLocal.java new file mode 100644 index 000000000..6fda59018 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/DateAdapterThreadLocal.java @@ -0,0 +1,36 @@ +package net.rolep.jpractice.threads; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by rolep on 3/15/17. + */ +public final class DateAdapterThreadLocal extends XmlAdapter { + + private static final ThreadLocal THREAD_CACHE = new ThreadLocal<>(); + + @Override + public Date unmarshal(String v) throws Exception { + if (v == null || v.equals("")) { + return null; + } + return getFormat().parse(v); + } + + @Override + public String marshal(Date v) throws Exception { + return getFormat().format(v); + } + + private static DateFormat getFormat() { + DateFormat format = THREAD_CACHE.get(); + if (format == null) { + format = new SimpleDateFormat("dd.MM.yyyy"); + THREAD_CACHE.set(format); + } + return format; + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/SimpleSecutiryContextHolder.java b/src/main/java/net/rolep/jpractice/threads/SimpleSecutiryContextHolder.java new file mode 100644 index 000000000..dbf430740 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/SimpleSecutiryContextHolder.java @@ -0,0 +1,17 @@ +package net.rolep.jpractice.threads; + +/** + * Created by rolep on 3/15/17. + */ +public class SimpleSecutiryContextHolder { + + private static final ThreadLocal threadLocalScope = new ThreadLocal<>(); + + public static final SimpleUser getLoggedUser() { + return threadLocalScope.get(); + } + + public static final void setLoggedUser(SimpleUser user) { + threadLocalScope.set(user); + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/SimpleUser.java b/src/main/java/net/rolep/jpractice/threads/SimpleUser.java new file mode 100644 index 000000000..322a4f158 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/SimpleUser.java @@ -0,0 +1,7 @@ +package net.rolep.jpractice.threads; + +/** + * Created by rolep on 3/15/17. + */ +public class SimpleUser { +} diff --git a/src/main/java/net/rolep/jpractice/threads/countdownlatch/Race.java b/src/main/java/net/rolep/jpractice/threads/countdownlatch/Race.java new file mode 100644 index 000000000..bf170ff25 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/countdownlatch/Race.java @@ -0,0 +1,48 @@ +package net.rolep.jpractice.threads.countdownlatch; + +import java.util.concurrent.CountDownLatch; + +/** + * Created by rolep on 3/15/17. + */ +public class Race { + + //Создаем CountDownLatch на 8 "условий" + private static final CountDownLatch START = new CountDownLatch(5); + + //Условная длина гоночной трассы + private static final int trackLength = 500000; + + public static void main(String[] args) throws InterruptedException { + for (int i = 1; i <= 5 ; i++) { + new Thread(new Car(i, (int) (Math.random()*100+50))).start(); + Thread.sleep(1000); + } + } + + public static class Car implements Runnable { + + private int carNumber; + private int carSpeed; + + public Car(int carNumber, int carSpeed) { + this.carNumber = carNumber; + this.carSpeed = carSpeed; + } + + @Override + public void run() { + try { + System.out.printf("Truck №%d is at start line.\n", carNumber); + + //Автомобиль подъехал к стартовой прямой - условие выполнено + //уменьшаем счетчик на 1 + START.countDown(); + START.await(); + System.out.printf("Truck №%d started race!\n", carNumber); + Thread.sleep(trackLength/carSpeed); + System.out.printf("Truck №%d finished!!!\n", carNumber); + } catch (InterruptedException e) {} + } + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/cyclicbarrier/Ferry.java b/src/main/java/net/rolep/jpractice/threads/cyclicbarrier/Ferry.java new file mode 100644 index 000000000..c9f0b44bb --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/cyclicbarrier/Ferry.java @@ -0,0 +1,51 @@ +package net.rolep.jpractice.threads.cyclicbarrier; + +import java.util.concurrent.CyclicBarrier; + +/** + * Created by rolep on 3/15/17. + */ +public class Ferry { + + private static final CyclicBarrier BARRIER = new CyclicBarrier(3, new FerryBoat()); + //Инициализируем барьер на три потока и таском, который будет выполняться, когда + //у барьера соберется три потока. После этого, они будут освобождены. + + public static void main(String[] args) throws InterruptedException { + for (int i = 0; i < 9; i++) { + new Thread(new Car(i)).start(); + Thread.sleep(4000); + } + } + + public static class FerryBoat implements Runnable { + @Override + public void run() { + try { + Thread.sleep(5000); + System.out.println("Ferry transfered cars!!!"); + } catch (InterruptedException e) {} + } + } + + public static class Car implements Runnable { + + private int carNumber; + + public Car(int carNumber) { + this.carNumber = carNumber; + } + + @Override + public void run() { + try { + System.out.printf("Truck №%d arrived at ferry station.\n", carNumber); + //Для указания потоку о том что он достиг барьера, нужно вызвать метод await() + //После этого данный поток блокируется, и ждет пока остальные стороны достигнут барьера + BARRIER.await(); + System.out.printf("Truck №%d continues its way.\n", carNumber); + } catch (Exception e) {} + } + } + +} diff --git a/src/main/java/net/rolep/jpractice/threads/exchanger/Delivery.java b/src/main/java/net/rolep/jpractice/threads/exchanger/Delivery.java new file mode 100644 index 000000000..c7fc5bdf2 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/exchanger/Delivery.java @@ -0,0 +1,51 @@ +package net.rolep.jpractice.threads.exchanger; + +import java.util.concurrent.Exchanger; + +/** + * Created by rolep on 3/15/17. + */ +public class Delivery { + + private static final Exchanger EXCHANGER = new Exchanger<>(); + + public static void main(String[] args) throws InterruptedException { + String[] p1 = new String[] {"{посылка A->D}", "{посылка A->C}"}; + String[] p2 = new String[] {"{посылка B->C}", "{посылка B->D}"}; + new Thread(new Truck(1, "A", "D", p1)).start(); + Thread.sleep(5000); + new Thread(new Truck(2, "B", "C", p2)).start(); + } + + public static class Truck implements Runnable { + private int number; + private String dep; + private String dest; + private String[] parcels; + + public Truck(int number, String dep, String dest, String[] parcels) { + this.number = number; + this.dep = dep; + this.dest = dest; + this.parcels = parcels; + } + + @Override + public void run() { + try { + System.out.printf("В грузовик №%d погрузили: %s и %s.\n", number, parcels[0], parcels[1]); + System.out.printf("Грузовик №%d выехал из пункта %s в пункт %s.\n", number, dep, dest); + Thread.sleep(1000 + (long)Math.random() * 5000); + System.out.printf("Грузовик №%d приехал в пункт Е.\n", number); + + parcels[1] = EXCHANGER.exchange(parcels[1]); + //При вызове exchange() поток блокируется и ждет + //пока другой поток вызовет exchange(), после этого произойдет обмен посылками + + System.out.printf("В грузовик №%d переместили посылку для пункта %s.\n", number, dest); + Thread.sleep(1000 + (long) Math.random() * 5000); + System.out.printf("Грузовик №%d приехал в %s и доставил: %s и %s.\n", number, dest, parcels[0], parcels[1]); + } catch (InterruptedException e) {} + } + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/phaser/Bus.java b/src/main/java/net/rolep/jpractice/threads/phaser/Bus.java new file mode 100644 index 000000000..476eab040 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/phaser/Bus.java @@ -0,0 +1,84 @@ +package net.rolep.jpractice.threads.phaser; + +import java.util.ArrayList; +import java.util.concurrent.Phaser; + +/** + * Created by rolep on 3/15/17. + */ +public class Bus { + + private static final Phaser PHASER = new Phaser(1); + + public static void main(String[] args) { + ArrayList passengers = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + if ((int)(Math.random() * 2) > 0) { + passengers.add(new Passenger(i, i+1)); + } + if ((int)(Math.random() * 2) > 0) { + passengers.add(new Passenger(i, 5)); + } + } + + for (int i = 0; i < 7; i++) { + switch (i) { + case 0: + System.out.println("Bus left the park."); + PHASER.arrive(); + break; + case 6: + System.out.println("Bus headed to the park."); + PHASER.arriveAndDeregister(); + break; + default: + int currentBusstop = PHASER.getPhase(); + System.out.println("Bus stop № " + currentBusstop); + + //Проверяем, есть ли пассажиры на остановке + for (Passenger p : passengers) { + if (p.departure == currentBusstop) { + //Регистрируем поток, который будет участвовать в фазах + PHASER.register(); + p.start(); + } + } + PHASER.arriveAndAwaitAdvance(); + } + } + } + + public static class Passenger extends Thread { + private int departure; + private int destination; + + public Passenger(int departure, int destination) { + this.departure = departure; + this.destination = destination; + System.out.println(this + " ждёт на остановке № " + this.departure); + } + + @Override + public void run() { + try { + System.out.println(this + " got on the bus."); + + //Пока автобус не приедет на нужную остановку(фазу) + while (PHASER.getPhase() < destination) { + PHASER.arriveAndAwaitAdvance(); + } + Thread.sleep(1); + System.out.println(this + " got off the bus."); + PHASER.arriveAndDeregister(); + } catch (InterruptedException e) {} + } + + @Override + public String toString() { + return "Passenger{" + + departure + + " -> " + destination + + '}'; + } + } +} diff --git a/src/main/java/net/rolep/jpractice/threads/semaphore/Parking.java b/src/main/java/net/rolep/jpractice/threads/semaphore/Parking.java new file mode 100644 index 000000000..7418628b1 --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/semaphore/Parking.java @@ -0,0 +1,70 @@ +package net.rolep.jpractice.threads.semaphore; + +import java.util.concurrent.Semaphore; + +/** + * Created by rolep on 3/15/17. + */ +public class Parking { + //Парковочное место занято - true, свободно - false + private static final boolean[] PARKING_PLACES = new boolean[5]; + + //Устанавливаем флаг "справедливый", в таком случае метод + //aсquire() будет раздавать разрешения в порядке очереди + private static final Semaphore SEMAPHORE = new Semaphore(5, true); + + public static void main(String[] args) throws InterruptedException { + for (int i = 0; i < 23; i++) { + new Thread(new Car(i)).start(); + Thread.sleep(400); + } + } + + + public static class Car implements Runnable { + + private int carNumber; + + public Car(int carNumber) { + this.carNumber = carNumber; + } + + @Override + public void run() { + System.out.printf("Truck №%d is at parking lot.\n", carNumber); + try { + //acquire() запрашивает доступ к следующему за вызовом этого метода блоку кода, + //если доступ не разрешен, поток вызвавший этот метод блокируется до тех пор, + //пока семафор не разрешит доступ + SEMAPHORE.acquire(); + + int parkingNumber = -1; + + //Ищем свободное место и паркуемся + synchronized (PARKING_PLACES) { + for (int i = 0; i < 5; i++) { + if (!PARKING_PLACES[i]) { + PARKING_PLACES[i] = true; + parkingNumber = i; + System.out.printf("Truck №%d parked at lot №%d.\n", carNumber, parkingNumber); + break; + } + } + } + + + Thread.sleep(5000); //Doing smthing, shopping etc + + synchronized (PARKING_PLACES) { + PARKING_PLACES[parkingNumber] = false; //Freeing parking lot + } + + //release(), напротив, освобождает ресурс + SEMAPHORE.release(); + System.out.printf("Truck №%d left parking lot.\n", carNumber); + } catch (InterruptedException e) { + + } + } + } +} diff --git a/src/main/java/net/rolep/masterjava/Main.java b/src/main/java/net/rolep/masterjava/Main.java new file mode 100644 index 000000000..3a348b7d8 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/Main.java @@ -0,0 +1,14 @@ +package net.rolep.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!"); + } +} diff --git a/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java b/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java new file mode 100644 index 000000000..e0ea6e626 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java @@ -0,0 +1,52 @@ +package net.rolep.masterjava.matrix; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * gkislin + * 03.07.2016 + */ +public class MainMatrix { + private static final int MATRIX_SIZE = 1000; + private static final int THREAD_NUMBER = 10; + + private final static ExecutorService executor = Executors.newFixedThreadPool(MainMatrix.THREAD_NUMBER); + + public static void main(String[] args) throws ExecutionException, InterruptedException { + final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE); + final int[][] matrixB = MatrixUtil.create(MATRIX_SIZE); + + double singleThreadSum = 0.; + double concurrentThreadSum = 0.; + int count = 1; + while (count < 6) { + System.out.println("Pass " + count); + long start = System.currentTimeMillis(); + final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); + double duration = (System.currentTimeMillis() - start) / 1000.; + out("Single thread time, sec: %.3f", duration); + singleThreadSum += duration; + + start = System.currentTimeMillis(); + final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); + duration = (System.currentTimeMillis() - start) / 1000.; + out("Concurrent thread time, sec: %.3f", duration); + concurrentThreadSum += duration; + + if (!MatrixUtil.compare(matrixC, concurrentMatrixC)) { + System.err.println("Comparison failed"); + break; + } + count++; + } + executor.shutdown(); + out("\nAverage single thread time, sec: %.3f", singleThreadSum / 5.); + out("Average concurrent thread time, sec: %.3f", concurrentThreadSum / 5.); + } + + private static void out(String format, double ms) { + System.out.println(String.format(format, ms)); + } +} diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java new file mode 100644 index 000000000..f2eb379f2 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java @@ -0,0 +1,61 @@ +package net.rolep.masterjava.matrix; + +import java.util.Random; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; + +/** + * gkislin + * 03.07.2016 + */ +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]; + + return matrixC; + } + + // TODO optimize by https://habrahabr.ru/post/114797/ + public static int[][] singleThreadMultiply(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++) { + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += matrixA[i][k] * matrixB[k][j]; + } + matrixC[i][j] = sum; + } + } + return matrixC; + } + + public static int[][] create(int size) { + int[][] matrix = new int[size][size]; + Random rn = new Random(); + + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + matrix[i][j] = rn.nextInt(10); + } + } + return matrix; + } + + public static boolean compare(int[][] matrixA, int[][] matrixB) { + final int matrixSize = matrixA.length; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + if (matrixA[i][j] != matrixB[i][j]) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/net/rolep/masterjava/service/MailService.java b/src/main/java/net/rolep/masterjava/service/MailService.java new file mode 100644 index 000000000..22b1d849d --- /dev/null +++ b/src/main/java/net/rolep/masterjava/service/MailService.java @@ -0,0 +1,75 @@ +package net.rolep.masterjava.service; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class MailService { + 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"; + private static final String INTERRUPTED_EXCEPTION = "+++ InterruptedException"; + + public GroupResult sendToList(final String template, final Set emails) throws Exception { + return new GroupResult(0, Collections.emptyList(), null); + } + + + // 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 From 0348b3f8637ba6095c9a98c76019c8ace5f02c19 Mon Sep 17 00:00:00 2001 From: rolep Date: Thu, 16 Mar 2017 17:04:08 +0200 Subject: [PATCH 07/97] 01 hw first task done --- .../jpractice/threads/syncing/SimpleSync.java | 47 +++++++++++++++++++ .../rolep/masterjava/matrix/MatrixUtil.java | 13 ++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/rolep/jpractice/threads/syncing/SimpleSync.java diff --git a/src/main/java/net/rolep/jpractice/threads/syncing/SimpleSync.java b/src/main/java/net/rolep/jpractice/threads/syncing/SimpleSync.java new file mode 100644 index 000000000..e11a9241a --- /dev/null +++ b/src/main/java/net/rolep/jpractice/threads/syncing/SimpleSync.java @@ -0,0 +1,47 @@ +package net.rolep.jpractice.threads.syncing; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.IntStream; + +/** + * Created by rolep on 3/16/17. + */ +public class SimpleSync { + + int count = 0; + void increment() { + count++; + } + + synchronized void incrementSync() { + count++; + } + + ReentrantLock lock = new ReentrantLock(); + + void incrementLock() { + lock.lock(); + try { + count++; + } finally { + lock.unlock(); + } + } + + void calculate() throws InterruptedException{ + ExecutorService executor = Executors.newFixedThreadPool(4); + + IntStream.range(0, 100000) + .forEach(i -> executor.submit(this::incrementSync)); + + executor.shutdown(); + while (!executor.isTerminated()) Thread.sleep(50); + System.out.println(count); + } + + public static void main(String[] args) throws InterruptedException { + new SimpleSync().calculate(); + } +} diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java index f2eb379f2..09bac2e6a 100644 --- a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java @@ -15,6 +15,8 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; + final int[][]matrixBT = new int[matrixSize][matrixSize]; + return matrixC; } @@ -23,11 +25,20 @@ public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; + final int[][] matrixBT = new int[matrixSize][matrixSize]; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + matrixBT[j][i] = matrixB[i][j]; + } + } + for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { int sum = 0; for (int k = 0; k < matrixSize; k++) { - sum += matrixA[i][k] * matrixB[k][j]; +// sum += matrixA[i][k] * matrixB[k][j]; + sum += matrixA[i][k] * matrixBT[j][k]; + } matrixC[i][j] = sum; } From 6cdbb7026ecef3ab95b2ef79b43b87afdbba30a5 Mon Sep 17 00:00:00 2001 From: rolep Date: Fri, 17 Mar 2017 17:26:22 +0200 Subject: [PATCH 08/97] HW 01 Concurrent done. Trying second implementation with accumulating result --- patches/1_1_MailService.patch | 96 +++++++++++++++++ .../rolep/masterjava/matrix/MainMatrix.java | 7 ++ .../rolep/masterjava/matrix/MatrixUtil.java | 100 +++++++++++++++++- 3 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 patches/1_1_MailService.patch 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/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java b/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java index e0ea6e626..4c4466c44 100644 --- a/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java +++ b/src/main/java/net/rolep/masterjava/matrix/MainMatrix.java @@ -18,6 +18,13 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE); final int[][] matrixB = MatrixUtil.create(MATRIX_SIZE); +/* + MatrixUtil.printMatrix(matrixA); + System.out.println(); + MatrixUtil.printMatrix(matrixB); + System.out.println(); +*/ + double singleThreadSum = 0.; double concurrentThreadSum = 0.; int count = 1; diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java index 09bac2e6a..f47960bb4 100644 --- a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java @@ -1,8 +1,14 @@ package net.rolep.masterjava.matrix; +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * gkislin @@ -15,8 +21,89 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - final int[][]matrixBT = new int[matrixSize][matrixSize]; + final int[][] matrixBT = new int[matrixSize][matrixSize]; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + matrixBT[j][i] = matrixB[i][j]; + } + } + + List> tasks = new ArrayList<>(); + IntStream.range(0, matrixSize) + .forEach(i -> + tasks.add(i, () -> { + int[] line = new int[matrixSize]; + for (int j = 0; j < matrixSize; j++) { + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += matrixA[i][k] * matrixBT[j][k]; + } + line[j] = sum; + } + return line; + }) + ); + List> lines = tasks.stream() + .map(executor::submit) + .collect(Collectors.toList()); + + lines.forEach(future -> { + try { + matrixC[lines.indexOf(future)] = future.get(); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + }); + return matrixC; + } + + public static int[][] concurrentMultiply3(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + + final int[][] matrixBT = new int[matrixSize][matrixSize]; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + matrixBT[j][i] = matrixB[i][j]; + } + } + + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + int res = matrixA[i][j] * matrixB[i][j]; + } + } + + + List> tasks = new ArrayList<>(); + IntStream.range(0, matrixSize) + .forEach(i -> + tasks.add(i, () -> { + int[] line = new int[matrixSize]; + for (int j = 0; j < matrixSize; j++) { + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += matrixA[i][k] * matrixBT[j][k]; + } + line[j] = sum; + } + return line; + }) + ); + + List> lines = tasks.stream() + .map(executor::submit) + .collect(Collectors.toList()); + + lines.forEach(future -> { + try { + matrixC[lines.indexOf(future)] = future.get(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }); return matrixC; } @@ -38,7 +125,6 @@ public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { for (int k = 0; k < matrixSize; k++) { // sum += matrixA[i][k] * matrixB[k][j]; sum += matrixA[i][k] * matrixBT[j][k]; - } matrixC[i][j] = sum; } @@ -69,4 +155,14 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { } return true; } + + public static void printMatrix(int[][] matrix) { + for (int i = 0; i < matrix.length; i++) { + System.out.print("\n[ "); + for (int j = 0; j < matrix[i].length; j++) { + System.out.print(matrix[i][j] + " "); + } + System.out.print("]"); + } + } } From ea2636274f3b854647d2f1fd6963132799b49bc5 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 11:11:26 +0200 Subject: [PATCH 09/97] HW1 mailservice updated --- .../rolep/masterjava/matrix/MatrixUtil.java | 1 - .../rolep/masterjava/service/MailService.java | 80 +++++++++++++++++-- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java index f47960bb4..92424e490 100644 --- a/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixUtil.java @@ -76,7 +76,6 @@ public static int[][] concurrentMultiply3(int[][] matrixA, int[][] matrixB, Exec } } - List> tasks = new ArrayList<>(); IntStream.range(0, matrixSize) .forEach(i -> diff --git a/src/main/java/net/rolep/masterjava/service/MailService.java b/src/main/java/net/rolep/masterjava/service/MailService.java index 22b1d849d..82e7b3ddb 100644 --- a/src/main/java/net/rolep/masterjava/service/MailService.java +++ b/src/main/java/net/rolep/masterjava/service/MailService.java @@ -1,8 +1,10 @@ package net.rolep.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,72 @@ public class MailService { 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 (InterruptedException e) { + return cancelWithFail(INTERRUPTED_EXCEPTION); + } catch (ExecutionException e) { + return cancelWithFail(e.getCause().toString()); + } + } +/* 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 { @@ -31,6 +95,11 @@ public static class MailResult { private final String email; private final String result; + private MailResult(String email, String cause) { + this.email = email; + this.result = cause; + } + private static MailResult ok(String email) { return new MailResult(email, OK); } @@ -43,11 +112,6 @@ 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 + ')'; From 11528633aa2ab425f16f1640c8b9147c229dc870 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 11:12:37 +0200 Subject: [PATCH 10/97] 1 1 MailService --- .../masterjava/service/MailService.java | 72 ++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/service/MailService.java b/src/main/java/ru/javaops/masterjava/service/MailService.java index 2b6aeb294..cef46e55e 100644 --- a/src/main/java/ru/javaops/masterjava/service/MailService.java +++ b/src/main/java/ru/javaops/masterjava/service/MailService.java @@ -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 @@ public class MailService { 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 { From e756595f1b7e6d41abf90f1e5011edc8c5dba43c Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 12:43:23 +0200 Subject: [PATCH 11/97] lesson 2 patches added --- .../2_01_HW1_singleThreadMultiplyOpt.patch | 54 ++ .../2_02_HW1_concurrentMultiply.patch | 182 +++++ .../2_03_HW1_concurrentMultiply3.patch | 163 ++++ .../lesson02/2_04_JMH_Benchmark_patch.patch | 95 +++ patches/lesson02/2_05_JMH_main_jar.patch | 107 +++ patches/lesson02/2_06_xml_scheme.patch | 754 ++++++++++++++++++ patches/lesson02/2_07_JAXB.patch | 358 +++++++++ patches/lesson02/2_08_StAX.patch | 117 +++ patches/lesson02/2_09_XPath.patch | 109 +++ patches/lesson02/2_10_Xslt.patch | 104 +++ 10 files changed, 2043 insertions(+) create mode 100644 patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch create mode 100644 patches/lesson02/2_02_HW1_concurrentMultiply.patch create mode 100644 patches/lesson02/2_03_HW1_concurrentMultiply3.patch create mode 100644 patches/lesson02/2_04_JMH_Benchmark_patch.patch create mode 100644 patches/lesson02/2_05_JMH_main_jar.patch create mode 100644 patches/lesson02/2_06_xml_scheme.patch create mode 100644 patches/lesson02/2_07_JAXB.patch create mode 100644 patches/lesson02/2_08_StAX.patch create mode 100644 patches/lesson02/2_09_XPath.patch create mode 100644 patches/lesson02/2_10_Xslt.patch diff --git a/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch b/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch new file mode 100644 index 000000000..d6368b376 --- /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..ff696a9e5 --- /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..ee3b74d2c --- /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..f7e15ada0 --- /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..f40846f23 --- /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..3aa5bcbb0 --- /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..e04a27b68 --- /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..26a9fc3ab --- /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..675cac038 --- /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..cc3a067ca --- /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)); ++ } ++ } ++} From 5cf866b752d2e87fceb021aa05e55f8412e6dbe6 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 12:49:57 +0200 Subject: [PATCH 12/97] lesson 2 patches crlf removed --- .../2_01_HW1_singleThreadMultiplyOpt.patch | 108 +- .../2_02_HW1_concurrentMultiply.patch | 364 ++-- .../2_03_HW1_concurrentMultiply3.patch | 326 ++-- .../lesson02/2_04_JMH_Benchmark_patch.patch | 190 +-- patches/lesson02/2_05_JMH_main_jar.patch | 214 +-- patches/lesson02/2_06_xml_scheme.patch | 1508 ++++++++--------- patches/lesson02/2_07_JAXB.patch | 716 ++++---- patches/lesson02/2_08_StAX.patch | 234 +-- patches/lesson02/2_09_XPath.patch | 218 +-- patches/lesson02/2_10_Xslt.patch | 208 +-- 10 files changed, 2043 insertions(+), 2043 deletions(-) diff --git a/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch b/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch index d6368b376..64e55f4ba 100644 --- a/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch +++ b/patches/lesson02/2_01_HW1_singleThreadMultiplyOpt.patch @@ -1,54 +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; +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 index ff696a9e5..f0bc080a4 100644 --- a/patches/lesson02/2_02_HW1_concurrentMultiply.patch +++ b/patches/lesson02/2_02_HW1_concurrentMultiply.patch @@ -1,182 +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 +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 index ee3b74d2c..edc3a1457 100644 --- a/patches/lesson02/2_03_HW1_concurrentMultiply3.patch +++ b/patches/lesson02/2_03_HW1_concurrentMultiply3.patch @@ -1,163 +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; +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 index f7e15ada0..a6dd998d0 100644 --- a/patches/lesson02/2_04_JMH_Benchmark_patch.patch +++ b/patches/lesson02/2_04_JMH_Benchmark_patch.patch @@ -1,95 +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 -+ - - - +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 index f40846f23..4033562e9 100644 --- a/patches/lesson02/2_05_JMH_main_jar.patch +++ b/patches/lesson02/2_05_JMH_main_jar.patch @@ -1,107 +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); - } +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 index 3aa5bcbb0..5222ac908 100644 --- a/patches/lesson02/2_06_xml_scheme.patch +++ b/patches/lesson02/2_06_xml_scheme.patch @@ -1,754 +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); -+ } -+ -+} +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 index e04a27b68..f319308e8 100644 --- a/patches/lesson02/2_07_JAXB.patch +++ b/patches/lesson02/2_07_JAXB.patch @@ -1,358 +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 - - - +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 index 26a9fc3ab..30167fae5 100644 --- a/patches/lesson02/2_08_StAX.patch +++ b/patches/lesson02/2_08_StAX.patch @@ -1,117 +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 +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 index 675cac038..4745b852f 100644 --- a/patches/lesson02/2_09_XPath.patch +++ b/patches/lesson02/2_09_XPath.patch @@ -1,109 +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 +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 index cc3a067ca..bf72e67b2 100644 --- a/patches/lesson02/2_10_Xslt.patch +++ b/patches/lesson02/2_10_Xslt.patch @@ -1,104 +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)); -+ } -+ } -+} +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)); ++ } ++ } ++} From f5152a0fd448c058899887ef320013bc82c4a1ab Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 12:54:47 +0200 Subject: [PATCH 13/97] 2 01 HW1 --- .../javaops/masterjava/matrix/MainMatrix.java | 2 +- .../javaops/masterjava/matrix/MatrixUtil.java | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index ec1c8a691..0695132ef 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -24,7 +24,7 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc 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/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 80a344ac2..64cfdbe81 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -18,18 +18,24 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu 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; From e793385ac69a6731ec3efdd736356df550fb3382 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 14:30:51 +0200 Subject: [PATCH 14/97] 2 02 HW1 concurrentMultiply --- .../javaops/masterjava/matrix/MatrixUtil.java | 153 +++++++++++++++++- 1 file changed, 148 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 64cfdbe81..46fd00ede 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -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 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { } return true; } -} +} \ No newline at end of file From 98a1bb23a419403ddd718cb956b6f2a0856cf478 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 14:31:58 +0200 Subject: [PATCH 15/97] 2 03 HW1 concurrentMultiply3 --- .../javaops/masterjava/matrix/MainMatrix.java | 2 +- .../javaops/masterjava/matrix/MatrixUtil.java | 120 +++++------------- 2 files changed, 33 insertions(+), 89 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index 0695132ef..4f30e499a 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc 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/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 46fd00ede..39f077898 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -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 @@ public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, Exec 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]; From 14ef81f5593f9fe6bc5e3e5dd2470411729dd81f Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 15:20:15 +0200 Subject: [PATCH 16/97] l2 my jmh changes added --- pom.xml | 53 +++++++++++++++ .../masterjava/matrix/MatrixBenchmark.java | 66 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java diff --git a/pom.xml b/pom.xml index 55944d271..04349af2f 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ 1.8 UTF-8 UTF-8 + 1.18 @@ -30,6 +31,43 @@ ${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 + + + + + + + + @@ -42,6 +80,21 @@ 4.0.0-b03 + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java b/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java new file mode 100644 index 000000000..afd399a84 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java @@ -0,0 +1,66 @@ +package net.rolep.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; +import java.util.concurrent.TimeUnit; + +/** + * Created by rolep on 3/18/17. + */ +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@BenchmarkMode({Mode.SingleShotTime}) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Threads(1) +@Fork(10) +@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 static final 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); + } + + public static void main(String[] args) throws RunnerException { + Options options = new OptionsBuilder() + .include(MatrixBenchmark.class.getSimpleName()) + .threads(1) + .forks(1) + .timeout(TimeValue.minutes(5)) + .build(); + new Runner(options).run(); + } + + @Benchmark + public int[][] singleThreadMultiply() throws Exception { + return MatrixUtil.singleThreadMultiply(matrixA, matrixB); + } + + @Benchmark + public int[][] concurrentMultiply() throws Exception { + return MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); + } + + @TearDown + public void tearDown() { + executor.shutdown(); + } +} From adf926604eed3c98fd3d897331ffa8f0fced09d8 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 15:21:00 +0200 Subject: [PATCH 17/97] 2 04 JMH Benchmark patch --- .../masterjava/matrix/MatrixBenchmark.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java new file mode 100644 index 000000000..6c056aacc --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java @@ -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(); + } +} From 2d10def701c4499d1712b7a368145d9a3de97909 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 18 Mar 2017 15:22:20 +0200 Subject: [PATCH 18/97] l2 my jmh changes added - forks set to 10 --- .../masterjava/matrix/MatrixBenchmark.java | 2 +- .../masterjava/matrix/MatrixBenchmark.java | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java b/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java index afd399a84..12bf03be5 100644 --- a/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java +++ b/src/main/java/net/rolep/masterjava/matrix/MatrixBenchmark.java @@ -43,7 +43,7 @@ public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(MatrixBenchmark.class.getSimpleName()) .threads(1) - .forks(1) + .forks(10) .timeout(TimeValue.minutes(5)) .build(); new Runner(options).run(); diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java index 6c056aacc..80f1558ea 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java @@ -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 @@ public void setUp() { 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); } From 56f97b3e654702e025c7a453c0f5d49a4ee5c37e Mon Sep 17 00:00:00 2001 From: rolep Date: Mon, 20 Mar 2017 09:47:12 +0200 Subject: [PATCH 19/97] l2 my first xml changes added --- src/main/test/java/resources/payload.xml | 25 +++++++++++ src/main/test/java/resources/payload.xsd | 56 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/main/test/java/resources/payload.xml create mode 100644 src/main/test/java/resources/payload.xsd diff --git a/src/main/test/java/resources/payload.xml b/src/main/test/java/resources/payload.xml new file mode 100644 index 000000000..5b4d5337f --- /dev/null +++ b/src/main/test/java/resources/payload.xml @@ -0,0 +1,25 @@ + + + + gmail@gmail.com + Full Name + + + + admin@javaops.ru + Admin + + + mail@yandex.ru + Deleted + + + + + Санкт-Петербург + Киев + Минск + + \ No newline at end of file diff --git a/src/main/test/java/resources/payload.xsd b/src/main/test/java/resources/payload.xsd new file mode 100644 index 000000000..2229ec35f --- /dev/null +++ b/src/main/test/java/resources/payload.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 86bf71dc07518409dfce946dd12ad198eee8f1ab Mon Sep 17 00:00:00 2001 From: rolep Date: Mon, 20 Mar 2017 22:51:21 +0200 Subject: [PATCH 20/97] l2 6 my classes generated from schema --- .../masterjava/xml/schema/CityType.java | 94 +++++++ .../masterjava/xml/schema/FlagType.java | 54 ++++ .../masterjava/xml/schema/ObjectFactory.java | 85 +++++++ .../masterjava/xml/schema/Payload.java | 233 ++++++++++++++++++ .../javaops/masterjava/xml/schema/User.java | 151 ++++++++++++ .../{test/java => }/resources/payload.xsd | 0 .../test/java => test}/resources/payload.xml | 0 7 files changed, 617 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/CityType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/Payload.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/User.java rename src/main/{test/java => }/resources/payload.xsd (100%) rename src/{main/test/java => test}/resources/payload.xml (100%) diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java new file mode 100644 index 000000000..029e352cb --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java @@ -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; + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java new file mode 100644 index 000000000..eda39fa9a --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java @@ -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); + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java new file mode 100644 index 000000000..e8f105e2a --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java @@ -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/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java new file mode 100644 index 000000000..2a6276490 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java @@ -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; + } + + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java new file mode 100644 index 000000000..fee43e99d --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -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="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
+ *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+ *     </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 = "city", required = true) + @XmlIDREF + @XmlSchemaType(name = "IDREF") + protected Object city; + @XmlAttribute(name = "flag", required = true) + protected FlagType flag; + + /** + * 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 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; + } + + /** + * 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; + } + +} diff --git a/src/main/test/java/resources/payload.xsd b/src/main/resources/payload.xsd similarity index 100% rename from src/main/test/java/resources/payload.xsd rename to src/main/resources/payload.xsd diff --git a/src/main/test/java/resources/payload.xml b/src/test/resources/payload.xml similarity index 100% rename from src/main/test/java/resources/payload.xml rename to src/test/resources/payload.xml From 8133ab4c6a05b347272881455aaea1aa4f3b956d Mon Sep 17 00:00:00 2001 From: rolep Date: Mon, 20 Mar 2017 23:06:04 +0200 Subject: [PATCH 21/97] 2 06 xml scheme + copy to rolep path --- .../rolep/masterjava/xml/schema/CityType.java | 94 +++++++ .../rolep/masterjava/xml/schema/FlagType.java | 54 ++++ .../masterjava/xml/schema/ObjectFactory.java | 85 +++++++ .../rolep/masterjava/xml/schema/Payload.java | 233 ++++++++++++++++++ .../net/rolep/masterjava/xml/schema/User.java | 151 ++++++++++++ .../javaops/masterjava/xml/schema/User.java | 38 +-- src/main/resources/myPayload.xsd | 56 +++++ src/test/resources/myPayload.xml | 25 ++ 8 files changed, 717 insertions(+), 19 deletions(-) create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/CityType.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/FlagType.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/Payload.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/User.java create mode 100644 src/main/resources/myPayload.xsd create mode 100644 src/test/resources/myPayload.xml diff --git a/src/main/java/net/rolep/masterjava/xml/schema/CityType.java b/src/main/java/net/rolep/masterjava/xml/schema/CityType.java new file mode 100644 index 000000000..ce79bbd2f --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/CityType.java @@ -0,0 +1,94 @@ + +package net.rolep.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://rolep.net", 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; + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/FlagType.java b/src/main/java/net/rolep/masterjava/xml/schema/FlagType.java new file mode 100644 index 000000000..4682ee75c --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/FlagType.java @@ -0,0 +1,54 @@ + +package net.rolep.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://rolep.net") +@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); + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java new file mode 100644 index 000000000..a0300865e --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java @@ -0,0 +1,85 @@ + +package net.rolep.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 net.rolep.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://rolep.net", "City"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: net.rolep.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://rolep.net", name = "City") + public JAXBElement createCity(CityType value) { + return new JAXBElement(_City_QNAME, CityType.class, null, value); + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Payload.java b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java new file mode 100644 index 000000000..9463a9e30 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java @@ -0,0 +1,233 @@ + +package net.rolep.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://rolep.net}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://rolep.net}User"/>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </all>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + +}) +@XmlRootElement(name = "Payload", namespace = "http://rolep.net") +public class Payload { + + @XmlElement(name = "Cities", namespace = "http://rolep.net", required = true) + protected Payload.Cities cities; + @XmlElement(name = "Users", namespace = "http://rolep.net", 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://rolep.net}City"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "city" + }) + public static class Cities { + + @XmlElement(name = "City", namespace = "http://rolep.net", 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://rolep.net}User"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "user" + }) + public static class Users { + + @XmlElement(name = "User", namespace = "http://rolep.net") + 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; + } + + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/User.java b/src/main/java/net/rolep/masterjava/xml/schema/User.java new file mode 100644 index 000000000..170103bea --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/User.java @@ -0,0 +1,151 @@ + +package net.rolep.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="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
+ *       <attribute name="flag" use="required" type="{http://rolep.net}flagType" />
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "email", + "fullName" +}) +@XmlRootElement(name = "User", namespace = "http://rolep.net") +public class User { + + @XmlElement(namespace = "http://rolep.net", required = true) + protected String email; + @XmlElement(namespace = "http://rolep.net", required = true) + protected String fullName; + @XmlAttribute(name = "city", required = true) + @XmlIDREF + @XmlSchemaType(name = "IDREF") + protected Object city; + @XmlAttribute(name = "flag", required = true) + protected FlagType flag; + + /** + * 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 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; + } + + /** + * 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; + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java index fee43e99d..b3430ce71 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/User.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -24,8 +24,8 @@ * <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="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" /> * <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> @@ -45,12 +45,12 @@ public class User { 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 = "flag", required = true) - protected FlagType flag; /** * Gets the value of the email property. @@ -101,51 +101,51 @@ public void setFullName(String value) { } /** - * Gets the value of the city property. + * Gets the value of the flag property. * * @return * possible object is - * {@link Object } + * {@link FlagType } * */ - public Object getCity() { - return city; + public FlagType getFlag() { + return flag; } /** - * Sets the value of the city property. + * Sets the value of the flag property. * * @param value * allowed object is - * {@link Object } + * {@link FlagType } * */ - public void setCity(Object value) { - this.city = value; + public void setFlag(FlagType value) { + this.flag = value; } /** - * Gets the value of the flag property. + * Gets the value of the city property. * * @return * possible object is - * {@link FlagType } + * {@link Object } * */ - public FlagType getFlag() { - return flag; + public Object getCity() { + return city; } /** - * Sets the value of the flag property. + * Sets the value of the city property. * * @param value * allowed object is - * {@link FlagType } + * {@link Object } * */ - public void setFlag(FlagType value) { - this.flag = value; + public void setCity(Object value) { + this.city = value; } } diff --git a/src/main/resources/myPayload.xsd b/src/main/resources/myPayload.xsd new file mode 100644 index 000000000..648bf83d0 --- /dev/null +++ b/src/main/resources/myPayload.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/myPayload.xml b/src/test/resources/myPayload.xml new file mode 100644 index 000000000..8931f1b50 --- /dev/null +++ b/src/test/resources/myPayload.xml @@ -0,0 +1,25 @@ + + + + gmail@gmail.com + Full Name + + + + admin@javaops.ru + Admin + + + mail@yandex.ru + Deleted + + + + + Санкт-Петербург + Киев + Минск + + \ No newline at end of file From c4d352848a9daf79a29b137b145aa275aaf09671 Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 01:07:03 +0200 Subject: [PATCH 22/97] 2 07 - my Jaxb --- pom.xml | 27 +++++- .../masterjava/xml/util/JaxbMarshaller.java | 43 ++++++++++ .../rolep/masterjava/xml/util/JaxbParser.java | 83 +++++++++++++++++++ .../masterjava/xml/util/JaxbUnmarshaller.java | 36 ++++++++ .../rolep/masterjava/xml/util/Schemas.java | 49 +++++++++++ .../masterjava/xml/util/JaxbParserTest.java | 43 ++++++++++ src/test/resources/myCity.xml | 4 + 7 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/rolep/masterjava/xml/util/JaxbMarshaller.java create mode 100644 src/main/java/net/rolep/masterjava/xml/util/JaxbParser.java create mode 100644 src/main/java/net/rolep/masterjava/xml/util/JaxbUnmarshaller.java create mode 100644 src/main/java/net/rolep/masterjava/xml/util/Schemas.java create mode 100644 src/test/java/net/rolep/masterjava/xml/util/JaxbParserTest.java create mode 100644 src/test/resources/myCity.xml diff --git a/pom.xml b/pom.xml index 04349af2f..d3462a04d 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,8 @@ UTF-8 UTF-8 1.18 + 21.0 + 4.12 @@ -31,7 +33,15 @@ ${java.version} - + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + -Dfile.encoding=UTF-8 + + org.apache.maven.plugins maven-shade-plugin @@ -95,6 +105,21 @@ provided + + + com.google.guava + guava + ${guava.version} + + + + + junit + junit + ${junit.version} + test + + diff --git a/src/main/java/net/rolep/masterjava/xml/util/JaxbMarshaller.java b/src/main/java/net/rolep/masterjava/xml/util/JaxbMarshaller.java new file mode 100644 index 000000000..fe0e5b86e --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/JaxbMarshaller.java @@ -0,0 +1,43 @@ +package net.rolep.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; + +/** + * Created by rolep on 20/03/17. + */ +public class JaxbMarshaller { + private Marshaller marshaller; + + public JaxbMarshaller(JAXBContext context) throws JAXBException { + marshaller = context.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 property, Object value) throws PropertyException { + marshaller.setProperty(property, value); + } + + public synchronized void setSchema(Schema schema) { + marshaller.setSchema(schema); + } + + public String marshal(Object instance) throws JAXBException { + StringWriter stringWriter = new StringWriter(); + marshal(instance, stringWriter); + return stringWriter.toString(); + } + + public synchronized void marshal(Object instance, Writer writer) throws JAXBException { + marshaller.marshal(instance, writer); + } + + +} diff --git a/src/main/java/net/rolep/masterjava/xml/util/JaxbParser.java b/src/main/java/net/rolep/masterjava/xml/util/JaxbParser.java new file mode 100644 index 000000000..54b33b2d3 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/JaxbParser.java @@ -0,0 +1,83 @@ +package net.rolep.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.*; + +/** + * Created by rolep on 20/03/17. + */ +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); + } + } + + public JaxbParser(String context) { + try { + init(JAXBContext.newInstance(context)); + } catch (JAXBException e) { + throw new IllegalArgumentException(e); + } + } + + private void init(JAXBContext context) throws JAXBException { + jaxbMarshaller = new JaxbMarshaller(context); + jaxbUnmarshaller = new JaxbUnmarshaller(context); + } + + // Unmarshaller + public T unmarshal(InputStream inputStream) throws JAXBException { + return (T) jaxbUnmarshaller.unmarshal(inputStream); + } + public T unmarshal(Reader reader) throws JAXBException { + return (T) jaxbUnmarshaller.unmarshal(reader); + } + public T unmarshal(String string) throws JAXBException { + return (T) jaxbUnmarshaller.unmarshal(string); + } + + // Marshaller + public void setMarshallerProperty(String property, Object value) { + try { + jaxbMarshaller.setProperty(property, 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 string) throws IOException, SAXException { + validate(new StringReader(string)); + } + + public void validate(Reader reader) throws IOException, SAXException { + schema.newValidator().validate(new StreamSource(reader)); + } +} diff --git a/src/main/java/net/rolep/masterjava/xml/util/JaxbUnmarshaller.java b/src/main/java/net/rolep/masterjava/xml/util/JaxbUnmarshaller.java new file mode 100644 index 000000000..97609913d --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/JaxbUnmarshaller.java @@ -0,0 +1,36 @@ +package net.rolep.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; + +/** + * Created by rolep on 20/03/17. + */ +public class JaxbUnmarshaller { + private Unmarshaller unmarshaller; + + public JaxbUnmarshaller(JAXBContext context) throws JAXBException { + unmarshaller = context.createUnmarshaller(); + } + + public synchronized void setSchema(Schema schema) { + unmarshaller.setSchema(schema); + } + + public synchronized Object unmarshal(InputStream inputStream) throws JAXBException { + return unmarshaller.unmarshal(inputStream); + } + + public synchronized Object unmarshal(Reader reader) throws JAXBException { + return unmarshaller.unmarshal(reader); + } + + public Object unmarshal(String string) throws JAXBException { + return unmarshal(new StringReader(string)); + } +} diff --git a/src/main/java/net/rolep/masterjava/xml/util/Schemas.java b/src/main/java/net/rolep/masterjava/xml/util/Schemas.java new file mode 100644 index 000000000..c56c5ddc8 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/Schemas.java @@ -0,0 +1,49 @@ +package net.rolep.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; + +/** + * Created by rolep on 20/03/17. + */ +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) { + return ofURL(Resources.getResource(Schema.class, 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); + } + } +} diff --git a/src/test/java/net/rolep/masterjava/xml/util/JaxbParserTest.java b/src/test/java/net/rolep/masterjava/xml/util/JaxbParserTest.java new file mode 100644 index 000000000..02606a3e2 --- /dev/null +++ b/src/test/java/net/rolep/masterjava/xml/util/JaxbParserTest.java @@ -0,0 +1,43 @@ +package net.rolep.masterjava.xml.util; + +import com.google.common.io.Resources; +import net.rolep.masterjava.xml.schema.CityType; +import net.rolep.masterjava.xml.schema.ObjectFactory; +import net.rolep.masterjava.xml.schema.Payload; +import org.junit.Test; + +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; + + +/** + * Created by rolep on 21/03/17. + */ +public class JaxbParserTest { + private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class); + + static { + JAXB_PARSER.setSchema(Schemas.ofClasspath("/myPayload.xsd")); + } + + @Test + public void testPayload() throws Exception { + Payload payload = JAXB_PARSER.unmarshal(Resources.getResource(JaxbParserTest.class, "/myPayload.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(JaxbParserTest.class, "/myCity.xml").openStream()); + CityType city = cityElement.getValue(); + JAXBElement cityElement2 = new JAXBElement(new QName("http://rolep.net", "City"), CityType.class, city); + String str = JAXB_PARSER.marshal(cityElement); + JAXB_PARSER.validate(str); + System.out.println(str); + String strCity =JAXB_PARSER.marshal(cityElement2); + JAXB_PARSER.validate(strCity); + System.out.println(strCity); + } +} \ No newline at end of file diff --git a/src/test/resources/myCity.xml b/src/test/resources/myCity.xml new file mode 100644 index 000000000..30463fb84 --- /dev/null +++ b/src/test/resources/myCity.xml @@ -0,0 +1,4 @@ +Санкт-Петербург + \ No newline at end of file From d51f3c244ce3ab025686b538bdc1680b45b9bc27 Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 01:08:04 +0200 Subject: [PATCH 23/97] 2 07 JAXB --- .../masterjava/xml/util/JaxbMarshaller.java | 43 +++++++++ .../masterjava/xml/util/JaxbParser.java | 89 +++++++++++++++++++ .../masterjava/xml/util/JaxbUnmarshaller.java | 37 ++++++++ .../javaops/masterjava/xml/util/Schemas.java | 51 +++++++++++ .../masterjava/xml/util/JaxbParserTest.java | 44 +++++++++ src/test/resources/city.xml | 4 + 6 files changed, 268 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/Schemas.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java create mode 100644 src/test/resources/city.xml diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java new file mode 100644 index 000000000..7401011e9 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java @@ -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); + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java new file mode 100644 index 000000000..56fc888f4 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java @@ -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)); + } +} diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java new file mode 100644 index 000000000..afc34a6e4 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java @@ -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)); + } +} diff --git a/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java b/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java new file mode 100644 index 000000000..711e9eabe --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java @@ -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); + } + } +} diff --git a/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java b/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java new file mode 100644 index 000000000..ab1e365e5 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java @@ -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 diff --git a/src/test/resources/city.xml b/src/test/resources/city.xml new file mode 100644 index 000000000..8b0abcf8a --- /dev/null +++ b/src/test/resources/city.xml @@ -0,0 +1,4 @@ +Санкт-Петербург + \ No newline at end of file From 6e768b63840b9590e03b3e97713d30327928a57d Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 10:17:41 +0200 Subject: [PATCH 24/97] 2 08 - my stax --- .../xml/util/StaxStreamProcessor.java | 55 +++++++++++++++++++ .../xml/util/StaxStreamProcessorTest.java | 42 ++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java create mode 100644 src/test/java/net/rolep/masterjava/xml/util/StaxStreamProcessorTest.java diff --git a/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java new file mode 100644 index 000000000..302bd5ef6 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java @@ -0,0 +1,55 @@ +package net.rolep.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; + +/** + * Created by rolep on 21/03/17. + */ +public class StaxStreamProcessor implements AutoCloseable { + private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance(); + + private final XMLStreamReader reader; + + public StaxStreamProcessor(InputStream inputStream) throws XMLStreamException { + reader = FACTORY.createXMLStreamReader(inputStream); + } + + 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) { + return (event == XMLEvent.CHARACTERS) ? reader.getText() : reader.getLocalName(); + } + + public String getElementValue(String element) throws XMLStreamException { + return doUntil(XMLEvent.START_ELEMENT, element) ? reader.getElementText() : null; + } + + @Override + public void close() { + if (reader != null) { + try { + reader.close(); + } catch (XMLStreamException e) { + // empty + } + } + } +} diff --git a/src/test/java/net/rolep/masterjava/xml/util/StaxStreamProcessorTest.java b/src/test/java/net/rolep/masterjava/xml/util/StaxStreamProcessorTest.java new file mode 100644 index 000000000..baad08358 --- /dev/null +++ b/src/test/java/net/rolep/masterjava/xml/util/StaxStreamProcessorTest.java @@ -0,0 +1,42 @@ +package net.rolep.masterjava.xml.util; + +import com.google.common.io.Resources; +import org.junit.Test; + +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.XMLEvent; + +import static org.junit.Assert.*; + +/** + * Created by rolep on 21/03/17. + */ +public class StaxStreamProcessorTest { + + @Test + public void readCities() throws Exception { + try (StaxStreamProcessor processor = + new StaxStreamProcessor(Resources.getResource(StaxStreamProcessorTest.class, "/myPayload.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(StaxStreamProcessorTest.class, "/myPayload.xml").openStream())) { + String city; + while ((city=processor.getElementValue("City")) != null) { + System.out.println(city); + } + } + } +} \ No newline at end of file From a8472b1a40a541172e9b1c3a12569767403dc475 Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 10:18:13 +0200 Subject: [PATCH 25/97] 2 08 StAX --- .../xml/util/StaxStreamProcessor.java | 60 +++++++++++++++++++ .../xml/util/StaxStreamProcessorTest.java | 40 +++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java new file mode 100644 index 000000000..81b759e1d --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java @@ -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 + } + } + } +} diff --git a/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java new file mode 100644 index 000000000..229e2da64 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java @@ -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 From bdeda349b01aaed8d9213564e5e9db8b2d0c14bb Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 17:50:41 +0200 Subject: [PATCH 26/97] 2 09 my xpath --- .../masterjava/xml/util/XPathProcessor.java | 61 +++++++++++++++++++ .../xml/util/XPathProcessorTest.java | 31 ++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/main/java/net/rolep/masterjava/xml/util/XPathProcessor.java create mode 100644 src/test/java/net/rolep/masterjava/xml/util/XPathProcessorTest.java diff --git a/src/main/java/net/rolep/masterjava/xml/util/XPathProcessor.java b/src/main/java/net/rolep/masterjava/xml/util/XPathProcessor.java new file mode 100644 index 000000000..2455ee82f --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/XPathProcessor.java @@ -0,0 +1,61 @@ +package net.rolep.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; + +/** + * Created by rolep on 3/21/17. + */ +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 static synchronized XPathExpression getExpression(String exp) { + try { + return XPATH.compile(exp); + } catch (XPathExpressionException e) { + throw new IllegalArgumentException(e); + } + } + + public XPathProcessor(InputStream inputStream) { + try { + doc = DOCUMENT_BUILDER.parse(inputStream); + } catch (SAXException | IOException 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); + } + } +} diff --git a/src/test/java/net/rolep/masterjava/xml/util/XPathProcessorTest.java b/src/test/java/net/rolep/masterjava/xml/util/XPathProcessorTest.java new file mode 100644 index 000000000..707b74943 --- /dev/null +++ b/src/test/java/net/rolep/masterjava/xml/util/XPathProcessorTest.java @@ -0,0 +1,31 @@ +package net.rolep.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; + +import static org.junit.Assert.*; + +/** + * Created by rolep on 3/21/17. + */ +public class XPathProcessorTest { + + @Test + public void getCities() throws Exception { + try (InputStream inputStream = + Resources.getResource(JaxbParserTest.class, "/myPayload.xml").openStream()) { + XPathProcessor processor = new XPathProcessor(inputStream); + 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 From b50c2a0d2df0856193563911942d9a59bb69778d Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 21 Mar 2017 17:54:35 +0200 Subject: [PATCH 27/97] 2 09 XPath --- .../masterjava/xml/util/XPathProcessor.java | 62 +++++++++++++++++++ .../xml/util/XPathProcessorTest.java | 30 +++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java new file mode 100644 index 000000000..d6456a5de --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java @@ -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); + } + } +} diff --git a/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java new file mode 100644 index 000000000..18b6efdc2 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java @@ -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 From 7c39de61b6dc37b4eca4265938e73e5d5aa180db Mon Sep 17 00:00:00 2001 From: rolep Date: Wed, 22 Mar 2017 09:23:47 +0200 Subject: [PATCH 28/97] 2 10 - my xslt --- .../masterjava/xml/util/XsltProcessor.java | 46 +++++++++++++++++++ src/main/resources/myCities.xsl | 9 ++++ .../xml/util/XsltProcessorTest.java | 23 ++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java create mode 100644 src/main/resources/myCities.xsl create mode 100644 src/test/java/net/rolep/masterjava/xml/util/XsltProcessorTest.java diff --git a/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java b/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java new file mode 100644 index 000000000..642afc4b5 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java @@ -0,0 +1,46 @@ +package net.rolep.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; + +/** + * Created by rolep on 22/03/17. + */ +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"; + } +} diff --git a/src/main/resources/myCities.xsl b/src/main/resources/myCities.xsl new file mode 100644 index 000000000..54e216f78 --- /dev/null +++ b/src/main/resources/myCities.xsl @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/net/rolep/masterjava/xml/util/XsltProcessorTest.java b/src/test/java/net/rolep/masterjava/xml/util/XsltProcessorTest.java new file mode 100644 index 000000000..8c1e02faf --- /dev/null +++ b/src/test/java/net/rolep/masterjava/xml/util/XsltProcessorTest.java @@ -0,0 +1,23 @@ +package net.rolep.masterjava.xml.util; + +import com.google.common.io.Resources; +import org.junit.Test; + +import java.io.InputStream; + +import static org.junit.Assert.*; + +/** + * Created by rolep on 22/03/17. + */ +public class XsltProcessorTest { + @Test + public void transform() throws Exception { + try (InputStream xslInputStream = Resources.getResource(JaxbParserTest.class, "/myCities.xsl").openStream(); + InputStream xmlInputStrean = Resources.getResource(JaxbParserTest.class, "/myPayload.xml").openStream()) { + XsltProcessor processor = new XsltProcessor(xslInputStream); + System.out.println(processor.transform(xmlInputStrean)); + } + + } +} \ No newline at end of file From d304cef55a377a8db06a1590801f4b4f4dba7e71 Mon Sep 17 00:00:00 2001 From: rolep Date: Wed, 22 Mar 2017 09:24:26 +0200 Subject: [PATCH 29/97] 2 10 Xslt --- .../masterjava/xml/util/XsltProcessor.java | 48 +++++++++++++++++++ src/main/resources/cities.xsl | 9 ++++ .../xml/util/XsltProcessorTest.java | 22 +++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java create mode 100644 src/main/resources/cities.xsl create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java new file mode 100644 index 000000000..359a379ea --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java @@ -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"; + } +} diff --git a/src/main/resources/cities.xsl b/src/main/resources/cities.xsl new file mode 100644 index 000000000..1c509124b --- /dev/null +++ b/src/main/resources/cities.xsl @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java new file mode 100644 index 000000000..403a14c87 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java @@ -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)); + } + } +} From ef8fa469da2646982cac4597d4ce762b9933f9ed Mon Sep 17 00:00:00 2001 From: rolep Date: Wed, 22 Mar 2017 16:36:50 +0200 Subject: [PATCH 30/97] hw2 try 01 - xml shema --- .../rolep/masterjava/xml/schema/Group.java | 246 ++++++++++++++++++ .../masterjava/xml/schema/GroupType.java | 40 +++ .../masterjava/xml/schema/ObjectFactory.java | 48 ++++ .../rolep/masterjava/xml/schema/Payload.java | 194 ++++++++++++++ .../rolep/masterjava/xml/schema/Project.java | 188 +++++++++++++ .../net/rolep/masterjava/xml/schema/User.java | 96 ++++--- src/main/resources/myPayload.xsd | 68 ++++- src/test/resources/myPayload.xml | 31 ++- 8 files changed, 875 insertions(+), 36 deletions(-) create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/Group.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/GroupType.java create mode 100644 src/main/java/net/rolep/masterjava/xml/schema/Project.java diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Group.java b/src/main/java/net/rolep/masterjava/xml/schema/Group.java new file mode 100644 index 000000000..283026c13 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/Group.java @@ -0,0 +1,246 @@ + +package net.rolep.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.XmlID; +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; +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="name">
+ *           <complexType>
+ *             <simpleContent>
+ *               <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ *                 <attribute name="groupID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ *               </extension>
+ *             </simpleContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <element name="projectID" type="{http://www.w3.org/2001/XMLSchema}IDREF" minOccurs="0"/>
+ *       </sequence>
+ *       <attribute name="type" use="required" type="{http://rolep.net}groupType" />
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "name", + "description", + "projectID" +}) +@XmlRootElement(name = "Group", namespace = "http://rolep.net") +public class Group { + + @XmlElement(namespace = "http://rolep.net", required = true) + protected Group.Name name; + @XmlElement(namespace = "http://rolep.net") + protected String description; + @XmlElement(namespace = "http://rolep.net") + @XmlIDREF + @XmlSchemaType(name = "IDREF") + protected Object projectID; + @XmlAttribute(name = "type", required = true) + protected GroupType type; + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link Group.Name } + * + */ + public Group.Name getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link Group.Name } + * + */ + public void setName(Group.Name value) { + this.name = value; + } + + /** + * 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 projectID property. + * + * @return + * possible object is + * {@link Object } + * + */ + public Object getProjectID() { + return projectID; + } + + /** + * Sets the value of the projectID property. + * + * @param value + * allowed object is + * {@link Object } + * + */ + public void setProjectID(Object value) { + this.projectID = 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; + } + + + /** + *

Java class for anonymous complex type. + * + *

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

+     * <complexType>
+     *   <simpleContent>
+     *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
+     *       <attribute name="groupID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+     *     </extension>
+     *   </simpleContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "value" + }) + public static class Name { + + @XmlValue + protected String value; + @XmlAttribute(name = "groupID", required = true) + @XmlJavaTypeAdapter(CollapsedStringAdapter.class) + @XmlID + @XmlSchemaType(name = "ID") + protected String groupID; + + /** + * 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 groupID property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getGroupID() { + return groupID; + } + + /** + * Sets the value of the groupID property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setGroupID(String value) { + this.groupID = value; + } + + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/GroupType.java b/src/main/java/net/rolep/masterjava/xml/schema/GroupType.java new file mode 100644 index 000000000..a3e67b703 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/GroupType.java @@ -0,0 +1,40 @@ + +package net.rolep.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://rolep.net") +@XmlEnum +public enum GroupType { + + REGISTERING, + CURRENT, + FINISHED; + + public String value() { + return name(); + } + + public static GroupType fromValue(String v) { + return valueOf(v); + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java index a0300865e..62ed6c0b0 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java @@ -33,6 +33,22 @@ public class ObjectFactory { public ObjectFactory() { } + /** + * Create an instance of {@link Project } + * + */ + public Project createProject() { + return new Project(); + } + + /** + * Create an instance of {@link Group } + * + */ + public Group createGroup() { + return new Group(); + } + /** * Create an instance of {@link Payload } * @@ -41,6 +57,22 @@ public Payload createPayload() { return new Payload(); } + /** + * Create an instance of {@link Project.Name } + * + */ + public Project.Name createProjectName() { + return new Project.Name(); + } + + /** + * Create an instance of {@link Group.Name } + * + */ + public Group.Name createGroupName() { + return new Group.Name(); + } + /** * Create an instance of {@link User } * @@ -65,6 +97,22 @@ public Payload.Users createPayloadUsers() { return new Payload.Users(); } + /** + * Create an instance of {@link Payload.Projects } + * + */ + public Payload.Projects createPayloadProjects() { + return new Payload.Projects(); + } + + /** + * Create an instance of {@link Payload.Groups } + * + */ + public Payload.Groups createPayloadGroups() { + return new Payload.Groups(); + } + /** * Create an instance of {@link CityType } * diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Payload.java b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java index 9463a9e30..aa1cef97d 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/Payload.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java @@ -42,6 +42,28 @@ * </complexContent> * </complexType> * </element> + * <element name="Projects"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence maxOccurs="unbounded" minOccurs="0"> + * <element ref="{http://rolep.net}Project"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> + * <element name="Groups"> + * <complexType> + * <complexContent> + * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <sequence maxOccurs="unbounded" minOccurs="0"> + * <element ref="{http://rolep.net}Group"/> + * </sequence> + * </restriction> + * </complexContent> + * </complexType> + * </element> * </all> * </restriction> * </complexContent> @@ -61,6 +83,10 @@ public class Payload { protected Payload.Cities cities; @XmlElement(name = "Users", namespace = "http://rolep.net", required = true) protected Payload.Users users; + @XmlElement(name = "Projects", namespace = "http://rolep.net", required = true) + protected Payload.Projects projects; + @XmlElement(name = "Groups", namespace = "http://rolep.net", required = true) + protected Payload.Groups groups; /** * Gets the value of the cities property. @@ -110,6 +136,54 @@ public void setUsers(Payload.Users value) { this.users = value; } + /** + * 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 groups property. + * + * @return + * possible object is + * {@link Payload.Groups } + * + */ + public Payload.Groups getGroups() { + return groups; + } + + /** + * Sets the value of the groups property. + * + * @param value + * allowed object is + * {@link Payload.Groups } + * + */ + public void setGroups(Payload.Groups value) { + this.groups = value; + } + /** *

Java class for anonymous complex type. @@ -171,6 +245,126 @@ public List getCity() { } + /** + *

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://rolep.net}Group"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "group" + }) + public static class Groups { + + @XmlElement(name = "Group", namespace = "http://rolep.net") + protected List group; + + /** + * 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 Group } + * + * + */ + public List getGroup() { + if (group == null) { + group = new ArrayList(); + } + return this.group; + } + + } + + + /** + *

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://rolep.net}Project"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "project" + }) + public static class Projects { + + @XmlElement(name = "Project", namespace = "http://rolep.net") + 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. * diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Project.java b/src/main/java/net/rolep/masterjava/xml/schema/Project.java new file mode 100644 index 000000000..ef54a18ff --- /dev/null +++ b/src/main/java/net/rolep/masterjava/xml/schema/Project.java @@ -0,0 +1,188 @@ + +package net.rolep.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.XmlID; +import javax.xml.bind.annotation.XmlRootElement; +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 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="name">
+ *           <complexType>
+ *             <simpleContent>
+ *               <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ *                 <attribute name="projectID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ *               </extension>
+ *             </simpleContent>
+ *           </complexType>
+ *         </element>
+ *         <element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "name", + "description" +}) +@XmlRootElement(name = "Project", namespace = "http://rolep.net") +public class Project { + + @XmlElement(namespace = "http://rolep.net", required = true) + protected Project.Name name; + @XmlElement(namespace = "http://rolep.net") + protected String description; + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link Project.Name } + * + */ + public Project.Name getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link Project.Name } + * + */ + public void setName(Project.Name value) { + this.name = value; + } + + /** + * 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; + } + + + /** + *

Java class for anonymous complex type. + * + *

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

+     * <complexType>
+     *   <simpleContent>
+     *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
+     *       <attribute name="projectID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+     *     </extension>
+     *   </simpleContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "value" + }) + public static class Name { + + @XmlValue + protected String value; + @XmlAttribute(name = "projectID", required = true) + @XmlJavaTypeAdapter(CollapsedStringAdapter.class) + @XmlID + @XmlSchemaType(name = "ID") + protected String projectID; + + /** + * 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 projectID property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getProjectID() { + return projectID; + } + + /** + * Sets the value of the projectID property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setProjectID(String value) { + this.projectID = value; + } + + } + +} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/User.java b/src/main/java/net/rolep/masterjava/xml/schema/User.java index 170103bea..0705ac50d 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/User.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/User.java @@ -1,11 +1,14 @@ package net.rolep.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.XmlList; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlType; @@ -21,11 +24,12 @@ * <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"/> + * <element name="Groups" type="{http://www.w3.org/2001/XMLSchema}IDREFS" minOccurs="0"/> * </sequence> * <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" /> * <attribute name="flag" use="required" type="{http://rolep.net}flagType" /> + * <attribute name="email" use="required" type="{http://rolep.net}emailType" /> * </restriction> * </complexContent> * </complexType> @@ -35,46 +39,27 @@ */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { - "email", - "fullName" + "fullName", + "groups" }) @XmlRootElement(name = "User", namespace = "http://rolep.net") public class User { - @XmlElement(namespace = "http://rolep.net", required = true) - protected String email; @XmlElement(namespace = "http://rolep.net", required = true) protected String fullName; + @XmlList + @XmlElement(name = "Groups", namespace = "http://rolep.net") + @XmlIDREF + @XmlSchemaType(name = "IDREFS") + protected List groups; @XmlAttribute(name = "city", required = true) @XmlIDREF @XmlSchemaType(name = "IDREF") protected Object city; @XmlAttribute(name = "flag", required = true) protected FlagType flag; - - /** - * 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; - } + @XmlAttribute(name = "email", required = true) + protected String email; /** * Gets the value of the fullName property. @@ -100,6 +85,35 @@ public void setFullName(String value) { this.fullName = value; } + /** + * Gets the value of the groups 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 groups property. + * + *

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

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

+ * Objects of the following type(s) are allowed in the list + * {@link Object } + * + * + */ + public List getGroups() { + if (groups == null) { + groups = new ArrayList(); + } + return this.groups; + } + /** * Gets the value of the city property. * @@ -148,4 +162,28 @@ public void setFlag(FlagType value) { this.flag = value; } + /** + * 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; + } + } diff --git a/src/main/resources/myPayload.xsd b/src/main/resources/myPayload.xsd index 648bf83d0..a9f5c1012 100644 --- a/src/main/resources/myPayload.xsd +++ b/src/main/resources/myPayload.xsd @@ -21,6 +21,20 @@ + + + + + + + + + + + + + + @@ -28,11 +42,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -53,4 +105,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/myPayload.xml b/src/test/resources/myPayload.xml index 8931f1b50..fcc0ceaf8 100644 --- a/src/test/resources/myPayload.xml +++ b/src/test/resources/myPayload.xml @@ -2,18 +2,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://rolep.net myPayload.xsd"> - - gmail@gmail.com + Full Name - - admin@javaops.ru + Admin - - mail@yandex.ru + Deleted + topjava09 topjava @@ -22,4 +20,25 @@ Киев Минск + + + MasterJava + Разработка полнофункционального многомодульного Maven проекта + + + TopJava + Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ + Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins + + + + + topjava10 + topjava + + + TopJava09 + topjava + + \ No newline at end of file From b9b24667b9c0c7f4dafcf38a20251a9f81cf660e Mon Sep 17 00:00:00 2001 From: rolep Date: Thu, 23 Mar 2017 13:44:08 +0200 Subject: [PATCH 31/97] hw2 try 02 - xml shema - simple string elements without refs --- .../rolep/masterjava/xml/schema/Group.java | 152 ++++-------------- .../masterjava/xml/schema/ObjectFactory.java | 28 +--- .../rolep/masterjava/xml/schema/Project.java | 108 +------------ .../net/rolep/masterjava/xml/schema/User.java | 18 ++- src/main/resources/myPayload.xsd | 31 +++- src/test/resources/myPayload.xml | 23 +-- 6 files changed, 90 insertions(+), 270 deletions(-) diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Group.java b/src/main/java/net/rolep/masterjava/xml/schema/Group.java index 283026c13..875892e2e 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/Group.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/Group.java @@ -5,14 +5,8 @@ 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.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; -import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** @@ -25,19 +19,11 @@ * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> - * <element name="name"> - * <complexType> - * <simpleContent> - * <extension base="<http://www.w3.org/2001/XMLSchema>string"> - * <attribute name="groupID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" /> - * </extension> - * </simpleContent> - * </complexType> - * </element> + * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> - * <element name="projectID" type="{http://www.w3.org/2001/XMLSchema}IDREF" minOccurs="0"/> + * <element name="project" type="{http://www.w3.org/2001/XMLSchema}string"/> * </sequence> - * <attribute name="type" use="required" type="{http://rolep.net}groupType" /> + * <attribute name="groupType" use="required" type="{http://rolep.net}groupType" /> * </restriction> * </complexContent> * </complexType> @@ -49,31 +35,29 @@ @XmlType(name = "", propOrder = { "name", "description", - "projectID" + "project" }) @XmlRootElement(name = "Group", namespace = "http://rolep.net") public class Group { @XmlElement(namespace = "http://rolep.net", required = true) - protected Group.Name name; + protected String name; @XmlElement(namespace = "http://rolep.net") protected String description; - @XmlElement(namespace = "http://rolep.net") - @XmlIDREF - @XmlSchemaType(name = "IDREF") - protected Object projectID; - @XmlAttribute(name = "type", required = true) - protected GroupType type; + @XmlElement(namespace = "http://rolep.net", required = true) + protected String project; + @XmlAttribute(name = "groupType", required = true) + protected GroupType groupType; /** * Gets the value of the name property. * * @return * possible object is - * {@link Group.Name } + * {@link String } * */ - public Group.Name getName() { + public String getName() { return name; } @@ -82,10 +66,10 @@ public Group.Name getName() { * * @param value * allowed object is - * {@link Group.Name } + * {@link String } * */ - public void setName(Group.Name value) { + public void setName(String value) { this.name = value; } @@ -114,133 +98,51 @@ public void setDescription(String value) { } /** - * Gets the value of the projectID property. + * Gets the value of the project property. * * @return * possible object is - * {@link Object } + * {@link String } * */ - public Object getProjectID() { - return projectID; + public String getProject() { + return project; } /** - * Sets the value of the projectID property. + * Sets the value of the project property. * * @param value * allowed object is - * {@link Object } + * {@link String } * */ - public void setProjectID(Object value) { - this.projectID = value; + public void setProject(String value) { + this.project = value; } /** - * Gets the value of the type property. + * Gets the value of the groupType property. * * @return * possible object is * {@link GroupType } * */ - public GroupType getType() { - return type; + public GroupType getGroupType() { + return groupType; } /** - * Sets the value of the type property. + * Sets the value of the groupType property. * * @param value * allowed object is * {@link GroupType } * */ - public void setType(GroupType value) { - this.type = value; - } - - - /** - *

Java class for anonymous complex type. - * - *

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

-     * <complexType>
-     *   <simpleContent>
-     *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
-     *       <attribute name="groupID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
-     *     </extension>
-     *   </simpleContent>
-     * </complexType>
-     * 
- * - * - */ - @XmlAccessorType(XmlAccessType.FIELD) - @XmlType(name = "", propOrder = { - "value" - }) - public static class Name { - - @XmlValue - protected String value; - @XmlAttribute(name = "groupID", required = true) - @XmlJavaTypeAdapter(CollapsedStringAdapter.class) - @XmlID - @XmlSchemaType(name = "ID") - protected String groupID; - - /** - * 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 groupID property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getGroupID() { - return groupID; - } - - /** - * Sets the value of the groupID property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setGroupID(String value) { - this.groupID = value; - } - + public void setGroupType(GroupType value) { + this.groupType = value; } } diff --git a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java index 62ed6c0b0..77f2f09c3 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java @@ -33,22 +33,6 @@ public class ObjectFactory { public ObjectFactory() { } - /** - * Create an instance of {@link Project } - * - */ - public Project createProject() { - return new Project(); - } - - /** - * Create an instance of {@link Group } - * - */ - public Group createGroup() { - return new Group(); - } - /** * Create an instance of {@link Payload } * @@ -58,19 +42,19 @@ public Payload createPayload() { } /** - * Create an instance of {@link Project.Name } + * Create an instance of {@link Project } * */ - public Project.Name createProjectName() { - return new Project.Name(); + public Project createProject() { + return new Project(); } /** - * Create an instance of {@link Group.Name } + * Create an instance of {@link Group } * */ - public Group.Name createGroupName() { - return new Group.Name(); + public Group createGroup() { + return new Group(); } /** diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Project.java b/src/main/java/net/rolep/masterjava/xml/schema/Project.java index ef54a18ff..66c8f9b66 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/Project.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/Project.java @@ -3,15 +3,9 @@ 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.XmlValue; -import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; -import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** @@ -24,15 +18,7 @@ * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> - * <element name="name"> - * <complexType> - * <simpleContent> - * <extension base="<http://www.w3.org/2001/XMLSchema>string"> - * <attribute name="projectID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" /> - * </extension> - * </simpleContent> - * </complexType> - * </element> + * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * </sequence> * </restriction> @@ -51,7 +37,7 @@ public class Project { @XmlElement(namespace = "http://rolep.net", required = true) - protected Project.Name name; + protected String name; @XmlElement(namespace = "http://rolep.net") protected String description; @@ -60,10 +46,10 @@ public class Project { * * @return * possible object is - * {@link Project.Name } + * {@link String } * */ - public Project.Name getName() { + public String getName() { return name; } @@ -72,10 +58,10 @@ public Project.Name getName() { * * @param value * allowed object is - * {@link Project.Name } + * {@link String } * */ - public void setName(Project.Name value) { + public void setName(String value) { this.name = value; } @@ -103,86 +89,4 @@ public void setDescription(String value) { this.description = value; } - - /** - *

Java class for anonymous complex type. - * - *

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

-     * <complexType>
-     *   <simpleContent>
-     *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
-     *       <attribute name="projectID" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
-     *     </extension>
-     *   </simpleContent>
-     * </complexType>
-     * 
- * - * - */ - @XmlAccessorType(XmlAccessType.FIELD) - @XmlType(name = "", propOrder = { - "value" - }) - public static class Name { - - @XmlValue - protected String value; - @XmlAttribute(name = "projectID", required = true) - @XmlJavaTypeAdapter(CollapsedStringAdapter.class) - @XmlID - @XmlSchemaType(name = "ID") - protected String projectID; - - /** - * 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 projectID property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getProjectID() { - return projectID; - } - - /** - * Sets the value of the projectID property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setProjectID(String value) { - this.projectID = value; - } - - } - } diff --git a/src/main/java/net/rolep/masterjava/xml/schema/User.java b/src/main/java/net/rolep/masterjava/xml/schema/User.java index 0705ac50d..785bf9b8a 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/User.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/User.java @@ -25,7 +25,11 @@ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/> - * <element name="Groups" type="{http://www.w3.org/2001/XMLSchema}IDREFS" minOccurs="0"/> + * <element name="groups" minOccurs="0"> + * <simpleType> + * <list itemType="{http://www.w3.org/2001/XMLSchema}string" /> + * </simpleType> + * </element> * </sequence> * <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" /> * <attribute name="flag" use="required" type="{http://rolep.net}flagType" /> @@ -48,10 +52,8 @@ public class User { @XmlElement(namespace = "http://rolep.net", required = true) protected String fullName; @XmlList - @XmlElement(name = "Groups", namespace = "http://rolep.net") - @XmlIDREF - @XmlSchemaType(name = "IDREFS") - protected List groups; + @XmlElement(namespace = "http://rolep.net") + protected List groups; @XmlAttribute(name = "city", required = true) @XmlIDREF @XmlSchemaType(name = "IDREF") @@ -103,13 +105,13 @@ public void setFullName(String value) { * *

* Objects of the following type(s) are allowed in the list - * {@link Object } + * {@link String } * * */ - public List getGroups() { + public List getGroups() { if (groups == null) { - groups = new ArrayList(); + groups = new ArrayList(); } return this.groups; } diff --git a/src/main/resources/myPayload.xsd b/src/main/resources/myPayload.xsd index a9f5c1012..e3f3fe810 100644 --- a/src/main/resources/myPayload.xsd +++ b/src/main/resources/myPayload.xsd @@ -43,7 +43,10 @@ - + + + + @@ -53,6 +56,26 @@ + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/test/resources/myPayload.xml b/src/test/resources/myPayload.xml index fcc0ceaf8..c6672b6ad 100644 --- a/src/test/resources/myPayload.xml +++ b/src/test/resources/myPayload.xml @@ -8,10 +8,11 @@ Admin + masterjava02 topjava10 Deleted - topjava09 topjava + topjava09 topjava10 @@ -22,23 +23,27 @@ - MasterJava + MasterJava Разработка полнофункционального многомодульного Maven проекта - TopJava + TopJava Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins - - topjava10 - topjava + + topjava10 + TopJava - - TopJava09 - topjava + + TopJava09 + TopJava + + + masterjava02 + MasterJava \ No newline at end of file From d5ae562992ef7ef2e15eed7af100b1e1cf87fda7 Mon Sep 17 00:00:00 2001 From: rolep Date: Thu, 23 Mar 2017 19:58:00 +0200 Subject: [PATCH 32/97] hw 2 - stax first try - in process --- src/main/java/net/rolep/masterjava/Main.java | 14 --- .../java/net/rolep/masterjava/MainXml.java | 105 ++++++++++++++++++ src/main/resources/myPayload.xml | 49 ++++++++ 3 files changed, 154 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/net/rolep/masterjava/Main.java create mode 100644 src/main/java/net/rolep/masterjava/MainXml.java create mode 100644 src/main/resources/myPayload.xml diff --git a/src/main/java/net/rolep/masterjava/Main.java b/src/main/java/net/rolep/masterjava/Main.java deleted file mode 100644 index 3a348b7d8..000000000 --- a/src/main/java/net/rolep/masterjava/Main.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.rolep.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!"); - } -} diff --git a/src/main/java/net/rolep/masterjava/MainXml.java b/src/main/java/net/rolep/masterjava/MainXml.java new file mode 100644 index 000000000..e77ecaf51 --- /dev/null +++ b/src/main/java/net/rolep/masterjava/MainXml.java @@ -0,0 +1,105 @@ +package net.rolep.masterjava; + +import com.google.common.io.Resources; +import net.rolep.masterjava.xml.schema.*; +import net.rolep.masterjava.xml.util.JaxbParser; +import net.rolep.masterjava.xml.util.Schemas; +import net.rolep.masterjava.xml.util.StaxStreamProcessor; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.XMLEvent; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Scanner; + +/** + * User: gkislin + * Date: 05.08.2015 + * + * @link http://caloriesmng.herokuapp.com/ + * @link https://github.com/JavaOPs/topjava + */ +public class MainXml { + + private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class); + + static { + JAXB_PARSER.setSchema(Schemas.ofClasspath("/myPayload.xsd")); + } + + public static void main(String[] args) throws Exception { + System.out.println("Enter project name:"); + Scanner scanner = new Scanner(System.in); + args = scanner.nextLine().split(" "); + scanner.close(); + + String projectName; + if (args.length < 1 || (projectName=args[0]) == null || projectName.isEmpty()) { + throw new IllegalArgumentException("Wrong argument provided"); + } + + Payload payload = JAXB_PARSER.unmarshal(Resources.getResource(MainXml.class, "/myPayload.xml").openStream()); + +/* for (Project project : payload.getProjects().getProject()) { + if (project.getName().equals(projectName)) { + break; + } + System.out.println("WARNING: No project with name " + projectName + " found!"); + }*/ + + List projectGroups = new ArrayList<>(); + for (Group group : payload.getGroups().getGroup()) { + if (group.getProject().equals(projectName)) { + projectGroups.add(group.getName()); + } + } + if (projectGroups.isEmpty()) { + System.out.println("There is no groups with this project!"); + return; + } + + List projectUsers = new ArrayList<>(); + for (User user : payload.getUsers().getUser()) { + for (String groupName : user.getGroups()) { + if (projectGroups.contains(groupName)) { + projectUsers.add(user); + break; + } + } + } + + if (projectUsers.isEmpty()) { + System.out.println("No users for project " + projectName + " found!"); + } else { + projectUsers.sort(Comparator.comparing(User::getFullName)); + for (User user : projectUsers) { + System.out.println(user.getFullName()); + } + } + + + System.out.println("Stax Test"); + + try (StaxStreamProcessor processor = + new StaxStreamProcessor(Resources.getResource(MainXml.class, "/myPayload.xml").openStream())) { + XMLStreamReader reader = processor.getReader(); + QName tagName; + while (reader.hasNext()) { + int event = reader.next(); + if (event == XMLEvent.START_ELEMENT) { + if ("Projects".equals(reader.getLocalName())) { + do { + tagName = reader.getName(); + } + } else if ("Groups".equals(reader.getLocalName())) { + + } else if ("Users".equals(reader.getLocalName())) { + + } + } + } + } + } +} diff --git a/src/main/resources/myPayload.xml b/src/main/resources/myPayload.xml new file mode 100644 index 000000000..c6672b6ad --- /dev/null +++ b/src/main/resources/myPayload.xml @@ -0,0 +1,49 @@ + + + + Full Name + + + + Admin + masterjava02 topjava10 + + + Deleted + topjava09 topjava10 + + + + + Санкт-Петербург + Киев + Минск + + + + MasterJava + Разработка полнофункционального многомодульного Maven проекта + + + TopJava + Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ + Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins + + + + + topjava10 + TopJava + + + TopJava09 + TopJava + + + masterjava02 + MasterJava + + + \ No newline at end of file From b9cba56a1e8f38f179fc4184b14756681f5b5580 Mon Sep 17 00:00:00 2001 From: rolep Date: Fri, 24 Mar 2017 10:43:58 +0200 Subject: [PATCH 33/97] hw 2 - my stax 03 --- src/main/java/net/rolep/masterjava/MainXml.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/rolep/masterjava/MainXml.java b/src/main/java/net/rolep/masterjava/MainXml.java index e77ecaf51..61cd8cd1f 100644 --- a/src/main/java/net/rolep/masterjava/MainXml.java +++ b/src/main/java/net/rolep/masterjava/MainXml.java @@ -90,8 +90,12 @@ public static void main(String[] args) throws Exception { int event = reader.next(); if (event == XMLEvent.START_ELEMENT) { if ("Projects".equals(reader.getLocalName())) { - do { - tagName = reader.getName(); + while (true) { + event = reader.nextTag(); + if (event == XMLEvent.END_ELEMENT && reader.getLocalName().equals("Projects")) {break;} + if (event == XMLEvent.START_ELEMENT && reader.getLocalName().equals("Project")) { + + } } } else if ("Groups".equals(reader.getLocalName())) { From fe50897842d1a4db984d8c67be9a4c85a2fdd2f0 Mon Sep 17 00:00:00 2001 From: rolep Date: Fri, 24 Mar 2017 16:29:58 +0200 Subject: [PATCH 34/97] 3 path files added --- patches/lesson03/3_1_HW2_schema.patch | 782 +++++++++++++++++++++++ patches/lesson03/3_2_HW2_JAXB_HTML.patch | 179 ++++++ patches/lesson03/3_3_HW2_StAX.patch | 127 ++++ patches/lesson03/3_4_HW2_xslt.patch | 102 +++ patches/lesson03/3_5_multimodule.patch | 294 +++++++++ 5 files changed, 1484 insertions(+) create mode 100644 patches/lesson03/3_1_HW2_schema.patch create mode 100644 patches/lesson03/3_2_HW2_JAXB_HTML.patch create mode 100644 patches/lesson03/3_3_HW2_StAX.patch create mode 100644 patches/lesson03/3_4_HW2_xslt.patch create mode 100644 patches/lesson03/3_5_multimodule.patch diff --git a/patches/lesson03/3_1_HW2_schema.patch b/patches/lesson03/3_1_HW2_schema.patch new file mode 100644 index 000000000..2d8e442e7 --- /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..d9850098f --- /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..5fdf9a390 --- /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..487adfaa5 --- /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..78fbe1823 --- /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 +- +- +- +- +- +- +- +- ++ ++ +
From de34ceb73134ed1d6f3b7cca59bf631a91e5e812 Mon Sep 17 00:00:00 2001 From: rolep Date: Fri, 24 Mar 2017 16:30:57 +0200 Subject: [PATCH 35/97] 3 patch files added --- patches/lesson03/3_1_HW2_schema.patch | 1564 +++++++++++----------- patches/lesson03/3_2_HW2_JAXB_HTML.patch | 358 ++--- patches/lesson03/3_3_HW2_StAX.patch | 254 ++-- patches/lesson03/3_4_HW2_xslt.patch | 204 +-- patches/lesson03/3_5_multimodule.patch | 588 ++++---- 5 files changed, 1484 insertions(+), 1484 deletions(-) diff --git a/patches/lesson03/3_1_HW2_schema.patch b/patches/lesson03/3_1_HW2_schema.patch index 2d8e442e7..7b0bf03a5 100644 --- a/patches/lesson03/3_1_HW2_schema.patch +++ b/patches/lesson03/3_1_HW2_schema.patch @@ -1,782 +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 } - * +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 index d9850098f..9f7279b70 100644 --- a/patches/lesson03/3_2_HW2_JAXB_HTML.patch +++ b/patches/lesson03/3_2_HW2_JAXB_HTML.patch @@ -1,179 +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 + ')'; -+ } -+ -+ - } +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 index 5fdf9a390..1898adfe2 100644 --- a/patches/lesson03/3_3_HW2_StAX.patch +++ b/patches/lesson03/3_3_HW2_StAX.patch @@ -1,127 +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"))) +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 index 487adfaa5..19a0e9ce5 100644 --- a/patches/lesson03/3_4_HW2_xslt.patch +++ b/patches/lesson03/3_4_HW2_xslt.patch @@ -1,102 +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); -+ } -+ } - } +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 index 78fbe1823..c558ac2d8 100644 --- a/patches/lesson03/3_5_multimodule.patch +++ b/patches/lesson03/3_5_multimodule.patch @@ -1,294 +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 -- -- -- -- -- -- -- -- -+ -+ -
+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 +- +- +- +- +- +- +- +- ++ ++ + From 9476927be08b1d858c513c70f51427ab8fc43ea7 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 25 Mar 2017 10:40:31 +0200 Subject: [PATCH 36/97] 3_1 hw2 schema --- .../masterjava/xml/schema/GroupType.java | 40 ++++ .../masterjava/xml/schema/ObjectFactory.java | 24 ++ .../masterjava/xml/schema/Payload.java | 105 ++++++++- .../masterjava/xml/schema/Project.java | 223 ++++++++++++++++++ .../javaops/masterjava/xml/schema/User.java | 118 +++++---- src/main/resources/payload.xsd | 56 ++++- src/test/resources/payload.xml | 38 +-- 7 files changed, 534 insertions(+), 70 deletions(-) create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/Project.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java b/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java new file mode 100644 index 000000000..d5041640b --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java @@ -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); + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java index e8f105e2a..bfb393299 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java @@ -33,6 +33,14 @@ public class ObjectFactory { public ObjectFactory() { } + /** + * Create an instance of {@link Project } + * + */ + public Project createProject() { + return new Project(); + } + /** * Create an instance of {@link Payload } * @@ -41,6 +49,14 @@ public Payload createPayload() { 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 @@ public User createUser() { 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/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java index 2a6276490..f4a8070e9 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java @@ -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 @@ public List getCity() { } + /** + *

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. * diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Project.java b/src/main/java/ru/javaops/masterjava/xml/schema/Project.java new file mode 100644 index 000000000..7e9cd961a --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/Project.java @@ -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; + } + + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java index b3430ce71..e50540ca4 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/User.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -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>
- *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+ *   <simpleContent>
+ *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ *       <attribute name="email" use="required" type="{http://javaops.ru}emailAddressType" />
  *       <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
- *     </restriction>
- *   </complexContent>
+ *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+ *       <attribute name="groupRefs" type="{http://www.w3.org/2001/XMLSchema}IDREFS" />
+ *     </extension>
+ *   </simpleContent>
  * </complexType>
  * 
* @@ -35,22 +35,49 @@ */ @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", 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; + @XmlAttribute(name = "flag", required = true) + protected FlagType flag; + @XmlAttribute(name = "groupRefs") + @XmlIDREF + @XmlSchemaType(name = "IDREFS") + protected List groupRefs; + + /** + * 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 email property. @@ -77,27 +104,27 @@ public void setEmail(String value) { } /** - * Gets the value of the fullName property. + * Gets the value of the city property. * * @return * possible object is - * {@link String } + * {@link Object } * */ - public String getFullName() { - return fullName; + public Object getCity() { + return city; } /** - * Sets the value of the fullName property. + * Sets the value of the city property. * * @param value * allowed object is - * {@link String } + * {@link Object } * */ - public void setFullName(String value) { - this.fullName = value; + public void setCity(Object value) { + this.city = value; } /** @@ -125,27 +152,32 @@ public void setFlag(FlagType value) { } /** - * Gets the value of the city property. + * 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 } * - * @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; + public List getGroupRefs() { + if (groupRefs == null) { + groupRefs = new ArrayList(); + } + return this.groupRefs; } } diff --git a/src/main/resources/payload.xsd b/src/main/resources/payload.xsd index 2229ec35f..af1260cdc 100644 --- a/src/main/resources/payload.xsd +++ b/src/main/resources/payload.xsd @@ -6,7 +6,14 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema"> - + + + + + + + + @@ -21,21 +28,46 @@ - + - - + + - - + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + @@ -44,6 +76,14 @@ + + + + + + + + diff --git a/src/test/resources/payload.xml b/src/test/resources/payload.xml index 5b4d5337f..9eec83ee6 100644 --- a/src/test/resources/payload.xml +++ b/src/test/resources/payload.xml @@ -1,25 +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 From 964cfeac617bd723780bbaf16d7357f61cd5ae07 Mon Sep 17 00:00:00 2001 From: rolep Date: Sat, 25 Mar 2017 16:34:29 +0200 Subject: [PATCH 37/97] 3_2 hw2 jaxb html --- pom.xml | 17 ++++ src/main/java/ru/javaops/masterjava/Main.java | 14 --- .../javaops/masterjava/xml/schema/User.java | 4 + .../java/ru/javaops/masterjava/MainXml.java | 87 +++++++++++++++++++ 4 files changed, 108 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/ru/javaops/masterjava/Main.java create mode 100644 src/test/java/ru/javaops/masterjava/MainXml.java diff --git a/pom.xml b/pom.xml index d3462a04d..dfc31f445 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,8 @@ 1.18 21.0 4.12 + 0.6.5 + 0.88 @@ -112,6 +114,21 @@ ${guava.version} + + + one.util + streamex + ${streamex.version} + + + + + com.j2html + j2html + ${j2html.version} + + + junit diff --git a/src/main/java/ru/javaops/masterjava/Main.java b/src/main/java/ru/javaops/masterjava/Main.java deleted file mode 100644 index a849258c4..000000000 --- a/src/main/java/ru/javaops/masterjava/Main.java +++ /dev/null @@ -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!"); - } -} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java index e50540ca4..c5a3632a5 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/User.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -180,4 +180,8 @@ public List getGroupRefs() { return this.groupRefs; } + @Override + public String toString() { + return value + '(' + email +')'; + } } diff --git a/src/test/java/ru/javaops/masterjava/MainXml.java b/src/test/java/ru/javaops/masterjava/MainXml.java new file mode 100644 index 000000000..164bbb748 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/MainXml.java @@ -0,0 +1,87 @@ +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.IOException; +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 + * Date: 05.08.2015 + * + * @link http://caloriesmng.herokuapp.com/ + * @link https://github.com/JavaOPs/topjava + */ +public class MainXml { + + public 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, xmlName"); + System.exit(1); + } + URL payloadUrl = Resources.getResource("payload.xml"); + String projectName = args[0]; + + 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()); + return StreamEx.of(payload.getUsers().getUser()) + .filter(u -> !Collections.disjoint(u.getGroupRefs(), groups)) + .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR))); + + } + + private static String toHtml(Set users, String projectName) throws IOException { + 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(); + } +} + From 6aa9810762637d351933023e013438e660b39dec Mon Sep 17 00:00:00 2001 From: rolep Date: Sun, 26 Mar 2017 09:32:01 +0300 Subject: [PATCH 38/97] 3_3 hw2 stax --- .../xml/util/StaxStreamProcessor.java | 17 +++++-- .../java/ru/javaops/masterjava/MainXml.java | 50 +++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java index 81b759e1d..55dcc2ab7 100644 --- a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java +++ b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java @@ -24,15 +24,26 @@ public XMLStreamReader getReader() { } public boolean doUntil(int stopEvent, String value) throws XMLStreamException { + return doUntilAny(stopEvent, value) != null; + } + + 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(getValue(event))) { + return xmlValue; + } } } } - return false; + return null; + } + + public String getAttribute(String name) { + return reader.getAttributeValue(null, name); } public String getValue(int event) throws XMLStreamException { diff --git a/src/test/java/ru/javaops/masterjava/MainXml.java b/src/test/java/ru/javaops/masterjava/MainXml.java index 164bbb748..3649398f5 100644 --- a/src/test/java/ru/javaops/masterjava/MainXml.java +++ b/src/test/java/ru/javaops/masterjava/MainXml.java @@ -1,5 +1,7 @@ package ru.javaops.masterjava; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; import com.google.common.io.Resources; import j2html.tags.ContainerTag; import one.util.streamex.StreamEx; @@ -9,7 +11,10 @@ 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.XMLStreamException; +import javax.xml.stream.events.XMLEvent; import java.io.IOException; import java.io.InputStream; import java.io.Writer; @@ -31,6 +36,9 @@ public class MainXml { public static final Comparator USER_COMPARATOR = Comparator.comparing(User::getValue).thenComparing(User::getEmail); + public static final String PROJECT = "Project"; + public static final String USERS = "Users"; + public static final String GROUP = "Group"; public static void main(String[] args) throws Exception { if (args.length != 1) { @@ -48,6 +56,10 @@ public static void main(String[] args) throws Exception { 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 { @@ -83,5 +95,43 @@ private static String toHtml(Set users, String projectName) throws IOExcep body().with(h1(projectName + " users"), table) ).render(); } + + private static Set processByStax(String projectName, URL payloadUrl) throws Exception { + try (InputStream is = payloadUrl.openStream()) { + StaxStreamProcessor processor = new StaxStreamProcessor(is); + Set groupNames = new HashSet<>(); + Set users = new TreeSet<>(USER_COMPARATOR); + String element; + + // Projects loop + projects: + while (processor.doUntil(XMLEvent.START_ELEMENT, PROJECT)) { + if (projectName.equals(processor.getAttribute("name"))) { + // Groups loop + while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, 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 + while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { + String groupRefs = processor.getAttribute("groupRefs"); + if (!Collections.disjoint(groupNames, Splitter.on(' ').splitToList(Strings.nullToEmpty(groupRefs)))) { + User user = new User(); + user.setEmail(processor.getAttribute("email")); + user.setValue(processor.getReader().getElementText()); + users.add(user); + } + } + return users; + } + } } From d0bcaeafb6f05f12fb71d376c0b7b1a1cc81ec9d Mon Sep 17 00:00:00 2001 From: rolep Date: Sun, 26 Mar 2017 10:05:15 +0300 Subject: [PATCH 39/97] 3_3 hw2 stax - synced changes to "my" branch --- .../java/net/rolep/masterjava/MainXml.java | 109 ----------- .../masterjava/xml/schema/ObjectFactory.java | 42 ++--- .../rolep/masterjava/xml/schema/Payload.java | 175 ++++-------------- .../rolep/masterjava/xml/schema/Project.java | 167 +++++++++++++++-- .../net/rolep/masterjava/xml/schema/User.java | 138 +++++++------- .../rolep/masterjava/xml/util/Schemas.java | 2 +- .../xml/util/StaxStreamProcessor.java | 17 +- src/main/resources/myPayload.xml | 49 ----- src/main/resources/myPayload.xsd | 105 +++-------- .../net/rolep/masterjava/xml/MainXml.java | 132 +++++++++++++ .../java/ru/javaops/masterjava/MainXml.java | 12 +- src/test/resources/myPayload.xml | 62 +++---- 12 files changed, 474 insertions(+), 536 deletions(-) delete mode 100644 src/main/java/net/rolep/masterjava/MainXml.java delete mode 100644 src/main/resources/myPayload.xml create mode 100644 src/test/java/net/rolep/masterjava/xml/MainXml.java diff --git a/src/main/java/net/rolep/masterjava/MainXml.java b/src/main/java/net/rolep/masterjava/MainXml.java deleted file mode 100644 index 61cd8cd1f..000000000 --- a/src/main/java/net/rolep/masterjava/MainXml.java +++ /dev/null @@ -1,109 +0,0 @@ -package net.rolep.masterjava; - -import com.google.common.io.Resources; -import net.rolep.masterjava.xml.schema.*; -import net.rolep.masterjava.xml.util.JaxbParser; -import net.rolep.masterjava.xml.util.Schemas; -import net.rolep.masterjava.xml.util.StaxStreamProcessor; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamReader; -import javax.xml.stream.events.XMLEvent; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Scanner; - -/** - * User: gkislin - * Date: 05.08.2015 - * - * @link http://caloriesmng.herokuapp.com/ - * @link https://github.com/JavaOPs/topjava - */ -public class MainXml { - - private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class); - - static { - JAXB_PARSER.setSchema(Schemas.ofClasspath("/myPayload.xsd")); - } - - public static void main(String[] args) throws Exception { - System.out.println("Enter project name:"); - Scanner scanner = new Scanner(System.in); - args = scanner.nextLine().split(" "); - scanner.close(); - - String projectName; - if (args.length < 1 || (projectName=args[0]) == null || projectName.isEmpty()) { - throw new IllegalArgumentException("Wrong argument provided"); - } - - Payload payload = JAXB_PARSER.unmarshal(Resources.getResource(MainXml.class, "/myPayload.xml").openStream()); - -/* for (Project project : payload.getProjects().getProject()) { - if (project.getName().equals(projectName)) { - break; - } - System.out.println("WARNING: No project with name " + projectName + " found!"); - }*/ - - List projectGroups = new ArrayList<>(); - for (Group group : payload.getGroups().getGroup()) { - if (group.getProject().equals(projectName)) { - projectGroups.add(group.getName()); - } - } - if (projectGroups.isEmpty()) { - System.out.println("There is no groups with this project!"); - return; - } - - List projectUsers = new ArrayList<>(); - for (User user : payload.getUsers().getUser()) { - for (String groupName : user.getGroups()) { - if (projectGroups.contains(groupName)) { - projectUsers.add(user); - break; - } - } - } - - if (projectUsers.isEmpty()) { - System.out.println("No users for project " + projectName + " found!"); - } else { - projectUsers.sort(Comparator.comparing(User::getFullName)); - for (User user : projectUsers) { - System.out.println(user.getFullName()); - } - } - - - System.out.println("Stax Test"); - - try (StaxStreamProcessor processor = - new StaxStreamProcessor(Resources.getResource(MainXml.class, "/myPayload.xml").openStream())) { - XMLStreamReader reader = processor.getReader(); - QName tagName; - while (reader.hasNext()) { - int event = reader.next(); - if (event == XMLEvent.START_ELEMENT) { - if ("Projects".equals(reader.getLocalName())) { - while (true) { - event = reader.nextTag(); - if (event == XMLEvent.END_ELEMENT && reader.getLocalName().equals("Projects")) {break;} - if (event == XMLEvent.START_ELEMENT && reader.getLocalName().equals("Project")) { - - } - } - } else if ("Groups".equals(reader.getLocalName())) { - - } else if ("Users".equals(reader.getLocalName())) { - - } - } - } - } - } -} diff --git a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java index 77f2f09c3..71f5db8b9 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/ObjectFactory.java @@ -34,27 +34,27 @@ public ObjectFactory() { } /** - * Create an instance of {@link Payload } + * Create an instance of {@link Project } * */ - public Payload createPayload() { - return new Payload(); + public Project createProject() { + return new Project(); } /** - * Create an instance of {@link Project } + * Create an instance of {@link Payload } * */ - public Project createProject() { - return new Project(); + public Payload createPayload() { + return new Payload(); } /** - * Create an instance of {@link Group } + * Create an instance of {@link Project.Group } * */ - public Group createGroup() { - return new Group(); + public Project.Group createProjectGroup() { + return new Project.Group(); } /** @@ -65,6 +65,14 @@ public User createUser() { 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 } * @@ -81,22 +89,6 @@ public Payload.Users createPayloadUsers() { return new Payload.Users(); } - /** - * Create an instance of {@link Payload.Projects } - * - */ - public Payload.Projects createPayloadProjects() { - return new Payload.Projects(); - } - - /** - * Create an instance of {@link Payload.Groups } - * - */ - public Payload.Groups createPayloadGroups() { - return new Payload.Groups(); - } - /** * Create an instance of {@link CityType } * diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Payload.java b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java index aa1cef97d..70676686f 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/Payload.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/Payload.java @@ -19,52 +19,41 @@ * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> - * <all> - * <element name="Cities"> + * <sequence> + * <element name="Projects"> * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence maxOccurs="unbounded"> - * <element ref="{http://rolep.net}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://rolep.net}User"/> + * <element ref="{http://rolep.net}Project"/> * </sequence> * </restriction> * </complexContent> * </complexType> * </element> - * <element name="Projects"> + * <element name="Cities"> * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> - * <sequence maxOccurs="unbounded" minOccurs="0"> - * <element ref="{http://rolep.net}Project"/> + * <sequence maxOccurs="unbounded"> + * <element ref="{http://rolep.net}City"/> * </sequence> * </restriction> * </complexContent> * </complexType> * </element> - * <element name="Groups"> + * <element name="Users"> * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence maxOccurs="unbounded" minOccurs="0"> - * <element ref="{http://rolep.net}Group"/> + * <element ref="{http://rolep.net}User"/> * </sequence> * </restriction> * </complexContent> * </complexType> * </element> - * </all> + * </sequence> * </restriction> * </complexContent> * </complexType> @@ -74,114 +63,90 @@ */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { - + "projects", + "cities", + "users" }) @XmlRootElement(name = "Payload", namespace = "http://rolep.net") public class Payload { + @XmlElement(name = "Projects", namespace = "http://rolep.net", required = true) + protected Payload.Projects projects; @XmlElement(name = "Cities", namespace = "http://rolep.net", required = true) protected Payload.Cities cities; @XmlElement(name = "Users", namespace = "http://rolep.net", required = true) protected Payload.Users users; - @XmlElement(name = "Projects", namespace = "http://rolep.net", required = true) - protected Payload.Projects projects; - @XmlElement(name = "Groups", namespace = "http://rolep.net", required = true) - protected Payload.Groups groups; /** - * 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. + * Gets the value of the projects property. * * @return * possible object is - * {@link Payload.Users } + * {@link Payload.Projects } * */ - public Payload.Users getUsers() { - return users; + public Payload.Projects getProjects() { + return projects; } /** - * Sets the value of the users property. + * Sets the value of the projects property. * * @param value * allowed object is - * {@link Payload.Users } + * {@link Payload.Projects } * */ - public void setUsers(Payload.Users value) { - this.users = value; + public void setProjects(Payload.Projects value) { + this.projects = value; } /** - * Gets the value of the projects property. + * Gets the value of the cities property. * * @return * possible object is - * {@link Payload.Projects } + * {@link Payload.Cities } * */ - public Payload.Projects getProjects() { - return projects; + public Payload.Cities getCities() { + return cities; } /** - * Sets the value of the projects property. + * Sets the value of the cities property. * * @param value * allowed object is - * {@link Payload.Projects } + * {@link Payload.Cities } * */ - public void setProjects(Payload.Projects value) { - this.projects = value; + public void setCities(Payload.Cities value) { + this.cities = value; } /** - * Gets the value of the groups property. + * Gets the value of the users property. * * @return * possible object is - * {@link Payload.Groups } + * {@link Payload.Users } * */ - public Payload.Groups getGroups() { - return groups; + public Payload.Users getUsers() { + return users; } /** - * Sets the value of the groups property. + * Sets the value of the users property. * * @param value * allowed object is - * {@link Payload.Groups } + * {@link Payload.Users } * */ - public void setGroups(Payload.Groups value) { - this.groups = value; + public void setUsers(Payload.Users value) { + this.users = value; } @@ -254,67 +219,7 @@ public List getCity() { * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> - * <sequence maxOccurs="unbounded" minOccurs="0"> - * <element ref="{http://rolep.net}Group"/> - * </sequence> - * </restriction> - * </complexContent> - * </complexType> - * - * - * - */ - @XmlAccessorType(XmlAccessType.FIELD) - @XmlType(name = "", propOrder = { - "group" - }) - public static class Groups { - - @XmlElement(name = "Group", namespace = "http://rolep.net") - protected List group; - - /** - * 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 Group } - * - * - */ - public List getGroup() { - if (group == null) { - group = new ArrayList(); - } - return this.group; - } - - } - - - /** - *

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">
+     *       <sequence maxOccurs="unbounded">
      *         <element ref="{http://rolep.net}Project"/>
      *       </sequence>
      *     </restriction>
@@ -330,7 +235,7 @@ public List getGroup() {
     })
     public static class Projects {
 
-        @XmlElement(name = "Project", namespace = "http://rolep.net")
+        @XmlElement(name = "Project", namespace = "http://rolep.net", required = true)
         protected List project;
 
         /**
diff --git a/src/main/java/net/rolep/masterjava/xml/schema/Project.java b/src/main/java/net/rolep/masterjava/xml/schema/Project.java
index 66c8f9b66..2c0739d32 100644
--- a/src/main/java/net/rolep/masterjava/xml/schema/Project.java
+++ b/src/main/java/net/rolep/masterjava/xml/schema/Project.java
@@ -1,11 +1,18 @@
 
 package net.rolep.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;
 
 
 /**
@@ -18,9 +25,21 @@
  *   <complexContent>
  *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
  *       <sequence>
- *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *         <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://rolep.net}groupType" />
+ *                 </restriction>
+ *               </complexContent>
+ *             </complexType>
+ *           </element>
+ *         </sequence>
  *       </sequence>
+ *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
  *     </restriction>
  *   </complexContent>
  * </complexType>
@@ -30,63 +49,175 @@
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "", propOrder = {
-    "name",
-    "description"
+    "description",
+    "group"
 })
 @XmlRootElement(name = "Project", namespace = "http://rolep.net")
 public class Project {
 
     @XmlElement(namespace = "http://rolep.net", required = true)
-    protected String name;
-    @XmlElement(namespace = "http://rolep.net")
     protected String description;
+    @XmlElement(name = "Group", namespace = "http://rolep.net", required = true)
+    protected List group;
+    @XmlAttribute(name = "name", required = true)
+    protected String name;
 
     /**
-     * Gets the value of the name property.
+     * Gets the value of the description property.
      * 
      * @return
      *     possible object is
      *     {@link String }
      *     
      */
-    public String getName() {
-        return name;
+    public String getDescription() {
+        return description;
     }
 
     /**
-     * Sets the value of the name property.
+     * Sets the value of the description property.
      * 
      * @param value
      *     allowed object is
      *     {@link String }
      *     
      */
-    public void setName(String value) {
-        this.name = value;
+    public void setDescription(String value) {
+        this.description = value;
     }
 
     /**
-     * Gets the value of the description property.
+     * 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 getDescription() { - return description; + public String getName() { + return name; } /** - * Sets the value of the description property. + * Sets the value of the name property. * * @param value * allowed object is * {@link String } * */ - public void setDescription(String value) { - this.description = value; + 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://rolep.net}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; + } + } } diff --git a/src/main/java/net/rolep/masterjava/xml/schema/User.java b/src/main/java/net/rolep/masterjava/xml/schema/User.java index 785bf9b8a..1159c3047 100644 --- a/src/main/java/net/rolep/masterjava/xml/schema/User.java +++ b/src/main/java/net/rolep/masterjava/xml/schema/User.java @@ -6,12 +6,11 @@ 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.XmlList; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlValue; /** @@ -21,21 +20,14 @@ * *
  * <complexType>
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="groups" minOccurs="0">
- *           <simpleType>
- *             <list itemType="{http://www.w3.org/2001/XMLSchema}string" />
- *           </simpleType>
- *         </element>
- *       </sequence>
+ *   <simpleContent>
+ *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ *       <attribute name="email" use="required" type="{http://rolep.net}emailType" />
  *       <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
  *       <attribute name="flag" use="required" type="{http://rolep.net}flagType" />
- *       <attribute name="email" use="required" type="{http://rolep.net}emailType" />
- *     </restriction>
- *   </complexContent>
+ *       <attribute name="groupRefs" type="{http://www.w3.org/2001/XMLSchema}IDREFS" />
+ *     </extension>
+ *   </simpleContent>
  * </complexType>
  * 
* @@ -43,77 +35,72 @@ */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { - "fullName", - "groups" + "value" }) @XmlRootElement(name = "User", namespace = "http://rolep.net") public class User { - @XmlElement(namespace = "http://rolep.net", required = true) - protected String fullName; - @XmlList - @XmlElement(namespace = "http://rolep.net") - protected List groups; + @XmlValue + protected String value; + @XmlAttribute(name = "email", required = true) + protected String email; @XmlAttribute(name = "city", required = true) @XmlIDREF @XmlSchemaType(name = "IDREF") protected Object city; @XmlAttribute(name = "flag", required = true) protected FlagType flag; - @XmlAttribute(name = "email", required = true) - protected String email; + @XmlAttribute(name = "groupRefs") + @XmlIDREF + @XmlSchemaType(name = "IDREFS") + protected List groupRefs; /** - * Gets the value of the fullName property. + * Gets the value of the value property. * * @return * possible object is * {@link String } * */ - public String getFullName() { - return fullName; + public String getValue() { + return value; } /** - * Sets the value of the fullName property. + * Sets the value of the value property. * * @param value * allowed object is * {@link String } * */ - public void setFullName(String value) { - this.fullName = value; + public void setValue(String value) { + this.value = value; } /** - * Gets the value of the groups 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 groups property. - * - *

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

-     *    getGroups().add(newItem);
-     * 
- * - * - *

- * Objects of the following type(s) are allowed in the list - * {@link String } + * 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 List getGroups() { - if (groups == null) { - groups = new ArrayList(); - } - return this.groups; + public void setEmail(String value) { + this.email = value; } /** @@ -165,27 +152,36 @@ public void setFlag(FlagType value) { } /** - * Gets the value of the email property. + * 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 } * - * @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; + public List getGroupRefs() { + if (groupRefs == null) { + groupRefs = new ArrayList(); + } + return this.groupRefs; } + @Override + public String toString() { + return value + '(' + email +')'; + } } diff --git a/src/main/java/net/rolep/masterjava/xml/util/Schemas.java b/src/main/java/net/rolep/masterjava/xml/util/Schemas.java index c56c5ddc8..a8755cf8f 100644 --- a/src/main/java/net/rolep/masterjava/xml/util/Schemas.java +++ b/src/main/java/net/rolep/masterjava/xml/util/Schemas.java @@ -28,7 +28,7 @@ public static synchronized Schema ofString(String xsd) { } public static synchronized Schema ofClasspath(String resource) { - return ofURL(Resources.getResource(Schema.class, resource)); + return ofURL(Resources.getResource(resource)); } public static synchronized Schema ofURL(URL url) { diff --git a/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java index 302bd5ef6..c73676ecd 100644 --- a/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java +++ b/src/main/java/net/rolep/masterjava/xml/util/StaxStreamProcessor.java @@ -23,15 +23,26 @@ public XMLStreamReader getReader() { } public boolean doUntil(int stopEvent, String value) throws XMLStreamException { + return doUntilAny(stopEvent, value) != null; + } + + 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(getValue(event))) { + return xmlValue; + } } } } - return false; + return null; + } + + public String getAttribute(String name) { + return reader.getAttributeValue(null, name); } public String getValue(int event) { diff --git a/src/main/resources/myPayload.xml b/src/main/resources/myPayload.xml deleted file mode 100644 index c6672b6ad..000000000 --- a/src/main/resources/myPayload.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - Full Name - - - - Admin - masterjava02 topjava10 - - - Deleted - topjava09 topjava10 - - - - - Санкт-Петербург - Киев - Минск - - - - MasterJava - Разработка полнофункционального многомодульного Maven проекта - - - TopJava - Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ - Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins - - - - - topjava10 - TopJava - - - TopJava09 - TopJava - - - masterjava02 - MasterJava - - - \ No newline at end of file diff --git a/src/main/resources/myPayload.xsd b/src/main/resources/myPayload.xsd index e3f3fe810..c59e87e91 100644 --- a/src/main/resources/myPayload.xsd +++ b/src/main/resources/myPayload.xsd @@ -6,111 +6,62 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema"> - - + + - - - - - - - - + - + - - + + - + - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + - + - - - - - - + + + + + + + + - - - - @@ -136,7 +87,7 @@ - + diff --git a/src/test/java/net/rolep/masterjava/xml/MainXml.java b/src/test/java/net/rolep/masterjava/xml/MainXml.java new file mode 100644 index 000000000..d7542f86f --- /dev/null +++ b/src/test/java/net/rolep/masterjava/xml/MainXml.java @@ -0,0 +1,132 @@ +package net.rolep.masterjava.xml; + +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.io.Resources; +import j2html.tags.ContainerTag; +import net.rolep.masterjava.xml.schema.ObjectFactory; +import net.rolep.masterjava.xml.schema.Payload; +import net.rolep.masterjava.xml.schema.Project; +import net.rolep.masterjava.xml.schema.User; +import net.rolep.masterjava.xml.util.JaxbParser; +import net.rolep.masterjava.xml.util.Schemas; +import net.rolep.masterjava.xml.util.StaxStreamProcessor; +import one.util.streamex.StreamEx; + +import javax.xml.stream.events.XMLEvent; +import java.io.IOException; +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 + * Date: 05.08.2015 + * + * @link http://caloriesmng.herokuapp.com/ + * @link https://github.com/JavaOPs/topjava + */ +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, xmlName"); + System.exit(1); + } + URL payloadUrl = Resources.getResource("myPayload.xml"); + String projectName = args[0]; + + 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/myUsers.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 { + JaxbParser parser = new JaxbParser(ObjectFactory.class); + parser.setSchema(Schemas.ofClasspath("myPayload.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()); + return StreamEx.of(payload.getUsers().getUser()) + .filter(u -> !Collections.disjoint(u.getGroupRefs(), groups)) + .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR))); + + } + + private static String toHtml(Set users, String projectName) throws IOException { + 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(); + } + + private static Set processByStax(String projectName, URL payloadUrl) throws Exception { + try (InputStream is = payloadUrl.openStream()) { + StaxStreamProcessor processor = new StaxStreamProcessor(is); + Set groupNames = new HashSet<>(); + Set users = new TreeSet<>(USER_COMPARATOR); + String element; + + // Projects loop + projects: + while (processor.doUntil(XMLEvent.START_ELEMENT, "Project")) { + if (projectName.equals(processor.getAttribute("name"))) { + // Groups loop + 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 + while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) { + String groupRefs = processor.getAttribute("groupRefs"); + if (!Collections.disjoint(groupNames, Splitter.on(' ').splitToList(Strings.nullToEmpty(groupRefs)))) { + User user = new User(); + user.setEmail(processor.getAttribute("email")); + user.setValue(processor.getReader().getElementText()); + users.add(user); + } + } + return users; + } + } +} diff --git a/src/test/java/ru/javaops/masterjava/MainXml.java b/src/test/java/ru/javaops/masterjava/MainXml.java index 3649398f5..5816235d4 100644 --- a/src/test/java/ru/javaops/masterjava/MainXml.java +++ b/src/test/java/ru/javaops/masterjava/MainXml.java @@ -13,7 +13,6 @@ import ru.javaops.masterjava.xml.util.Schemas; import ru.javaops.masterjava.xml.util.StaxStreamProcessor; -import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import java.io.IOException; import java.io.InputStream; @@ -35,10 +34,7 @@ */ public class MainXml { - public static final Comparator USER_COMPARATOR = Comparator.comparing(User::getValue).thenComparing(User::getEmail); - public static final String PROJECT = "Project"; - public static final String USERS = "Users"; - public static final String GROUP = "Group"; + 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) { @@ -105,11 +101,11 @@ private static Set processByStax(String projectName, URL payloadUrl) throw // Projects loop projects: - while (processor.doUntil(XMLEvent.START_ELEMENT, PROJECT)) { + while (processor.doUntil(XMLEvent.START_ELEMENT, "Project")) { if (projectName.equals(processor.getAttribute("name"))) { // Groups loop - while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, GROUP, USERS)) != null) { - if (!element.equals(GROUP)) { + while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, "Project", "Group", "Users")) != null) { + if (!element.equals("Group")) { break projects; } groupNames.add(processor.getAttribute("name")); diff --git a/src/test/resources/myPayload.xml b/src/test/resources/myPayload.xml index c6672b6ad..4a18d6299 100644 --- a/src/test/resources/myPayload.xml +++ b/src/test/resources/myPayload.xml @@ -1,49 +1,31 @@ - - - Full Name - - - - Admin - masterjava02 topjava10 - - - Deleted - topjava09 topjava10 - - - + + + Topjava + + + + + + Masterjava + + + + Санкт-Петербург + Москва Киев Минск - - - MasterJava - Разработка полнофункционального многомодульного Maven проекта - - - TopJava - Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ - Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins - - - - - topjava10 - TopJava - - - TopJava09 - TopJava - - - masterjava02 - MasterJava - - + + Full Name + Admin + Deleted + User1 + User2 + User3 + \ No newline at end of file From 8a33c86884a8d9c07d3ee7f4d472a1b1c83760af Mon Sep 17 00:00:00 2001 From: rolep Date: Sun, 26 Mar 2017 11:16:24 +0300 Subject: [PATCH 40/97] 3_4 hw2 xslt my --- .../masterjava/xml/util/XsltProcessor.java | 4 ++ src/main/resources/myGroups,xsl | 37 +++++++++++++++++++ .../net/rolep/masterjava/xml/MainXml.java | 16 ++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/main/resources/myGroups,xsl diff --git a/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java b/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java index 642afc4b5..8b60842de 100644 --- a/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java +++ b/src/main/java/net/rolep/masterjava/xml/util/XsltProcessor.java @@ -43,4 +43,8 @@ public void transform(Reader sourceReader, Writer result) throws TransformerExce public static String getXsltHeader(String xslt) { return "\n"; } + + public void setParameter(String name, String value) { + xformer.setParameter(name, value); + } } diff --git a/src/main/resources/myGroups,xsl b/src/main/resources/myGroups,xsl new file mode 100644 index 000000000..1193dc564 --- /dev/null +++ b/src/main/resources/myGroups,xsl @@ -0,0 +1,37 @@ + + + + + + + + + <xsl:value-of select="$projectName"/> groups + + + +

+ groups +

+ + + + + + + + + + + +
GroupType
+ + + +
+ + +
+ +
\ No newline at end of file diff --git a/src/test/java/net/rolep/masterjava/xml/MainXml.java b/src/test/java/net/rolep/masterjava/xml/MainXml.java index d7542f86f..6b1e16c13 100644 --- a/src/test/java/net/rolep/masterjava/xml/MainXml.java +++ b/src/test/java/net/rolep/masterjava/xml/MainXml.java @@ -11,6 +11,7 @@ import net.rolep.masterjava.xml.util.JaxbParser; import net.rolep.masterjava.xml.util.Schemas; import net.rolep.masterjava.xml.util.StaxStreamProcessor; +import net.rolep.masterjava.xml.util.XsltProcessor; import one.util.streamex.StreamEx; import javax.xml.stream.events.XMLEvent; @@ -56,6 +57,12 @@ public static void main(String[] args) throws Exception { System.out.println(); users = processByStax(projectName, payloadUrl); users.forEach(System.out::println); + + html = transform(projectName, payloadUrl); + System.out.println(html); + try (Writer writer = Files.newBufferedWriter(Paths.get("out/myGroupsXslt.html"))) { + writer.write(html); + } } private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception { @@ -129,4 +136,13 @@ private static Set processByStax(String projectName, URL payloadUrl) throw return users; } } + + private static String transform(String projectName, URL payloadUrl) throws Exception { + URL xsl = Resources.getResource("myGroups.xsl"); + try (InputStream xmlStream = payloadUrl.openStream(); InputStream xslStream = xsl.openStream()) { + XsltProcessor processor = new XsltProcessor(xslStream); + processor.setParameter("projectName", projectName); + return processor.transform(xmlStream); + } + } } From e12e8084cbd932bacd857b220c64f8973b9dce64 Mon Sep 17 00:00:00 2001 From: rolep Date: Sun, 26 Mar 2017 11:16:40 +0300 Subject: [PATCH 41/97] 3 4 HW2 xslt --- .../masterjava/xml/util/XsltProcessor.java | 4 +++ .../resources/{myGroups,xsl => groups.xsl} | 1 - src/main/resources/myGroups.xsl | 36 +++++++++++++++++++ .../rolep/masterjava/{xml => }/MainXml.java | 5 ++- .../java/ru/javaops/masterjava/MainXml.java | 15 ++++++++ 5 files changed, 57 insertions(+), 4 deletions(-) rename src/main/resources/{myGroups,xsl => groups.xsl} (99%) create mode 100644 src/main/resources/myGroups.xsl rename src/test/java/net/rolep/masterjava/{xml => }/MainXml.java (97%) diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java index 359a379ea..4a395ba3e 100644 --- a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java +++ b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java @@ -45,4 +45,8 @@ public void transform(Reader sourceReader, Writer result) throws TransformerExce public static String getXsltHeader(String xslt) { return "\n"; } + + public void setParameter(String name, String value) { + xformer.setParameter(name, value); + } } diff --git a/src/main/resources/myGroups,xsl b/src/main/resources/groups.xsl similarity index 99% rename from src/main/resources/myGroups,xsl rename to src/main/resources/groups.xsl index 1193dc564..dcb6901a2 100644 --- a/src/main/resources/myGroups,xsl +++ b/src/main/resources/groups.xsl @@ -33,5 +33,4 @@ - \ No newline at end of file diff --git a/src/main/resources/myGroups.xsl b/src/main/resources/myGroups.xsl new file mode 100644 index 000000000..dcb6901a2 --- /dev/null +++ b/src/main/resources/myGroups.xsl @@ -0,0 +1,36 @@ + + + + + + + + + <xsl:value-of select="$projectName"/> groups + + + +

+ groups +

+ + + + + + + + + + + +
GroupType
+ + + +
+ + +
+
\ No newline at end of file diff --git a/src/test/java/net/rolep/masterjava/xml/MainXml.java b/src/test/java/net/rolep/masterjava/MainXml.java similarity index 97% rename from src/test/java/net/rolep/masterjava/xml/MainXml.java rename to src/test/java/net/rolep/masterjava/MainXml.java index 6b1e16c13..0c252d308 100644 --- a/src/test/java/net/rolep/masterjava/xml/MainXml.java +++ b/src/test/java/net/rolep/masterjava/MainXml.java @@ -1,4 +1,4 @@ -package net.rolep.masterjava.xml; +package net.rolep.masterjava; import com.google.common.base.Splitter; import com.google.common.base.Strings; @@ -39,7 +39,7 @@ public class MainXml { public static void main(String[] args) throws Exception { if (args.length != 1) { - System.out.println("Format: projectName, xmlName"); + System.out.println("Format: projectName"); System.exit(1); } URL payloadUrl = Resources.getResource("myPayload.xml"); @@ -59,7 +59,6 @@ public static void main(String[] args) throws Exception { users.forEach(System.out::println); html = transform(projectName, payloadUrl); - System.out.println(html); try (Writer writer = Files.newBufferedWriter(Paths.get("out/myGroupsXslt.html"))) { writer.write(html); } diff --git a/src/test/java/ru/javaops/masterjava/MainXml.java b/src/test/java/ru/javaops/masterjava/MainXml.java index 5816235d4..8aefbc0b3 100644 --- a/src/test/java/ru/javaops/masterjava/MainXml.java +++ b/src/test/java/ru/javaops/masterjava/MainXml.java @@ -12,6 +12,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.IOException; @@ -56,6 +57,11 @@ public static void main(String[] args) throws Exception { 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 { @@ -129,5 +135,14 @@ private static Set processByStax(String projectName, URL payloadUrl) throw return users; } } + + 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); + } + } } From 12456b0a5e19e7f1ee1f0303fa2bb41828f4e8ae Mon Sep 17 00:00:00 2001 From: rolep Date: Wed, 29 Mar 2017 13:55:58 +0300 Subject: [PATCH 42/97] lesson4 patch files added --- patches/lesson04/4_1_HW3_pom_structure.patch | 490 +++++++++++++++ .../lesson04/4_2_HW3_thymeleaf_upload.patch | 428 ++++++++++++++ .../lesson04/4_3_HW3_upload_servlet3.patch | 83 +++ patches/lesson04/4_4_dependencies.patch | 33 ++ patches/lesson04/4_5_fix_convergence.patch | 58 ++ patches/lesson04/4_6_enforcer.patch | 32 + patches/lesson04/4_7_logging.patch | 186 ++++++ patches/lesson04/4_8_fix_and_context.patch | 87 +++ patches/lesson04/4_9_persist.patch | 559 ++++++++++++++++++ 9 files changed, 1956 insertions(+) create mode 100644 patches/lesson04/4_1_HW3_pom_structure.patch create mode 100644 patches/lesson04/4_2_HW3_thymeleaf_upload.patch create mode 100644 patches/lesson04/4_3_HW3_upload_servlet3.patch create mode 100644 patches/lesson04/4_4_dependencies.patch create mode 100644 patches/lesson04/4_5_fix_convergence.patch create mode 100644 patches/lesson04/4_6_enforcer.patch create mode 100644 patches/lesson04/4_7_logging.patch create mode 100644 patches/lesson04/4_8_fix_and_context.patch create mode 100644 patches/lesson04/4_9_persist.patch 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; From cca0127c36f28bba0856f5ec7be1e0b78de4048e Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Mon, 3 Apr 2017 15:43:41 +0300 Subject: [PATCH 43/97] 3 5 multimodule --- common/pom.xml | 21 +++++++ export/pom.xml | 39 +++++++++++++ parent/pom.xml | 69 +++++++++++++++++++++++ pom.xml | 145 ++++--------------------------------------------- 4 files changed, 140 insertions(+), 134 deletions(-) create mode 100644 common/pom.xml create mode 100644 export/pom.xml create mode 100644 parent/pom.xml 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/export/pom.xml b/export/pom.xml new file mode 100644 index 000000000..0d2d1b34c --- /dev/null +++ b/export/pom.xml @@ -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 diff --git a/parent/pom.xml b/parent/pom.xml new file mode 100644 index 000000000..6fe28bda3 --- /dev/null +++ b/parent/pom.xml @@ -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 diff --git a/pom.xml b/pom.xml index dfc31f445..330a0d8e8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,144 +4,21 @@ ru.javaops masterjava - jar + pom 1.0-SNAPSHOT Master Java https://github.com/JavaOPs/masterjava - - 1.8 - UTF-8 - UTF-8 - 1.18 - 21.0 - 4.12 - 0.6.5 - 0.88 - - - - 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 - - - - - - - - - - - - - - - - javax.servlet - javax.servlet-api - 4.0.0-b03 - - - - - org.openjdk.jmh - jmh-core - ${jmh.version} - - - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh.version} - provided - - - - - com.google.guava - guava - ${guava.version} - - - - - one.util - streamex - ${streamex.version} - - - - - com.j2html - j2html - ${j2html.version} - - - - - - junit - junit - ${junit.version} - test - - - - - - - - - + + export + common + + From 049c426d6d0f6ad5ef66ddec4a9afed3b4ebba72 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Mon, 3 Apr 2017 15:50:12 +0300 Subject: [PATCH 44/97] 4 1 HW3 pom structure --- {export => parent-web}/pom.xml | 19 +++-- pom.xml | 11 +-- services/mail-api/pom.xml | 26 +++++++ services/mail-service/pom.xml | 26 +++++++ .../masterjava/service/mail}/MailService.java | 2 +- services/pom.xml | 15 ++++ test/pom.xml | 76 +++++++++++++++++++ .../javaops/masterjava/matrix/MainMatrix.java | 0 .../masterjava/matrix/MatrixBenchmark.java | 0 .../javaops/masterjava/matrix/MatrixUtil.java | 0 web/export/pom.xml | 31 ++++++++ .../masterjava/xml/schema/CityType.java | 0 .../masterjava/xml/schema/FlagType.java | 0 .../masterjava/xml/schema/GroupType.java | 0 .../masterjava/xml/schema/ObjectFactory.java | 0 .../masterjava/xml/schema/Payload.java | 0 .../masterjava/xml/schema/Project.java | 0 .../javaops/masterjava/xml/schema/User.java | 0 .../masterjava/xml/util/JaxbMarshaller.java | 0 .../masterjava/xml/util/JaxbParser.java | 0 .../masterjava/xml/util/JaxbUnmarshaller.java | 0 .../javaops/masterjava/xml/util/Schemas.java | 0 .../xml/util/StaxStreamProcessor.java | 0 .../masterjava/xml/util/XPathProcessor.java | 0 .../masterjava/xml/util/XsltProcessor.java | 0 .../export/src}/main/resources/cities.xsl | 0 .../export/src}/main/resources/groups.xsl | 0 .../export/src}/main/resources/payload.xsd | 0 .../java/ru/javaops/masterjava/MainXml.java | 0 .../masterjava/xml/util/JaxbParserTest.java | 0 .../xml/util/StaxStreamProcessorTest.java | 0 .../xml/util/XPathProcessorTest.java | 0 .../xml/util/XsltProcessorTest.java | 0 .../export/src}/test/resources/city.xml | 0 .../export/src}/test/resources/payload.xml | 0 web/pom.xml | 15 ++++ web/webapp/pom.xml | 26 +++++++ 37 files changed, 232 insertions(+), 15 deletions(-) rename {export => parent-web}/pom.xml (74%) create mode 100644 services/mail-api/pom.xml create mode 100644 services/mail-service/pom.xml rename {src/main/java/ru/javaops/masterjava/service => services/mail-service/src/main/java/ru/javaops/masterjava/service/mail}/MailService.java (99%) create mode 100644 services/pom.xml create mode 100644 test/pom.xml rename {src => test/src}/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (100%) rename {src => test/src}/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (100%) rename {src => test/src}/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (100%) create mode 100644 web/export/pom.xml rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/CityType.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/Payload.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/Project.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/schema/User.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/Schemas.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (100%) rename {src => web/export/src}/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (100%) rename {src => web/export/src}/main/resources/cities.xsl (100%) rename {src => web/export/src}/main/resources/groups.xsl (100%) rename {src => web/export/src}/main/resources/payload.xsd (100%) rename {src => web/export/src}/test/java/ru/javaops/masterjava/MainXml.java (100%) rename {src => web/export/src}/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (100%) rename {src => web/export/src}/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (100%) rename {src => web/export/src}/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (100%) rename {src => web/export/src}/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (100%) rename {src => web/export/src}/test/resources/city.xml (100%) rename {src => web/export/src}/test/resources/payload.xml (100%) create mode 100644 web/pom.xml create mode 100644 web/webapp/pom.xml diff --git a/export/pom.xml b/parent-web/pom.xml similarity index 74% rename from export/pom.xml rename to parent-web/pom.xml index 0d2d1b34c..ac59247ba 100644 --- a/export/pom.xml +++ b/parent-web/pom.xml @@ -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 diff --git a/pom.xml b/pom.xml index 330a0d8e8..68ac6ad48 100644 --- a/pom.xml +++ b/pom.xml @@ -8,17 +8,12 @@ 1.0-SNAPSHOT - Master Java + MasterJava Root https://github.com/JavaOPs/masterjava - export common - + web + services diff --git a/services/mail-api/pom.xml b/services/mail-api/pom.xml new file mode 100644 index 000000000..25c53388e --- /dev/null +++ b/services/mail-api/pom.xml @@ -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 diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml new file mode 100644 index 000000000..2b4be6bad --- /dev/null +++ b/services/mail-service/pom.xml @@ -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 diff --git a/src/main/java/ru/javaops/masterjava/service/MailService.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java similarity index 99% rename from src/main/java/ru/javaops/masterjava/service/MailService.java rename to services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index cef46e55e..1d9a0026b 100644 --- a/src/main/java/ru/javaops/masterjava/service/MailService.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -1,4 +1,4 @@ -package ru.javaops.masterjava.service; +package ru.javaops.masterjava.service.mail; import java.util.ArrayList; import java.util.List; diff --git a/services/pom.xml b/services/pom.xml new file mode 100644 index 000000000..bb7824194 --- /dev/null +++ b/services/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + ru.javaops + services + pom + 1.0-SNAPSHOT + + MasterJava Services + + mail-api + mail-service + + diff --git a/test/pom.xml b/test/pom.xml new file mode 100644 index 000000000..f469908cf --- /dev/null +++ b/test/pom.xml @@ -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 diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/test/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java rename to test/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/test/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java rename to test/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/test/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java rename to test/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java diff --git a/web/export/pom.xml b/web/export/pom.xml new file mode 100644 index 000000000..08872515c --- /dev/null +++ b/web/export/pom.xml @@ -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 diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/CityType.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/Payload.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Project.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/Project.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/Project.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/Project.java diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/web/export/src/main/java/ru/javaops/masterjava/xml/schema/User.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/schema/User.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/schema/User.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/Schemas.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/web/export/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java rename to web/export/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java diff --git a/src/main/resources/cities.xsl b/web/export/src/main/resources/cities.xsl similarity index 100% rename from src/main/resources/cities.xsl rename to web/export/src/main/resources/cities.xsl diff --git a/src/main/resources/groups.xsl b/web/export/src/main/resources/groups.xsl similarity index 100% rename from src/main/resources/groups.xsl rename to web/export/src/main/resources/groups.xsl diff --git a/src/main/resources/payload.xsd b/web/export/src/main/resources/payload.xsd similarity index 100% rename from src/main/resources/payload.xsd rename to web/export/src/main/resources/payload.xsd diff --git a/src/test/java/ru/javaops/masterjava/MainXml.java b/web/export/src/test/java/ru/javaops/masterjava/MainXml.java similarity index 100% rename from src/test/java/ru/javaops/masterjava/MainXml.java rename to web/export/src/test/java/ru/javaops/masterjava/MainXml.java diff --git a/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java b/web/export/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java similarity index 100% rename from src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java rename to web/export/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java diff --git a/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java b/web/export/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java similarity index 100% rename from src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java rename to web/export/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java diff --git a/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java b/web/export/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java similarity index 100% rename from src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java rename to web/export/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java diff --git a/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java b/web/export/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java similarity index 100% rename from src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java rename to web/export/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java diff --git a/src/test/resources/city.xml b/web/export/src/test/resources/city.xml similarity index 100% rename from src/test/resources/city.xml rename to web/export/src/test/resources/city.xml diff --git a/src/test/resources/payload.xml b/web/export/src/test/resources/payload.xml similarity index 100% rename from src/test/resources/payload.xml rename to web/export/src/test/resources/payload.xml diff --git a/web/pom.xml b/web/pom.xml new file mode 100644 index 000000000..f1fd40ede --- /dev/null +++ b/web/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + ru.javaops + web + pom + 1.0-SNAPSHOT + MasterJava Web + + + export + webapp + + diff --git a/web/webapp/pom.xml b/web/webapp/pom.xml new file mode 100644 index 000000000..0cf8c6098 --- /dev/null +++ b/web/webapp/pom.xml @@ -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 From 65e452b61f85e5492b936e510beeebece6adf6a2 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Mon, 3 Apr 2017 16:39:20 +0300 Subject: [PATCH 45/97] 4 2 HW3 thymeleaf upload --- parent-web/pom.xml | 5 ++ .../masterjava/common/web/ThymeleafUtil.java | 24 +++++++ web/common-web/pom.xml | 42 +++++++++++++ .../masterjava/export/ThymeleafListener.java | 21 +++++++ .../masterjava/export/UploadServlet.java | 56 +++++++++++++++++ .../javaops/masterjava/export/UserExport.java | 32 ++++++++++ .../ru/javaops/masterjava/model/User.java | 63 +++++++++++++++++++ .../ru/javaops/masterjava/model/UserFlag.java | 11 ++++ .../webapp/WEB-INF/templates/exception.html | 19 ++++++ .../main/webapp/WEB-INF/templates/export.html | 16 +++++ .../main/webapp/WEB-INF/templates/result.html | 26 ++++++++ web/pom.xml | 1 + 12 files changed, 316 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java create mode 100644 web/common-web/pom.xml create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java create mode 100644 web/export/src/main/java/ru/javaops/masterjava/model/User.java create mode 100644 web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java create mode 100644 web/export/src/main/webapp/WEB-INF/templates/exception.html create mode 100644 web/export/src/main/webapp/WEB-INF/templates/export.html create mode 100644 web/export/src/main/webapp/WEB-INF/templates/result.html diff --git a/parent-web/pom.xml b/parent-web/pom.xml index ac59247ba..8d1555ab0 100644 --- a/parent-web/pom.xml +++ b/parent-web/pom.xml @@ -30,6 +30,11 @@ + + ${project.groupId} + common-web + ${project.version} + javax.servlet javax.servlet-api diff --git a/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java b/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java new file mode 100644 index 000000000..bf87ed3eb --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java @@ -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; + } +} diff --git a/web/common-web/pom.xml b/web/common-web/pom.xml new file mode 100644 index 000000000..0bd4bb07d --- /dev/null +++ b/web/common-web/pom.xml @@ -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 diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java b/web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java new file mode 100644 index 000000000..8ec22e3c9 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java @@ -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) { + } +} 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 new file mode 100644 index 000000000..3983ee1bb --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UploadServlet.java @@ -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()); + } + } +} 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 new file mode 100644 index 000000000..27daf5f7c --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java @@ -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; + } +} diff --git a/web/export/src/main/java/ru/javaops/masterjava/model/User.java b/web/export/src/main/java/ru/javaops/masterjava/model/User.java new file mode 100644 index 000000000..d7c3f8cd3 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/model/User.java @@ -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 + + ')'; + } +} diff --git a/web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java b/web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java new file mode 100644 index 000000000..603626ae1 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/model/UserFlag.java @@ -0,0 +1,11 @@ +package ru.javaops.masterjava.model; + +/** + * gkislin + * 13.10.2016 + */ +public enum UserFlag { + active, + deleted, + superuser; +} diff --git a/web/export/src/main/webapp/WEB-INF/templates/exception.html b/web/export/src/main/webapp/WEB-INF/templates/exception.html new file mode 100644 index 000000000..6123126d2 --- /dev/null +++ b/web/export/src/main/webapp/WEB-INF/templates/exception.html @@ -0,0 +1,19 @@ + + + + Export XML + + + +

+
+
+

Application error:

+

exception.message

+
    +
  • +
+
+
+ + \ No newline at end of file diff --git a/web/export/src/main/webapp/WEB-INF/templates/export.html b/web/export/src/main/webapp/WEB-INF/templates/export.html new file mode 100644 index 000000000..1ed758208 --- /dev/null +++ b/web/export/src/main/webapp/WEB-INF/templates/export.html @@ -0,0 +1,16 @@ + + + Export XML + + +
+

Select xml file to upload

+

+
+

+

+ +

+
+ + \ No newline at end of file diff --git a/web/export/src/main/webapp/WEB-INF/templates/result.html b/web/export/src/main/webapp/WEB-INF/templates/result.html new file mode 100644 index 000000000..ca4baa915 --- /dev/null +++ b/web/export/src/main/webapp/WEB-INF/templates/result.html @@ -0,0 +1,26 @@ + + + + Uploaded users + + +

Export XML

+

Uploaded users

+ + + + + + + + + + + + + + + +
Full NameEmailFlag
+ + \ No newline at end of file diff --git a/web/pom.xml b/web/pom.xml index f1fd40ede..bf9ef21c3 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -9,6 +9,7 @@ MasterJava Web + common-web export webapp From dd6b4c33cf15c72d76ee62c4379591fdfc837943 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Mon, 3 Apr 2017 17:40:11 +0300 Subject: [PATCH 46/97] 4 2 HW3 thymeleaf upload - tlutil was in wrong directory --- .../main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src => web/common-web/src}/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java (100%) diff --git a/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java b/web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java similarity index 100% rename from src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java rename to web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafUtil.java From 361bf332a39c94901756ec26cad1520ff19c83d8 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Tue, 4 Apr 2017 13:29:12 +0300 Subject: [PATCH 47/97] 4 3 HW3 upload servlet3 --- web/common-web/pom.xml | 5 ---- .../masterjava/export/UploadServlet.java | 26 +++++++------------ 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/web/common-web/pom.xml b/web/common-web/pom.xml index 0bd4bb07d..29290f5d1 100644 --- a/web/common-web/pom.xml +++ b/web/common-web/pom.xml @@ -21,11 +21,6 @@ common ${project.version} - - commons-fileupload - commons-fileupload - 1.3.2 - javax.servlet javax.servlet-api 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 3983ee1bb..6b8e58734 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,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 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se @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); From a5eb083583de58834a80c64878de2a444c646722 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Wed, 5 Apr 2017 11:38:16 +0300 Subject: [PATCH 48/97] 4 4 dependencies --- parent/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parent/pom.xml b/parent/pom.xml index 6fe28bda3..4d1823ebb 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -14,6 +14,8 @@ 1.8 UTF-8 UTF-8 + + false From 9b545a6037939ae21e4bfb8dc87012ceb185e42a Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Wed, 5 Apr 2017 11:38:49 +0300 Subject: [PATCH 49/97] 4 5 fix convergence --- parent/pom.xml | 2 +- test/pom.xml | 4 ++-- web/export/pom.xml | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/parent/pom.xml b/parent/pom.xml index 4d1823ebb..6b8107eae 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -50,7 +50,7 @@ one.util streamex - RELEASE + 0.6.2 diff --git a/test/pom.xml b/test/pom.xml index f469908cf..bfab1855d 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -64,12 +64,12 @@ org.openjdk.jmh jmh-core - RELEASE + 1.15 org.openjdk.jmh jmh-generator-annprocess - RELEASE + 1.15 provided
diff --git a/web/export/pom.xml b/web/export/pom.xml index 08872515c..e64c94500 100644 --- a/web/export/pom.xml +++ b/web/export/pom.xml @@ -25,6 +25,12 @@ com.j2html j2html 0.7 + + + com.google.guava + guava + + From da4d6c82cd0b508bd1802f5cb79d63685e880fc8 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Wed, 5 Apr 2017 11:39:31 +0300 Subject: [PATCH 50/97] 4 6 enforcer --- parent/pom.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/parent/pom.xml b/parent/pom.xml index 6b8107eae..3e3635f7f 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -38,6 +38,24 @@ -Dfile.encoding=UTF-8 + + org.apache.maven.plugins + maven-enforcer-plugin + 1.4.1 + + + enforce + + + + + + + enforce + + + + From b4ef396970db6e56d7115b1e398098c2905d8cc6 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 13 Apr 2017 11:54:00 +0300 Subject: [PATCH 51/97] 4 7 logging --- config_templates/logback-test.xml | 21 ++++++++++++++++ config_templates/logback.xml | 40 +++++++++++++++++++++++++++++++ parent-web/pom.xml | 13 ++++++++++ parent/pom.xml | 31 ++++++++++++++++++++++++ web/common-web/pom.xml | 6 +++++ 5 files changed, 111 insertions(+) create mode 100644 config_templates/logback-test.xml create mode 100644 config_templates/logback.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/parent-web/pom.xml b/parent-web/pom.xml index 8d1555ab0..0c34224d3 100644 --- a/parent-web/pom.xml +++ b/parent-web/pom.xml @@ -27,6 +27,19 @@ + + + + ${masterjava.config} + true + + logback.xml + + + + src/main/resources + + diff --git a/parent/pom.xml b/parent/pom.xml index 3e3635f7f..b8fc732a9 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -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 + + @@ -71,6 +87,21 @@ 0.6.2 + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + runtime + + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + + junit diff --git a/web/common-web/pom.xml b/web/common-web/pom.xml index 29290f5d1..da4f46174 100644 --- a/web/common-web/pom.xml +++ b/web/common-web/pom.xml @@ -32,6 +32,12 @@ org.thymeleaf thymeleaf 3.0.3.RELEASE + + + org.slf4j + slf4j-api + + \ No newline at end of file From c5fb8f53a9fd2800b8ac87ea291dff5674e80daf Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 13 Apr 2017 11:54:53 +0300 Subject: [PATCH 52/97] 4 8 fix and context --- config_templates/context.xml | 49 +++++++++++++++++++++++++++++++ config_templates/logback-test.xml | 1 - parent/pom.xml | 1 - 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 config_templates/context.xml 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 index 739dd6dcf..b6815ab8d 100644 --- a/config_templates/logback-test.xml +++ b/config_templates/logback-test.xml @@ -12,7 +12,6 @@ - diff --git a/parent/pom.xml b/parent/pom.xml index b8fc732a9..90f1b8ec9 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -99,7 +99,6 @@ ch.qos.logback logback-classic ${logback.version} - runtime From 5c64802da4d9e14ace0024a17265089663901a75 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 13 Apr 2017 12:03:45 +0300 Subject: [PATCH 53/97] 4 9 persist --- config_templates/logback-test.xml | 1 + config_templates/sql/initDB.sql | 15 +++++ persist/pom.xml | 46 +++++++++++++++ .../masterjava/persist/DBIProvider.java | 56 +++++++++++++++++++ .../masterjava/persist/dao/AbstractDao.java | 11 ++++ .../masterjava/persist/dao/UserDao.java | 43 ++++++++++++++ .../masterjava/persist/model/BaseEntity.java | 41 ++++++++++++++ .../masterjava/persist}/model/User.java | 43 ++++++++++---- .../masterjava/persist}/model/UserFlag.java | 2 +- .../masterjava/persist/DBITestProvider.java | 24 ++++++++ .../masterjava/persist/UserTestData.java | 41 ++++++++++++++ .../persist/dao/AbstractDaoTest.java | 20 +++++++ .../masterjava/persist/dao/UserDaoTest.java | 39 +++++++++++++ pom.xml | 2 + web/export/pom.xml | 5 ++ .../masterjava/export/UploadServlet.java | 2 +- .../javaops/masterjava/export/UserExport.java | 4 +- 17 files changed, 379 insertions(+), 16 deletions(-) create mode 100644 config_templates/sql/initDB.sql create mode 100644 persist/pom.xml create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/AbstractDao.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java rename {web/export/src/main/java/ru/javaops/masterjava => persist/src/main/java/ru/javaops/masterjava/persist}/model/User.java (69%) rename {web/export/src/main/java/ru/javaops/masterjava => persist/src/main/java/ru/javaops/masterjava/persist}/model/UserFlag.java (68%) create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java diff --git a/config_templates/logback-test.xml b/config_templates/logback-test.xml index b6815ab8d..739dd6dcf 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 000000000..888ba8141 --- /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 000000000..5816258ef --- /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 000000000..69904ce80 --- /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 000000000..f7e97e459 --- /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 000000000..915efdf27 --- /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 000000000..c967068e9 --- /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 d7c3f8cd3..f4445cb50 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 UserFlag getFlag() { 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 String toString() { ", 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 603626ae1..bc2f69183 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 000000000..79467af1c --- /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 000000000..bc80bba38 --- /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 000000000..76ceb141c --- /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 000000000..e47dbac09 --- /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 68ac6ad48..b3667beeb 100644 --- a/pom.xml +++ b/pom.xml @@ -15,5 +15,7 @@ common web services + persist + test diff --git a/web/export/pom.xml b/web/export/pom.xml index e64c94500..3196e8a05 100644 --- a/web/export/pom.xml +++ b/web/export/pom.xml @@ -21,6 +21,11 @@ + + ${project.groupId} + persist + ${project.version} + com.j2html j2html 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 6b8e58734..b254d148e 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 27daf5f7c..078268b30 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; From af09e13d513bbddb970fa28bf5adcdd4a925d276 Mon Sep 17 00:00:00 2001 From: rolep Date: Tue, 18 Apr 2017 08:18:45 +0300 Subject: [PATCH 54/97] l5 patch files added --- patches/lesson05/5_1_HW4_export_chunk.patch | 249 +++++++++++++++ patches/lesson05/5_2_HW4_webapp_users.patch | 95 ++++++ .../lesson05/5_3_HW4_already_present.patch | 117 ++++++++ patches/lesson05/5_4_HW4_parallel.patch | 284 ++++++++++++++++++ patches/lesson05/5_5_typesafe_config.patch | 88 ++++++ patches/lesson05/5_6_lombook.patch | 268 +++++++++++++++++ patches/lesson05/5_7_fix.patch | 53 ++++ .../5_8_fix_share_ThymeleafListener.patch | 63 ++++ 8 files changed, 1217 insertions(+) create mode 100644 patches/lesson05/5_1_HW4_export_chunk.patch create mode 100644 patches/lesson05/5_2_HW4_webapp_users.patch create mode 100644 patches/lesson05/5_3_HW4_already_present.patch create mode 100644 patches/lesson05/5_4_HW4_parallel.patch create mode 100644 patches/lesson05/5_5_typesafe_config.patch create mode 100644 patches/lesson05/5_6_lombook.patch create mode 100644 patches/lesson05/5_7_fix.patch create mode 100644 patches/lesson05/5_8_fix_share_ThymeleafListener.patch 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 From 1c04811b0086711b8dabccf9379984bf12d23021 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 14:07:49 +0300 Subject: [PATCH 55/97] 5 1 HW4 export chunk --- parent-web/pom.xml | 41 +++++++++++++++++ .../masterjava/persist/dao/UserDao.java | 9 +++- .../masterjava/persist/dao/UserDaoTest.java | 7 +++ .../masterjava/export/UploadServlet.java | 44 ++++++++++++++----- .../javaops/masterjava/export/UserExport.java | 7 ++- .../main/webapp/WEB-INF/templates/export.html | 6 +++ 6 files changed, 100 insertions(+), 14 deletions(-) diff --git a/parent-web/pom.xml b/parent-web/pom.xml index 0c34224d3..7756bfb42 100644 --- a/parent-web/pom.xml +++ b/parent-web/pom.xml @@ -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} + + + + + + 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 index 915efdf27..284c162a1 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -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 @@ public User insert(User user) { 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 @@ public User insert(User user) { @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); + } 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 index e47dbac09..50e86da31 100644 --- a/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java @@ -36,4 +36,11 @@ public void getWithLimit() { 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 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 b254d148e..d6e16475c 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,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()); } } 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 078268b30..9c45da1a0 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,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 @@ public List process(final InputStream is) throws XMLStreamException { final User user = new User(fullName, email, flag); users.add(user); } + userDao.insertBatch(users, chunkSize); return users; } } diff --git a/web/export/src/main/webapp/WEB-INF/templates/export.html b/web/export/src/main/webapp/WEB-INF/templates/export.html index 1ed758208..704600594 100644 --- a/web/export/src/main/webapp/WEB-INF/templates/export.html +++ b/web/export/src/main/webapp/WEB-INF/templates/export.html @@ -1,11 +1,17 @@ + Export XML + +

Message

Select xml file to upload

+ + +


From 01b37b2c7209197bc84543794268864bb8a6f38a Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 14:09:42 +0300 Subject: [PATCH 56/97] 5 2 HW4 webapp users --- web/webapp/pom.xml | 6 +++- .../masterjava/webapp/UsersServlet.java | 28 +++++++++++++++++++ .../main/webapp/WEB-INF/templates/users.html | 27 ++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java create mode 100644 web/webapp/src/main/webapp/WEB-INF/templates/users.html diff --git a/web/webapp/pom.xml b/web/webapp/pom.xml index 0cf8c6098..de3a56fc2 100644 --- a/web/webapp/pom.xml +++ b/web/webapp/pom.xml @@ -16,10 +16,14 @@ war WebApp + + webapp + + ${project.groupId} - common + persist ${project.version} diff --git a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java new file mode 100644 index 000000000..d068401fe --- /dev/null +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java @@ -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()); + } +} diff --git a/web/webapp/src/main/webapp/WEB-INF/templates/users.html b/web/webapp/src/main/webapp/WEB-INF/templates/users.html new file mode 100644 index 000000000..3991c8d07 --- /dev/null +++ b/web/webapp/src/main/webapp/WEB-INF/templates/users.html @@ -0,0 +1,27 @@ + + + + Users + + + + + + + + + + + + + + + + + + + + +
Full NameEmailFlag
+ + \ No newline at end of file From b67a5c41d6cec997e4c2ebe846ea646d2ff48b84 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 14:10:17 +0300 Subject: [PATCH 57/97] 5 3 HW4 already present --- config_templates/sql/initDB.sql | 1 + .../javaops/masterjava/persist/dao/UserDao.java | 8 +++++--- .../javaops/masterjava/export/UploadServlet.java | 6 +++--- .../ru/javaops/masterjava/export/UserExport.java | 15 +++++++++++++-- .../src/main/webapp/WEB-INF/templates/result.html | 4 ++-- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/config_templates/sql/initDB.sql b/config_templates/sql/initDB.sql index 888ba8141..09b463d69 100644 --- a/config_templates/sql/initDB.sql +++ b/config_templates/sql/initDB.sql @@ -13,3 +13,4 @@ CREATE TABLE users ( flag user_flag NOT NULL ); +CREATE UNIQUE INDEX email_idx ON users (email); \ No newline at end of file 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 index 284c162a1..0e1325726 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -42,7 +42,9 @@ public User insert(User user) { @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); } 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 d6e16475c..dfe7a8096 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 @@ -44,11 +44,11 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S } 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/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java index 9c45da1a0..95b4d4352 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,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 @@ public class UserExport { 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 @@ public List process(final InputStream is, int chunkSize) throws XMLStreamE 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(); } } diff --git a/web/export/src/main/webapp/WEB-INF/templates/result.html b/web/export/src/main/webapp/WEB-INF/templates/result.html index ca4baa915..6af6acbfc 100644 --- a/web/export/src/main/webapp/WEB-INF/templates/result.html +++ b/web/export/src/main/webapp/WEB-INF/templates/result.html @@ -1,11 +1,11 @@ - Uploaded users + Already present users

Export XML

-

Uploaded users

+

Already present users

From fd13ca864f04e4dc4ac8961f1b3f9a694df35b9f Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 14:10:52 +0300 Subject: [PATCH 58/97] 5 4 HW4 parallel --- .../masterjava/persist/dao/UserDao.java | 23 +++- .../masterjava/persist/dao/UserDaoTest.java | 7 ++ .../masterjava/export/UploadServlet.java | 7 +- .../javaops/masterjava/export/UserExport.java | 108 ++++++++++++++---- .../main/webapp/WEB-INF/templates/result.html | 24 +--- 5 files changed, 124 insertions(+), 45 deletions(-) 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 index 0e1325726..aab183fd7 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -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 @@ public User insert(User user) { 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 User insert(User user) { 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(); + } } 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 index 50e86da31..1dd6ed408 100644 --- a/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserDaoTest.java @@ -43,4 +43,11 @@ public void insertBatch() throws Exception { 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 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 dfe7a8096..bcaa685ce 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 @@ -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 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S } 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; } 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 95b4d4352..353a7b902 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,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<>(); - - 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); + 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(id++, fullName, email, flag); + chunk.add(user); + if (chunk.size() == chunkSize) { + futures.add(submit(chunk)); + chunk.clear(); + id = userDao.getSeqAndSkip(chunkSize); + } + } + + 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; + } - int[] result = userDao.insertBatch(users, chunkSize); - return IntStreamEx.range(0, users.size()) - .filter(i -> result[i] == 0) - .mapToObj(users::get) - .toList(); + 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/web/export/src/main/webapp/WEB-INF/templates/result.html b/web/export/src/main/webapp/WEB-INF/templates/result.html index 6af6acbfc..db5a25e39 100644 --- a/web/export/src/main/webapp/WEB-INF/templates/result.html +++ b/web/export/src/main/webapp/WEB-INF/templates/result.html @@ -1,26 +1,14 @@ - Already present users + Failed users

Export XML

-

Already present users

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

Failed users

+
    + +
  • +
\ No newline at end of file From 765b895b306c68c377bb88e0e04b900832c2f515 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 20:13:28 +0300 Subject: [PATCH 59/97] 5 5 typesafe config --- .../ru/javaops/masterjava/config/Configs.java | 19 +++++++++++++++++++ parent/pom.xml | 6 ++++++ persist/src/main/resources/persist.conf | 7 +++++++ .../masterjava/persist/DBITestProvider.java | 6 +++++- 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 common/src/main/java/ru/javaops/masterjava/config/Configs.java create mode 100644 persist/src/main/resources/persist.conf 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..d11483da2 --- /dev/null +++ b/common/src/main/java/ru/javaops/masterjava/config/Configs.java @@ -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); + } +} diff --git a/parent/pom.xml b/parent/pom.xml index 90f1b8ec9..5b9dca064 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -86,6 +86,12 @@ streamex 0.6.2
+ + + com.typesafe + config + 1.3.1 + diff --git a/persist/src/main/resources/persist.conf b/persist/src/main/resources/persist.conf new file mode 100644 index 000000000..fe150292e --- /dev/null +++ b/persist/src/main/resources/persist.conf @@ -0,0 +1,7 @@ +db { + url = "jdbc:postgresql://localhost:5432/masterjava" + user = user + password = password +} + +include required(file("/apps/masterjava/config/persist.conf")) diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java b/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java index 79467af1c..b391650fc 100644 --- a/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java +++ b/persist/src/test/java/ru/javaops/masterjava/persist/DBITestProvider.java @@ -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) { From 6d32fdc922f036a4ada1f508eff7c27e8df5c621 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 20:13:57 +0300 Subject: [PATCH 60/97] 5 6 lombook --- parent/pom.xml | 7 ++ .../masterjava/persist/DBIProvider.java | 6 +- .../masterjava/persist/model/BaseEntity.java | 23 ++---- .../masterjava/persist/model/User.java | 82 +++---------------- .../masterjava/export/UploadServlet.java | 5 +- .../javaops/masterjava/export/UserExport.java | 12 +-- 6 files changed, 34 insertions(+), 101 deletions(-) diff --git a/parent/pom.xml b/parent/pom.xml index 5b9dca064..ba5e87b75 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -93,6 +93,13 @@ 1.3.1 + + org.projectlombok + lombok + 1.16.16 + provided + + org.slf4j diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java b/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java index 69904ce80..59579cbb6 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/DBIProvider.java @@ -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; 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 index c967068e9..bd0967990 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java @@ -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; } diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java index f4445cb50..927a299f3 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java @@ -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; - } - - 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 + - ')'; + this(fullName, email, flag); + this.id=id; } } \ No newline at end of file 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 bcaa685ce..9a8b98d2e 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,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(); 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 353a7b902..242b0a516 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,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; From 943889d71979978867fa570e52af78aa675fbdf0 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 20:14:17 +0300 Subject: [PATCH 61/97] 5 7 fix --- .../java/ru/javaops/masterjava/persist/dao/UserDao.java | 2 +- .../java/ru/javaops/masterjava/export/UserExport.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) 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 index aab183fd7..1047ebefa 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -61,7 +61,7 @@ public int getSeqAndSkip(int step) { 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) 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 242b0a516..0a2188bcd 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 @@ -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 @@ public List call() throws XMLStreamException { 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 @@ public List call() throws XMLStreamException { 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; From 3cf43630c12123cde18e3e95b9c94f8ebd8cf3b1 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Thu, 20 Apr 2017 20:14:33 +0300 Subject: [PATCH 62/97] 5 8 fix share ThymeleafListener --- .../ru/javaops/masterjava/common/web}/ThymeleafListener.java | 3 +-- .../java/ru/javaops/masterjava/export/UploadServlet.java | 2 +- .../main/java/ru/javaops/masterjava/webapp/UsersServlet.java | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) rename web/{export/src/main/java/ru/javaops/masterjava/export => common-web/src/main/java/ru/javaops/masterjava/common/web}/ThymeleafListener.java (84%) diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java b/web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafListener.java similarity index 84% rename from web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java rename to web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafListener.java index 8ec22e3c9..16948aa44 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/ThymeleafListener.java +++ b/web/common-web/src/main/java/ru/javaops/masterjava/common/web/ThymeleafListener.java @@ -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; 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 9a8b98d2e..c97470678 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 @@ -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/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java index d068401fe..5b587128f 100644 --- a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/UsersServlet.java @@ -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 @@ public class UsersServlet extends HttpServlet { 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()); } } From c25741d51d2a74991688822178b3206fab38d711 Mon Sep 17 00:00:00 2001 From: ROleP <> Date: Sun, 23 Apr 2017 18:54:44 +0300 Subject: [PATCH 63/97] lesson 6 patches added --- patches/lesson06/6_1_HW5_model_sql.patch | 290 ++++++++ patches/lesson06/6_2_HW5_dao_test.patch | 698 ++++++++++++++++++ .../6_3_HW5_add_PayloadImporter.patch | 134 ++++ .../lesson06/6_4_HW5_add_CityImporter.patch | 152 ++++ patches/lesson06/6_5_web_services.patch | 171 +++++ 5 files changed, 1445 insertions(+) create mode 100644 patches/lesson06/6_1_HW5_model_sql.patch create mode 100644 patches/lesson06/6_2_HW5_dao_test.patch create mode 100644 patches/lesson06/6_3_HW5_add_PayloadImporter.patch create mode 100644 patches/lesson06/6_4_HW5_add_CityImporter.patch create mode 100644 patches/lesson06/6_5_web_services.patch 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"; From ec58b89dd96ebde3243bfa1f9a851bd93d9334ea Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 28 Apr 2017 16:52:42 +0300 Subject: [PATCH 64/97] 6 1 HW5 model sql --- config_templates/sql/001_add_city.sql | 10 ++++++ config_templates/sql/002_add_projects.sql | 20 +++++++++++ config_templates/sql/databaseChangeLog.sql | 35 +++++++++++++++++++ config_templates/sql/lb_apply.bat | 8 +++++ .../masterjava/persist/dao/UserDao.java | 2 +- .../masterjava/persist/model/BaseEntity.java | 6 ++-- .../masterjava/persist/model/City.java | 21 +++++++++++ .../masterjava/persist/model/Group.java | 21 +++++++++++ .../masterjava/persist/model/GroupType.java | 7 ++++ .../masterjava/persist/model/Project.java | 19 ++++++++++ .../masterjava/persist/model/User.java | 3 +- .../masterjava/persist/model/UserGroup.java | 12 +++++++ 12 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 config_templates/sql/001_add_city.sql create mode 100644 config_templates/sql/002_add_projects.sql create mode 100644 config_templates/sql/databaseChangeLog.sql create mode 100644 config_templates/sql/lb_apply.bat create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/City.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java diff --git a/config_templates/sql/001_add_city.sql b/config_templates/sql/001_add_city.sql new file mode 100644 index 000000000..4ac3edee9 --- /dev/null +++ b/config_templates/sql/001_add_city.sql @@ -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 diff --git a/config_templates/sql/002_add_projects.sql b/config_templates/sql/002_add_projects.sql new file mode 100644 index 000000000..28f5db44e --- /dev/null +++ b/config_templates/sql/002_add_projects.sql @@ -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) +); diff --git a/config_templates/sql/databaseChangeLog.sql b/config_templates/sql/databaseChangeLog.sql new file mode 100644 index 000000000..6685c9ab5 --- /dev/null +++ b/config_templates/sql/databaseChangeLog.sql @@ -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) +); diff --git a/config_templates/sql/lb_apply.bat b/config_templates/sql/lb_apply.bat new file mode 100644 index 000000000..80f23598b --- /dev/null +++ b/config_templates/sql/lb_apply.bat @@ -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 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 index 1047ebefa..ef0733224 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -50,7 +50,7 @@ public int getSeqAndSkip(int step) { 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(); 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 index bd0967990..8a840ad6c 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/BaseEntity.java @@ -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 diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/City.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/City.java new file mode 100644 index 000000000..6c968930d --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/City.java @@ -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 diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java new file mode 100644 index 000000000..2482b1fa2 --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/Group.java @@ -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; + } +} diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java new file mode 100644 index 000000000..ab80bfc76 --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/GroupType.java @@ -0,0 +1,7 @@ +package ru.javaops.masterjava.persist.model; + +public enum GroupType { + REGISTERING, + CURRENT, + FINISHED; +} diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java new file mode 100644 index 000000000..e3bcb6dcc --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/Project.java @@ -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; + } +} diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java index 927a299f3..0a233652f 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java @@ -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; diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java new file mode 100644 index 000000000..d7eaee36b --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/UserGroup.java @@ -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 From e76ca2bc5163f53c34f10b430a2465e53643e2ea Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 28 Apr 2017 16:53:14 +0300 Subject: [PATCH 65/97] 6 2 HW5 dao test --- .../masterjava/persist/dao/CityDao.java | 38 +++++++++++++ .../masterjava/persist/dao/GroupDao.java | 37 +++++++++++++ .../masterjava/persist/dao/ProjectDao.java | 37 +++++++++++++ .../masterjava/persist/dao/UserDao.java | 6 +- .../masterjava/persist/dao/UserGroupDao.java | 38 +++++++++++++ .../masterjava/persist/model/User.java | 6 +- .../masterjava/persist/CityTestData.java | 32 +++++++++++ .../masterjava/persist/GroupTestData.java | 55 +++++++++++++++++++ .../masterjava/persist/ProjectTestData.java | 32 +++++++++++ .../masterjava/persist/UserGroupTestData.java | 45 +++++++++++++++ .../masterjava/persist/UserTestData.java | 15 +++-- .../persist/dao/AbstractDaoTest.java | 23 ++++++-- .../masterjava/persist/dao/CityDaoTest.java | 30 ++++++++++ .../masterjava/persist/dao/GroupDaoTest.java | 36 ++++++++++++ .../persist/dao/ProjectDaoTest.java | 30 ++++++++++ .../persist/dao/UserGroupDaoTest.java | 39 +++++++++++++ .../javaops/masterjava/export/UserExport.java | 2 +- 17 files changed, 485 insertions(+), 16 deletions(-) create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java create mode 100644 persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java create mode 100644 persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java new file mode 100644 index 000000000..71fe79128 --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/CityDao.java @@ -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); +} diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java new file mode 100644 index 000000000..7eb23fd59 --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java @@ -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); + } +} diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java new file mode 100644 index 000000000..e5b8a9b1f --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/ProjectDao.java @@ -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); + } +} 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 index ef0733224..d5fa6676a 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -39,11 +39,11 @@ public int getSeqAndSkip(int step) { 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 int getSeqAndSkip(int step) { 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); diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java new file mode 100644 index 000000000..2ca4a8ed7 --- /dev/null +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserGroupDao.java @@ -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 diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java index 0a233652f..3eb24a74c 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/model/User.java @@ -13,9 +13,11 @@ public class User extends BaseEntity { 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 diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java new file mode 100644 index 000000000..084b5cd1a --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/CityTestData.java @@ -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); + }); + } +} diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java new file mode 100644 index 000000000..01aba6bb9 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/GroupTestData.java @@ -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(); + } +} diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java new file mode 100644 index 000000000..b26b49178 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/ProjectTestData.java @@ -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(); + } +} diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java new file mode 100644 index 000000000..77f64ea59 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/UserGroupTestData.java @@ -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); + } +} diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java b/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java index bc80bba38..31c83da80 100644 --- a/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java +++ b/persist/src/test/java/ru/javaops/masterjava/persist/UserTestData.java @@ -7,6 +7,8 @@ import java.util.List; +import static ru.javaops.masterjava.persist.CityTestData.*; + /** * gkislin * 14.11.2016 @@ -21,12 +23,13 @@ public class UserTestData { 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); } 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 index 76ceb141c..3e8a891a5 100644 --- a/persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/AbstractDaoTest.java @@ -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) { diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java new file mode 100644 index 000000000..02d771475 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/CityDaoTest.java @@ -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 diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java new file mode 100644 index 000000000..467fad4b0 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/GroupDaoTest.java @@ -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 diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java new file mode 100644 index 000000000..1577859b0 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/ProjectDaoTest.java @@ -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 diff --git a/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.java new file mode 100644 index 000000000..a46f6dbd3 --- /dev/null +++ b/persist/src/test/java/ru/javaops/masterjava/persist/dao/UserGroupDaoTest.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.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 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 0a2188bcd..b561cdb59 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 @@ -70,7 +70,7 @@ public List call() throws XMLStreamException { 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)); From f9560a78bfff7b5d01ccbdc797a4e2ab62f0f1c1 Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 28 Apr 2017 16:53:40 +0300 Subject: [PATCH 66/97] 6 3 HW5 add PayloadImporter --- .../masterjava/export/PayloadImporter.java | 28 +++++++++++++++++++ .../masterjava/export/UploadServlet.java | 4 +-- .../{UserExport.java => UserImporter.java} | 19 ++----------- .../main/webapp/WEB-INF/templates/result.html | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java rename web/export/src/main/java/ru/javaops/masterjava/export/{UserExport.java => UserImporter.java} (88%) diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java new file mode 100644 index 000000000..88ba80731 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java @@ -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); + } +} 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 c97470678..9c0147f9b 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 @@ -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 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S } 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(), diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java similarity index 88% rename from web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java rename to web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java index b561cdb59..f5792d913 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/UserExport.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java @@ -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 @@ public List call() throws XMLStreamException { 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"); diff --git a/web/export/src/main/webapp/WEB-INF/templates/result.html b/web/export/src/main/webapp/WEB-INF/templates/result.html index db5a25e39..e8c63fbfa 100644 --- a/web/export/src/main/webapp/WEB-INF/templates/result.html +++ b/web/export/src/main/webapp/WEB-INF/templates/result.html @@ -7,7 +7,7 @@

Export XML

Failed users

    - +
From 1ed44854ec264dc6251d06fafd739b7c82d8f168 Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 28 Apr 2017 16:54:04 +0300 Subject: [PATCH 67/97] 6 4 HW5 add CityImporter --- .../masterjava/export/CityImporter.java | 38 +++++++++++++++++++ .../masterjava/export/PayloadImporter.java | 5 ++- .../masterjava/export/UserImporter.java | 28 +++++++++----- 3 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java new file mode 100644 index 000000000..f6b4e8be3 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/CityImporter.java @@ -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 diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java index 88ba80731..6e762a431 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java @@ -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 String toString() { 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); } } diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java index f5792d913..dcaf97ea0 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java @@ -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 @@ public class UserImporter { 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 @@ public List call() throws XMLStreamException { 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 @@ public List call() throws XMLStreamException { 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()); From 004d1d4ddbebecf82796ce044394b44e2eaa32f6 Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 28 Apr 2017 16:54:37 +0300 Subject: [PATCH 68/97] 6 5 web services --- .../masterjava/service/mail/Addressee.java | 17 +++++++++++++ .../masterjava/service/mail/MailService.java | 21 ++++++++++++++++ .../masterjava/service/mail/MailSender.java | 16 ++++++++++++ ...lService.java => MailServiceExecutor.java} | 2 +- .../service/mail/MailServiceImpl.java | 15 +++++++++++ .../service/mail/MailServiceClient.java | 25 +++++++++++++++++++ .../service/mail/MailServicePublisher.java | 14 +++++++++++ 7 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java rename services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/{MailService.java => MailServiceExecutor.java} (99%) create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java create mode 100644 services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java create mode 100644 services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java new file mode 100644 index 000000000..f30f68fc4 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -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; +} diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java new file mode 100644 index 000000000..2ebaf8d76 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java new file mode 100644 index 000000000..a6147371a --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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:"")); + } +} diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java similarity index 99% rename from services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java rename to services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java index 1d9a0026b..e26f302d2 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java @@ -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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java new file mode 100644 index 000000000..66cd43bea --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java new file mode 100644 index 000000000..4ef6f6d4f --- /dev/null +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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"); + } +} diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java new file mode 100644 index 000000000..88de00ae3 --- /dev/null +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java @@ -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()); + } +} From ed8b4f64b8cc7396ce9427935f5b95e32b8ce7b5 Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 2 May 2017 17:24:08 +0300 Subject: [PATCH 69/97] lesson 7 patches added --- patches/lesson07/7_10_send_group_bulk.patch | 238 +++++++++ patches/lesson07/7_1_HW6_MailSender.patch | 203 ++++++++ patches/lesson07/7_2_HW6_mail_history.patch | 396 +++++++++++++++ .../7_3_HW6_ProjectGroupImporter.patch | 141 ++++++ .../7_4_HW6_refactor_UserImporter.patch | 154 ++++++ patches/lesson07/7_5_customize_WSDL.patch | 74 +++ .../lesson07/7_6_publish_customizedWSDL.patch | 109 +++++ patches/lesson07/7_7_deploy_Tomcat.patch | 66 +++ patches/lesson07/7_8_create_client.patch | 189 ++++++++ patches/lesson07/7_9_refactoring.patch | 454 ++++++++++++++++++ 10 files changed, 2024 insertions(+) create mode 100644 patches/lesson07/7_10_send_group_bulk.patch create mode 100644 patches/lesson07/7_1_HW6_MailSender.patch create mode 100644 patches/lesson07/7_2_HW6_mail_history.patch create mode 100644 patches/lesson07/7_3_HW6_ProjectGroupImporter.patch create mode 100644 patches/lesson07/7_4_HW6_refactor_UserImporter.patch create mode 100644 patches/lesson07/7_5_customize_WSDL.patch create mode 100644 patches/lesson07/7_6_publish_customizedWSDL.patch create mode 100644 patches/lesson07/7_7_deploy_Tomcat.patch create mode 100644 patches/lesson07/7_8_create_client.patch create mode 100644 patches/lesson07/7_9_refactoring.patch 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 From 64c34b1a66e04eb4b1fd4a0597e4dd401e20fb88 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:31:41 +0300 Subject: [PATCH 70/97] 7 1 HW6 MailSender --- .../masterjava/service/mail/Addressee.java | 4 ++ services/mail-service/pom.xml | 16 +++++ .../masterjava/service/mail/MailConfig.java | 67 +++++++++++++++++++ .../masterjava/service/mail/MailSender.java | 21 ++++++ .../mail-service/src/main/resources/mail.conf | 12 ++++ .../service/mail/MailServiceClient.java | 3 +- 6 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java create mode 100644 services/mail-service/src/main/resources/mail.conf diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java index f30f68fc4..011df791e 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -14,4 +14,8 @@ public class Addressee { private String email; private String name; + + public Addressee(String email) { + this(email, null); + } } diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index 2b4be6bad..983a87918 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java new file mode 100644 index 000000000..4b00e0276 --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailConfig.java @@ -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 + '\''; + } +} diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index a6147371a..cbf27df42 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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); + } } } diff --git a/services/mail-service/src/main/resources/mail.conf b/services/mail-service/src/main/resources/mail.conf new file mode 100644 index 000000000..fdc6ca092 --- /dev/null +++ b/services/mail-service/src/main/resources/mail.conf @@ -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")) diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 4ef6f6d4f..54c5ffc46 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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"); } } From 57bed4b9815589b7f75b1c0e28eb75a27e4eda03 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:32:06 +0300 Subject: [PATCH 71/97] 7 2 HW6 mail history --- config_templates/sql/001_add_city.sql | 10 ---- config_templates/sql/002_add_projects.sql | 20 -------- config_templates/sql/databaseChangeLog.sql | 14 ++++++ persist/pom.xml | 19 ++++++++ .../masterjava/service/mail/Addressee.java | 14 +++++- services/mail-service/pom.xml | 12 +++++ .../masterjava/service/mail/MailSender.java | 10 +++- .../service/mail/persist/MailCase.java | 28 +++++++++++ .../service/mail/persist/MailCaseDao.java | 24 ++++++++++ .../service/mail/MailServiceClient.java | 9 +++- .../service/mail/MailServicePublisher.java | 3 ++ .../service/mail/persist/MailCaseDaoTest.java | 22 +++++++++ .../mail/persist/MailCaseTestData.java | 47 +++++++++++++++++++ 13 files changed, 199 insertions(+), 33 deletions(-) delete mode 100644 config_templates/sql/001_add_city.sql delete mode 100644 config_templates/sql/002_add_projects.sql create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java create mode 100644 services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java create mode 100644 services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java diff --git a/config_templates/sql/001_add_city.sql b/config_templates/sql/001_add_city.sql deleted file mode 100644 index 4ac3edee9..000000000 --- a/config_templates/sql/001_add_city.sql +++ /dev/null @@ -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 diff --git a/config_templates/sql/002_add_projects.sql b/config_templates/sql/002_add_projects.sql deleted file mode 100644 index 28f5db44e..000000000 --- a/config_templates/sql/002_add_projects.sql +++ /dev/null @@ -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) -); diff --git a/config_templates/sql/databaseChangeLog.sql b/config_templates/sql/databaseChangeLog.sql index 6685c9ab5..af0b27954 100644 --- a/config_templates/sql/databaseChangeLog.sql +++ b/config_templates/sql/databaseChangeLog.sql @@ -33,3 +33,17 @@ CREATE TABLE user_group ( 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 diff --git a/persist/pom.xml b/persist/pom.xml index 5816258ef..960abcf04 100644 --- a/persist/pom.xml +++ b/persist/pom.xml @@ -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/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java index 011df791e..2e11f5f94 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -16,6 +16,18 @@ public class Addressee { 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 + '>'; } } diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index 983a87918..45d7b23b9 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index cbf27df42..8013547b0 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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 @@ static void sendMail(List to, List cc, String subject, Str // 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); } } diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java new file mode 100644 index 000000000..9565458b3 --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java new file mode 100644 index 000000000..d2915c53c --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCaseDao.java @@ -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); +} diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 54c5ffc46..01528810a 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -19,6 +19,13 @@ public static void main(String[] args) throws MalformedURLException { 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"); } } diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java index 88de00ae3..2758f4aa5 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java @@ -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()); } } diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java new file mode 100644 index 000000000..2f6253501 --- /dev/null +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseDaoTest.java @@ -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 diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java new file mode 100644 index 000000000..6979e8a0e --- /dev/null +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java @@ -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); + }); + } +} From 8420583d0ee436a17a08fd91ea57d370582b2ee3 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:32:22 +0300 Subject: [PATCH 72/97] 7 3 HW6 ProjectGroupImporter --- .../masterjava/persist/dao/GroupDao.java | 9 ++-- .../masterjava/export/PayloadImporter.java | 4 +- .../export/ProjectGroupImporter.java | 53 +++++++++++++++++++ .../masterjava/export/UserImporter.java | 3 +- 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java diff --git a/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java b/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java index 7eb23fd59..9fc78e2c7 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/GroupDao.java @@ -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 @@ public void insert(Group groups) { 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); } diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java index 6e762a431..1879a6018 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/PayloadImporter.java @@ -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 String toString() { 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); } } diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java new file mode 100644 index 000000000..d9b2c9159 --- /dev/null +++ b/web/export/src/main/java/ru/javaops/masterjava/export/ProjectGroupImporter.java @@ -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(); + } +} diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java index dcaf97ea0..2f9a680e5 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java @@ -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 @@ public class UserImporter { 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>() { From 166bf0be103b3846dc716c86198566a70d1eceec Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:32:38 +0300 Subject: [PATCH 73/97] 7 4 HW6 refactor UserImporter --- .../masterjava/persist/dao/UserDao.java | 4 +- .../masterjava/export/UserImporter.java | 74 ++++++++++++------- 2 files changed, 50 insertions(+), 28 deletions(-) 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 index d5fa6676a..2f138983c 100644 --- a/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java +++ b/persist/src/main/java/ru/javaops/masterjava/persist/dao/UserDao.java @@ -61,11 +61,11 @@ public int getSeqAndSkip(int step) { 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(); } } diff --git a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java index 2f9a680e5..5ce55a638 100644 --- a/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java +++ b/web/export/src/main/java/ru/javaops/masterjava/export/UserImporter.java @@ -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 @@ public ChunkFuture(List chunk, Future> future) { @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 @@ public List call() throws XMLStreamException { 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 @@ public List call() throws XMLStreamException { 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; From 7be0894e2a6a1bf50411d96d553e165a8fe5cce3 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:32:53 +0300 Subject: [PATCH 74/97] 7 5 customize WSDL --- .../main/webapp/WEB-INF/wsdl/mailService.wsdl | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl diff --git a/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl b/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl new file mode 100644 index 000000000..09511ad15 --- /dev/null +++ b/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0af5fba4ddde3040a9f89b7e58993527deac1cd2 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:33:13 +0300 Subject: [PATCH 75/97] 7 6 publish customizedWSDL --- .../masterjava/service/mail/MailService.java | 10 +++++----- .../service/mail/MailServiceImpl.java | 8 +++----- .../service/mail/MailServiceClient.java | 6 +----- .../service/mail/MailServicePublisher.java | 18 +++++++++++++----- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index 2ebaf8d76..8b814c37c 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index 66cd43bea..d122011f3 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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); diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 01528810a..e641346e6 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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); diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java index 2758f4aa5..1901d0fc3 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java @@ -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"); } } From 94d79dd6c96ab1af84a6fe3ebb9ffda99f8d6086 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:33:26 +0300 Subject: [PATCH 76/97] 7 7 deploy Tomcat --- services/mail-service/pom.xml | 38 +++++++++++++++++++ .../src/main/webapp/WEB-INF/sun-jaxws.xml | 5 +++ 2 files changed, 43 insertions(+) create mode 100644 services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index 45d7b23b9..5ee50a195 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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/services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml b/services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml new file mode 100644 index 000000000..763d86504 --- /dev/null +++ b/services/mail-service/src/main/webapp/WEB-INF/sun-jaxws.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file From 740bf0ea0e0503622f9a19a014369e5121151395 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:33:40 +0300 Subject: [PATCH 77/97] 7 8 create client --- .../ru/javaops/masterjava/web/WsClient.java | 40 ++++++++++++ common/src/main/resources/hosts.conf | 4 ++ .../masterjava/service/mail/MailWSClient.java | 27 ++++++++ .../service/mail/MailWSClientMain.java | 11 ++++ .../src/test/resources/wsdl/mailService.wsdl | 65 +++++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 common/src/main/java/ru/javaops/masterjava/web/WsClient.java create mode 100644 common/src/main/resources/hosts.conf create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java create mode 100644 services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java create mode 100644 services/mail-api/src/test/resources/wsdl/mailService.wsdl diff --git a/common/src/main/java/ru/javaops/masterjava/web/WsClient.java b/common/src/main/java/ru/javaops/masterjava/web/WsClient.java new file mode 100644 index 000000000..13f027ff4 --- /dev/null +++ b/common/src/main/java/ru/javaops/masterjava/web/WsClient.java @@ -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; + } +} diff --git a/common/src/main/resources/hosts.conf b/common/src/main/resources/hosts.conf new file mode 100644 index 000000000..660c9c067 --- /dev/null +++ b/common/src/main/resources/hosts.conf @@ -0,0 +1,4 @@ +hosts { + mail = "http://localhost:8080" +} +include file("/apps/masterjava/config/hosts.conf") diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java new file mode 100644 index 000000000..beb38c983 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java new file mode 100644 index 000000000..bba10762c --- /dev/null +++ b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java @@ -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 diff --git a/services/mail-api/src/test/resources/wsdl/mailService.wsdl b/services/mail-api/src/test/resources/wsdl/mailService.wsdl new file mode 100644 index 000000000..09511ad15 --- /dev/null +++ b/services/mail-api/src/test/resources/wsdl/mailService.wsdl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From eee5b19ea4e5c04db9001578e477b9fab5f6b458 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:33:54 +0300 Subject: [PATCH 78/97] 7 9 refactoring --- .../masterjava/service/mail/Addressee.java | 13 +++ .../masterjava/service/mail/MailService.java | 6 +- .../masterjava/service/mail/MailWSClient.java | 4 +- .../service/mail/MailWSClientMain.java | 6 +- .../masterjava/service/mail/GroupResult.java | 19 ++++ .../masterjava/service/mail/MailResult.java | 20 ++++ .../masterjava/service/mail/MailSender.java | 15 ++- .../service/mail/MailServiceExecutor.java | 97 +++---------------- .../service/mail/MailServiceImpl.java | 6 +- .../service/mail/persist/MailCase.java | 4 +- .../service/mail/MailServiceClient.java | 10 +- .../mail/persist/MailCaseTestData.java | 5 +- 12 files changed, 95 insertions(+), 110 deletions(-) create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java create mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java index 2e11f5f94..446b28674 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -30,4 +30,17 @@ public Addressee(String email) { 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(); + } } diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index 8b814c37c..0b10580fb 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 @@ public interface MailService { @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 diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index beb38c983..8dbd294ff 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 class MailWSClient { } - 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); } diff --git a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java index bba10762c..e9852928a 100644 --- a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +++ b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java new file mode 100644 index 000000000..4f6ee6f8b --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java @@ -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); + } +} diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java new file mode 100644 index 000000000..7f5b3c7fa --- /dev/null +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java @@ -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 + ')'; + } +} diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index 8013547b0..4fb2fbb93 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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 @@ static void sendMail(List to, List cc, String subject, Str } MAIL_CASE_DAO.insert(MailCase.of(to, cc, subject, body, state)); log.info("Sent with state: " + state); + return state; } } diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java index e26f302d2..a51b303c7 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java @@ -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 @@ public class MailServiceExecutor { 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 @@ public GroupResult call() { 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 @@ private GroupResult cancelWithFail(String cause) { } }.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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index d122011f3..b0a104795 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java index 9565458b3..2286a3966 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/persist/MailCase.java @@ -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 @@ public class MailCase extends BaseEntity { 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/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index e641346e6..9b83a8a16 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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 @@ public static void main(String[] args) throws MalformedURLException { 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"); } } diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java index 6979e8a0e..3ba350895 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/persist/MailCaseTestData.java @@ -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 @@ public class MailCaseTestData { 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" From 3697760d09de99d62754aa9af75843062c18d358 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:34:08 +0300 Subject: [PATCH 79/97] 7 10 send group bulk --- .../masterjava/service/mail/Addressee.java | 4 ---- .../masterjava/service/mail/GroupResult.java | 21 ++++++++++++++++++ .../masterjava/service/mail/MailResult.java | 22 +++++++++++++++++++ .../masterjava/service/mail/MailService.java | 9 +++++++- .../masterjava/service/mail/MailWSClient.java | 2 +- .../masterjava/service/mail/GroupResult.java | 8 ++++--- .../masterjava/service/mail/MailSender.java | 6 ++--- .../service/mail/MailServiceExecutor.java | 6 ++--- .../service/mail/MailServiceImpl.java | 11 ++++++++-- .../service/mail/MailServiceClient.java | 4 ++-- 10 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java index 446b28674..864baab54 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -4,10 +4,6 @@ import lombok.Data; import lombok.NoArgsConstructor; -/** - * gkislin - * 15.11.2016 - */ @Data @AllArgsConstructor @NoArgsConstructor diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java new file mode 100644 index 000000000..179a202c0 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java @@ -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); + } +} diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java new file mode 100644 index 000000000..dc69d6cf3 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java @@ -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 + ')'; + } +} diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index 0b10580fb..0e5fb3df4 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 8dbd294ff..473f696c2 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -22,6 +22,6 @@ public class MailWSClient { 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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java index 4f6ee6f8b..179a202c0 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java @@ -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() { diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index 4fb2fbb93..13d0e565b 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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 { diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java index a51b303c7..db64ec60d 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java @@ -15,13 +15,13 @@ public class MailServiceExecutor { 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() { diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index b0a104795..264fdab1f 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 9b83a8a16..2ae59915c 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -16,11 +16,11 @@ public static void main(String[] args) throws MalformedURLException { 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"); } From 0d2411bdf5317f0f50e6a564b210acbaa9cd40e8 Mon Sep 17 00:00:00 2001 From: ROleP Date: Thu, 11 May 2017 17:39:17 +0300 Subject: [PATCH 80/97] lesson 8 patches added --- patches/lesson08/8_0_fix.patch | 118 +++ patches/lesson08/8_1_HW7_wsdl_share.patch | 153 ++++ patches/lesson08/8_2_app_conf.patch | 156 ++++ patches/lesson08/8_3_HW7_update_wsdl.patch | 175 +++++ patches/lesson08/8_4_HW7_webapp.patch | 225 ++++++ patches/lesson08/8_5_soap_exceptions.patch | 719 ++++++++++++++++++ .../lesson08/8_6_fix_wsdl_and_schema.patch | 92 +++ 7 files changed, 1638 insertions(+) create mode 100644 patches/lesson08/8_0_fix.patch create mode 100644 patches/lesson08/8_1_HW7_wsdl_share.patch create mode 100644 patches/lesson08/8_2_app_conf.patch create mode 100644 patches/lesson08/8_3_HW7_update_wsdl.patch create mode 100644 patches/lesson08/8_4_HW7_webapp.patch create mode 100644 patches/lesson08/8_5_soap_exceptions.patch create mode 100644 patches/lesson08/8_6_fix_wsdl_and_schema.patch 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; + From 2ed9d5a8ab001d5dd9fb054246f7e39e34904e7b Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:03:21 +0300 Subject: [PATCH 81/97] lesson 09 patches added --- patches/lesson09/9_0_mvn_plugins.patch | 110 +++++ patches/lesson09/9_1_HW8_service_attach.patch | 278 +++++++++++++ patches/lesson09/9_2_HW8_MTOM.patch | 106 +++++ patches/lesson09/9_3_HW8_webapp_attach.patch | 174 ++++++++ patches/lesson09/9_4_HW8_mail_attach.patch | 115 ++++++ patches/lesson09/9_5_msg_ctx_auth.patch | 142 +++++++ patches/lesson09/9_6_logging_handlers.patch | 377 ++++++++++++++++++ patches/lesson09/9_7_prepare_HW9.patch | 50 +++ 8 files changed, 1352 insertions(+) create mode 100644 patches/lesson09/9_0_mvn_plugins.patch create mode 100644 patches/lesson09/9_1_HW8_service_attach.patch create mode 100644 patches/lesson09/9_2_HW8_MTOM.patch create mode 100644 patches/lesson09/9_3_HW8_webapp_attach.patch create mode 100644 patches/lesson09/9_4_HW8_mail_attach.patch create mode 100644 patches/lesson09/9_5_msg_ctx_auth.patch create mode 100644 patches/lesson09/9_6_logging_handlers.patch create mode 100644 patches/lesson09/9_7_prepare_HW9.patch 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 ++ ++ } ++ ++} From 49b0b3f22820acd97b70d91dd7b04f7ebb095b18 Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:09:34 +0300 Subject: [PATCH 82/97] 8 0 fix --- .../masterjava/service/mail/GroupResult.java | 8 ++++--- .../masterjava/service/mail/MailResult.java | 8 +++++-- .../masterjava/service/mail/GroupResult.java | 21 ------------------- .../masterjava/service/mail/MailResult.java | 20 ------------------ 4 files changed, 11 insertions(+), 46 deletions(-) delete mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java delete mode 100644 services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java index 179a202c0..35da521e0 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java @@ -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 @@ public class GroupResult { @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/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java index dc69d6cf3..319784d6f 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java @@ -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 @@ public boolean isOk() { @Override public String toString() { - return '(' + email + ',' + result + ')'; + return '\'' + email + "' result '" + result + '\''; } } diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java deleted file mode 100644 index 179a202c0..000000000 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +++ /dev/null @@ -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); - } -} diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java deleted file mode 100644 index 7f5b3c7fa..000000000 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailResult.java +++ /dev/null @@ -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 + ')'; - } -} From c7d6a67095d7ec88642845dbd351be61d860b50b Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:09:46 +0300 Subject: [PATCH 83/97] 8 1 HW7 wsdl share --- .../wsdl/mailService.wsdl | 0 parent/pom.xml | 1 + services/mail-api/pom.xml | 11 ++++ services/mail-service/pom.xml | 23 +++++++ .../main/webapp/WEB-INF/wsdl/mailService.wsdl | 65 ------------------- 5 files changed, 35 insertions(+), 65 deletions(-) rename {services/mail-api/src/test/resources => config_templates}/wsdl/mailService.wsdl (100%) delete mode 100644 services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl diff --git a/services/mail-api/src/test/resources/wsdl/mailService.wsdl b/config_templates/wsdl/mailService.wsdl similarity index 100% rename from services/mail-api/src/test/resources/wsdl/mailService.wsdl rename to config_templates/wsdl/mailService.wsdl diff --git a/parent/pom.xml b/parent/pom.xml index ba5e87b75..46400fac3 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -18,6 +18,7 @@ 1.2.2 1.7.25 + /apps/masterjava/config/ false diff --git a/services/mail-api/pom.xml b/services/mail-api/pom.xml index 25c53388e..beec94956 100644 --- a/services/mail-api/pom.xml +++ b/services/mail-api/pom.xml @@ -15,6 +15,17 @@ 1.0-SNAPSHOT Mail API + + + + ${masterjava.config} + + wsdl/mailService.wsdl + + + + + ${project.groupId} diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index 5ee50a195..2546f41f2 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl b/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl deleted file mode 100644 index 09511ad15..000000000 --- a/services/mail-service/src/main/webapp/WEB-INF/wsdl/mailService.wsdl +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 9086e7ba6d72a4edbfe84666edb3f148d3c15481 Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:09:57 +0300 Subject: [PATCH 84/97] 8 2 app conf --- .../java/ru/javaops/masterjava/config/Configs.java | 14 ++++++++++---- config_templates/app.conf | 6 ++++++ config_templates/version.html | 11 +++++++++++ parent-web/pom.xml | 13 +++++++++++++ services/mail-service/pom.xml | 10 ++++++++++ .../service/mail/MailServicePublisher.java | 5 ++--- 6 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 config_templates/app.conf create mode 100644 config_templates/version.html diff --git a/common/src/main/java/ru/javaops/masterjava/config/Configs.java b/common/src/main/java/ru/javaops/masterjava/config/Configs.java index d11483da2..1c9b1ccd7 100644 --- a/common/src/main/java/ru/javaops/masterjava/config/Configs.java +++ b/common/src/main/java/ru/javaops/masterjava/config/Configs.java @@ -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) { 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/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/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/parent-web/pom.xml b/parent-web/pom.xml index 7756bfb42..17f1f347f 100644 --- a/parent-web/pom.xml +++ b/parent-web/pom.xml @@ -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 diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index 2546f41f2..ef39f45cb 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -26,6 +26,16 @@ false + + src/main/webapp + + + ${masterjava.config} + + version.html + + true + ${masterjava.config} diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java index 1901d0fc3..88a747cdd 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java @@ -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 @@ public static void main(String[] args) { 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"); From 60725dc760a95a35314c297923a8778ab4e7e0ed Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:10:09 +0300 Subject: [PATCH 85/97] 8 3 HW7 update wsdl --- config_templates/wsdl/mailService.wsdl | 79 ++++++++++++++++--- .../masterjava/service/mail/MailWSClient.java | 2 +- .../service/mail/MailWSClientMain.java | 2 +- .../service/mail/MailServiceClient.java | 13 +-- 4 files changed, 78 insertions(+), 18 deletions(-) diff --git a/config_templates/wsdl/mailService.wsdl b/config_templates/wsdl/mailService.wsdl index 09511ad15..7bf3c021a 100644 --- a/config_templates/wsdl/mailService.wsdl +++ b/config_templates/wsdl/mailService.wsdl @@ -8,10 +8,12 @@ name="MailServiceImplService"> - - + + + + - + @@ -19,6 +21,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -33,21 +68,43 @@ - - + + - - + + + + + + + + - - - + + + + + + + - + + + + + + + + + + diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 473f696c2..95596f780 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -20,7 +20,7 @@ public class MailWSClient { } - 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/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java index e9852928a..095fa8368 100644 --- a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +++ b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java @@ -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"); } diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 2ae59915c..e8495dd17 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -16,12 +16,15 @@ public static void main(String[] args) throws MalformedURLException { 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); } } From 57fc6fd6e2fa7b5fe95714d60a20cd1b85cc0099 Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:10:23 +0300 Subject: [PATCH 86/97] 8 4 HW7 webapp --- .../masterjava/service/mail/GroupResult.java | 5 ++ .../masterjava/service/mail/MailWSClient.java | 33 +++++++- web/webapp/pom.xml | 5 ++ .../masterjava/webapp/SendServlet.java | 27 +++++++ .../main/webapp/WEB-INF/templates/users.html | 78 ++++++++++++++----- 5 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java index 35da521e0..33f30fd30 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/GroupResult.java @@ -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 @@ public class GroupResult { 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/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 95596f780..de8dfc3d1 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 class MailWSClient { } - 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)); } } diff --git a/web/webapp/pom.xml b/web/webapp/pom.xml index de3a56fc2..e892e75e0 100644 --- a/web/webapp/pom.xml +++ b/web/webapp/pom.xml @@ -26,5 +26,10 @@ persist ${project.version}
+ + ${project.groupId} + mail-api + ${project.version} +
\ No newline at end of file diff --git a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java new file mode 100644 index 000000000..0f7c99fcd --- /dev/null +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java @@ -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()); + } +} diff --git a/web/webapp/src/main/webapp/WEB-INF/templates/users.html b/web/webapp/src/main/webapp/WEB-INF/templates/users.html index 3991c8d07..9b2f3b71a 100644 --- a/web/webapp/src/main/webapp/WEB-INF/templates/users.html +++ b/web/webapp/src/main/webapp/WEB-INF/templates/users.html @@ -3,25 +3,65 @@ Users + + + - - - - - - - - - - - - - - - - - - -
Full NameEmailFlag
+ + +

+ + + + + + + + + + + + + + + + + + + + +
#Full NameEmailFlag +
+
+

+ +

+

+
+

+

+ +

+
+
+ \ No newline at end of file From b34f295ce84e170717cb55590b012a6c089bbec5 Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:10:38 +0300 Subject: [PATCH 87/97] 8 5 soap exceptions --- .../ru/javaops/masterjava/ExceptionType.java | 34 ++++++++ config_templates/wsdl/common.xsd | 32 ++++++++ config_templates/wsdl/mailService.wsdl | 17 ++++ services/common-ws/pom.xml | 77 +++++++++++++++++++ .../main/java/ru/javaops/web/FaultInfo.java | 19 +++++ .../ru/javaops/web/WebStateException.java | 35 +++++++++ .../main/java/ru/javaops}/web/WsClient.java | 8 +- services/mail-api/pom.xml | 3 +- .../masterjava/service/mail/MailService.java | 6 +- .../masterjava/service/mail/MailWSClient.java | 15 ++-- .../service/mail/MailWSClientMain.java | 15 +++- services/mail-service/pom.xml | 45 +---------- .../masterjava/service/mail/MailSender.java | 13 +++- .../service/mail/MailServiceImpl.java | 6 +- .../service/mail/MailServiceClient.java | 13 +++- .../service/mail/MailServicePublisher.java | 3 +- services/pom.xml | 1 + .../masterjava/webapp/SendServlet.java | 11 ++- 18 files changed, 283 insertions(+), 70 deletions(-) create mode 100644 common/src/main/java/ru/javaops/masterjava/ExceptionType.java create mode 100644 config_templates/wsdl/common.xsd create mode 100644 services/common-ws/pom.xml create mode 100644 services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java create mode 100644 services/common-ws/src/main/java/ru/javaops/web/WebStateException.java rename {common/src/main/java/ru/javaops/masterjava => services/common-ws/src/main/java/ru/javaops}/web/WsClient.java (80%) 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..55e5512f6 --- /dev/null +++ b/common/src/main/java/ru/javaops/masterjava/ExceptionType.java @@ -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 + ')'; + } +} diff --git a/config_templates/wsdl/common.xsd b/config_templates/wsdl/common.xsd new file mode 100644 index 000000000..c0798056b --- /dev/null +++ b/config_templates/wsdl/common.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config_templates/wsdl/mailService.wsdl b/config_templates/wsdl/mailService.wsdl index 7bf3c021a..5577a648d 100644 --- a/config_templates/wsdl/mailService.wsdl +++ b/config_templates/wsdl/mailService.wsdl @@ -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 @@ + + + diff --git a/services/common-ws/pom.xml b/services/common-ws/pom.xml new file mode 100644 index 000000000..95ba18fda --- /dev/null +++ b/services/common-ws/pom.xml @@ -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 diff --git a/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java b/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java new file mode 100644 index 000000000..c2c644ecc --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java @@ -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(); + } +} diff --git a/services/common-ws/src/main/java/ru/javaops/web/WebStateException.java b/services/common-ws/src/main/java/ru/javaops/web/WebStateException.java new file mode 100644 index 000000000..8f1ffc4e0 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/WebStateException.java @@ -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(); + } +} diff --git a/common/src/main/java/ru/javaops/masterjava/web/WsClient.java b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java similarity index 80% rename from common/src/main/java/ru/javaops/masterjava/web/WsClient.java rename to services/common-ws/src/main/java/ru/javaops/web/WsClient.java index 13f027ff4..3e43c0ce2 100644 --- a/common/src/main/java/ru/javaops/masterjava/web/WsClient.java +++ b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java @@ -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 @@ public T getPort() { 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); + } } diff --git a/services/mail-api/pom.xml b/services/mail-api/pom.xml index beec94956..3ff36485e 100644 --- a/services/mail-api/pom.xml +++ b/services/mail-api/pom.xml @@ -21,6 +21,7 @@ ${masterjava.config} wsdl/mailService.wsdl + wsdl/common.xsd @@ -29,7 +30,7 @@ ${project.groupId} - common + common-ws ${project.version} diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index 0e5fb3df4..f7e9cb3ae 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 @@ String sendToGroup( @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 diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index de8dfc3d1..e418d2d57 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 class MailWSClient { } - 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 @@ public static String sendToGroup(final Set to, final Set c 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; diff --git a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java index 095fa8368..3e440fab6 100644 --- a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +++ b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java @@ -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 diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index ef39f45cb..d1bae735f 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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 @@ -83,43 +80,5 @@ 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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index 13d0e565b..ce130ddbb 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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 @@ static String sendToGroup(Set to, Set cc, String subject, 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; } diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index 264fdab1f..136fdbec5 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index e8495dd17..53d90c63a 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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 @@ public static void main(String[] args) throws MalformedURLException { 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); + } } } diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java index 88a747cdd..1d77f0f27 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServicePublisher.java @@ -16,7 +16,8 @@ public static void main(String[] args) { 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"); diff --git a/services/pom.xml b/services/pom.xml index bb7824194..5aea18c6b 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -9,6 +9,7 @@ MasterJava Services + common-ws mail-api mail-service diff --git a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java index 0f7c99fcd..27effc56b 100644 --- a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java @@ -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 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S 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); } } From a4681843192119c43eba146d1bbc811d7e45c3a5 Mon Sep 17 00:00:00 2001 From: ROleP Date: Mon, 15 May 2017 18:10:49 +0300 Subject: [PATCH 88/97] 8 6 fix wsdl and schema --- .../java/ru/javaops/masterjava/ExceptionType.java | 3 +++ config_templates/wsdl/common.xsd | 6 ++++-- .../src/main/java/ru/javaops/web/FaultInfo.java | 3 +++ .../javaops/masterjava/service/mail/Addressee.java | 12 ++++++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/ru/javaops/masterjava/ExceptionType.java b/common/src/main/java/ru/javaops/masterjava/ExceptionType.java index 55e5512f6..8489c2f24 100644 --- a/common/src/main/java/ru/javaops/masterjava/ExceptionType.java +++ b/common/src/main/java/ru/javaops/masterjava/ExceptionType.java @@ -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("Ошибка базы данных"), diff --git a/config_templates/wsdl/common.xsd b/config_templates/wsdl/common.xsd index c0798056b..5c47776cd 100644 --- a/config_templates/wsdl/common.xsd +++ b/config_templates/wsdl/common.xsd @@ -1,12 +1,14 @@ + - + - + diff --git a/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java b/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java index c2c644ecc..d3525c5b9 100644 --- a/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java +++ b/services/common-ws/src/main/java/ru/javaops/web/FaultInfo.java @@ -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/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java index 864baab54..babe171b5 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Addressee.java @@ -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) { From 0d95b244b800dfd154a4c5eaee41ad57c877e517 Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 16 May 2017 17:25:59 +0300 Subject: [PATCH 89/97] 9 0 mvn plugins --- persist/pom.xml | 24 +++++++++++ services/mail-service/pom.xml | 43 ++++++++----------- .../sql => sql}/databaseChangeLog.sql | 0 {config_templates/sql => sql}/initDB.sql | 0 {config_templates/sql => sql}/lb_apply.bat | 0 5 files changed, 42 insertions(+), 25 deletions(-) rename {config_templates/sql => sql}/databaseChangeLog.sql (100%) rename {config_templates/sql => sql}/initDB.sql (100%) rename {config_templates/sql => sql}/lb_apply.bat (100%) diff --git a/persist/pom.xml b/persist/pom.xml index 960abcf04..369d3f832 100644 --- a/persist/pom.xml +++ b/persist/pom.xml @@ -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 + + + + diff --git a/services/mail-service/pom.xml b/services/mail-service/pom.xml index d1bae735f..7ad11cdae 100644 --- a/services/mail-service/pom.xml +++ b/services/mail-service/pom.xml @@ -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 + + + + + + + + + + + diff --git a/config_templates/sql/databaseChangeLog.sql b/sql/databaseChangeLog.sql similarity index 100% rename from config_templates/sql/databaseChangeLog.sql rename to sql/databaseChangeLog.sql diff --git a/config_templates/sql/initDB.sql b/sql/initDB.sql similarity index 100% rename from config_templates/sql/initDB.sql rename to sql/initDB.sql diff --git a/config_templates/sql/lb_apply.bat b/sql/lb_apply.bat similarity index 100% rename from config_templates/sql/lb_apply.bat rename to sql/lb_apply.bat From 8b408ea924d4dd926bf662a0456165548c0d1e5b Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 16 May 2017 17:26:15 +0300 Subject: [PATCH 90/97] 9 1 HW8 service attach --- config_templates/wsdl/mailService.wsdl | 10 +++++++++ .../masterjava/service/mail/Attach.java | 22 +++++++++++++++++++ .../masterjava/service/mail/MailService.java | 7 ++++-- .../masterjava/service/mail/MailWSClient.java | 9 ++++---- .../service/mail/MailWSClientMain.java | 13 +++++++---- .../service/mail/MailServiceImpl.java | 5 +++-- .../service/mail/MailServiceClient.java | 15 ++++++++----- .../masterjava/webapp/SendServlet.java | 2 +- 8 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java diff --git a/config_templates/wsdl/mailService.wsdl b/config_templates/wsdl/mailService.wsdl index 5577a648d..391bffc24 100644 --- a/config_templates/wsdl/mailService.wsdl +++ b/config_templates/wsdl/mailService.wsdl @@ -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 @@ + + + + + + + diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java new file mode 100644 index 000000000..c9e7cd377 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/Attach.java @@ -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; +} diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java index f7e9cb3ae..6e51b1926 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailService.java @@ -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 @@ String sendToGroup( @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 diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index e418d2d57..5b0637733 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 class MailWSClient { } - 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 @@ public static String sendToGroup(final Set to, final Set c 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); diff --git a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java index 3e440fab6..6ec2b76d7 100644 --- a/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java +++ b/services/mail-api/src/test/java/ru/javaops/masterjava/service/mail/MailWSClientMain.java @@ -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); diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index 136fdbec5..1bbd1562a 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java index 53d90c63a..722112b14 100644 --- a/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java +++ b/services/mail-service/src/test/java/ru/javaops/masterjava/service/mail/MailServiceClient.java @@ -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 @@ public static void main(String[] args) throws MalformedURLException { 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); diff --git a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java index 27effc56b..d68ab75eb 100644 --- a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java @@ -23,7 +23,7 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S 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(); } From fe68e4e44a5491c388e1d688dbf1b2278eb5ce88 Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 16 May 2017 17:26:30 +0300 Subject: [PATCH 91/97] 9 2 HW8 MTOM --- services/common-ws/pom.xml | 6 ++++++ .../common-ws/src/main/java/ru/javaops/web/WsClient.java | 5 +++-- .../ru/javaops/masterjava/service/mail/MailWSClient.java | 9 +++++++-- .../javaops/masterjava/service/mail/MailServiceImpl.java | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/services/common-ws/pom.xml b/services/common-ws/pom.xml index 95ba18fda..9a38ba13a 100644 --- a/services/common-ws/pom.xml +++ b/services/common-ws/pom.xml @@ -50,6 +50,12 @@ + + org.jvnet.mimepull + mimepull + 1.9.4 + + javax.activation activation diff --git a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java index 3e43c0ce2..b42b51e71 100644 --- a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java +++ b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java @@ -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 @@ public void init(String host, String endpointAddress) { } // 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); diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 5b0637733..029fa539b 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 @@ public static String sendToGroup(final Set to, final Set c 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 @@ public static GroupResult sendBulk(final Set to, final String subject 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 @@ public static GroupResult sendBulk(final Set to, final String subject 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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index 1bbd1562a..5602393f3 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 From a3ac7f0db30dccc46a115bd1a1bab44602480798 Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 16 May 2017 17:26:47 +0300 Subject: [PATCH 92/97] 9 3 HW8 webapp attach --- .../service/mail/util/Attachments.java | 47 +++++++++++++++++++ .../masterjava/webapp/SendServlet.java | 17 ++++++- .../main/webapp/WEB-INF/templates/users.html | 43 ++++++++--------- 3 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java new file mode 100644 index 000000000..43ab81c68 --- /dev/null +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java @@ -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 ""; + } + } +} diff --git a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java index d68ab75eb..772c262c5 100644 --- a/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java +++ b/web/webapp/src/main/java/ru/javaops/masterjava/webapp/SendServlet.java @@ -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/web/webapp/src/main/webapp/WEB-INF/templates/users.html b/web/webapp/src/main/webapp/WEB-INF/templates/users.html index 9b2f3b71a..5da8d9e0f 100644 --- a/web/webapp/src/main/webapp/WEB-INF/templates/users.html +++ b/web/webapp/src/main/webapp/WEB-INF/templates/users.html @@ -31,36 +31,37 @@ - +
-

- -

-

-
-

-

- -

-
+
+ + + +

+ +

+

+
+

+

+ +

+

+ +

+
From d3a8d07558ef9fc9b1516aa01665a914c3fd0f62 Mon Sep 17 00:00:00 2001 From: ROleP Date: Tue, 16 May 2017 17:27:06 +0300 Subject: [PATCH 93/97] 9 4 HW8 mail attach --- .../masterjava/service/mail/MailSender.java | 27 ++++++++++++------- .../service/mail/MailServiceExecutor.java | 4 +-- .../service/mail/MailServiceImpl.java | 4 +-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java index ce130ddbb..9cfbb6c7d 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailSender.java @@ -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 @@ static String sendToGroup(Set to, Set cc, String subject, 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 @@ static String sendToGroup(Set to, Set cc, String subject, 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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java index db64ec60d..9b31f9ec3 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceExecutor.java @@ -17,11 +17,11 @@ public class MailServiceExecutor { 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() { diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index 5602393f3..b8b7b498d 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -15,11 +15,11 @@ public class MailServiceImpl implements MailService { @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 From 08863601cbc17ec1396594539aafd9431e9e2a11 Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 26 May 2017 15:40:39 +0300 Subject: [PATCH 94/97] 9 5 msg ctx auth --- .../main/java/ru/javaops/web/AuthUtil.java | 32 +++++++++++++++++++ .../main/java/ru/javaops/web/WsClient.java | 6 ++++ .../masterjava/service/mail/MailWSClient.java | 9 +++++- .../service/mail/MailServiceImpl.java | 19 +++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java diff --git a/services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java b/services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java new file mode 100644 index 000000000..bdf9bbf6f --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/AuthUtil.java @@ -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; + } + } +} diff --git a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java index b42b51e71..fe533216e 100644 --- a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java +++ b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java @@ -40,6 +40,12 @@ public T getPort(WebServiceFeature... features) { 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); diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 029fa539b..0a056d9d1 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 @@ public static GroupResult sendBulk(final Set to, final String subject } 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/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index b8b7b498d..de8b54752 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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); } From 81e8444ad7944aa179722ac41379ad88af0eec5e Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 26 May 2017 15:40:59 +0300 Subject: [PATCH 95/97] 9 6 logging handlers --- .../main/java/ru/javaops/web/WsClient.java | 10 ++ .../javaops/web/handler/SoapBaseHandler.java | 23 ++++ .../web/handler/SoapClientLoggingHandler.java | 15 +++ .../web/handler/SoapLoggingHandler.java | 120 ++++++++++++++++++ .../web/handler/SoapServerLoggingHandler.java | 16 +++ services/mail-api/pom.xml | 5 + .../masterjava/service/mail/MailWSClient.java | 4 + .../service/mail/util/Attachments.java | 12 +- .../service/mail/MailServiceImpl.java | 2 + .../src/main/resources/mailWsHandlers.xml | 8 ++ 10 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java create mode 100644 services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java create mode 100644 services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java create mode 100644 services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java create mode 100644 services/mail-service/src/main/resources/mailWsHandlers.xml diff --git a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java index fe533216e..f2db3a9f7 100644 --- a/services/common-ws/src/main/java/ru/javaops/web/WsClient.java +++ b/services/common-ws/src/main/java/ru/javaops/web/WsClient.java @@ -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 @@ public static void setAuth(T port, String user, String password) { 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); diff --git a/services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java new file mode 100644 index 000000000..ad2b18779 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapBaseHandler.java @@ -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); + } +} diff --git a/services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java new file mode 100644 index 000000000..fe352a5b1 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapClientLoggingHandler.java @@ -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 diff --git a/services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java new file mode 100644 index 000000000..b01f8dac6 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapLoggingHandler.java @@ -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; + } +} diff --git a/services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java new file mode 100644 index 000000000..03438b254 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/handler/SoapServerLoggingHandler.java @@ -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 diff --git a/services/mail-api/pom.xml b/services/mail-api/pom.xml index 3ff36485e..cd8452acb 100644 --- a/services/mail-api/pom.xml +++ b/services/mail-api/pom.xml @@ -33,6 +33,11 @@ common-ws ${project.version} + + commons-io + commons-io + 2.5 + \ No newline at end of file diff --git a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java index 0a056d9d1..63d8dc310 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/MailWSClient.java @@ -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 @@ public class MailWSClient { 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 @@ public static GroupResult sendBulk(final Set to, final String subject 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/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java index 43ab81c68..b3fd3f46d 100644 --- a/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java +++ b/services/mail-api/src/main/java/ru/javaops/masterjava/service/mail/util/Attachments.java @@ -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 @@ public static Attach getAttach(String name, InputStream inputStream) { 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 diff --git a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java index de8b54752..252b4f31d 100644 --- a/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java +++ b/services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailServiceImpl.java @@ -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 diff --git a/services/mail-service/src/main/resources/mailWsHandlers.xml b/services/mail-service/src/main/resources/mailWsHandlers.xml new file mode 100644 index 000000000..6415e80be --- /dev/null +++ b/services/mail-service/src/main/resources/mailWsHandlers.xml @@ -0,0 +1,8 @@ + + + + SoapLoggingHandler + ru.javaops.web.handler.SoapServerLoggingHandler + + + \ No newline at end of file From 7bca93898814f0d4281d18420bf9a98bd138a54d Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 26 May 2017 15:41:14 +0300 Subject: [PATCH 96/97] 9 7 prepare HW9 --- common/src/main/resources/hosts.conf | 8 ++++++- .../main/java/ru/javaops/web/Statistics.java | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 services/common-ws/src/main/java/ru/javaops/web/Statistics.java diff --git a/common/src/main/resources/hosts.conf b/common/src/main/resources/hosts.conf index 660c9c067..6b0157bfe 100644 --- a/common/src/main/resources/hosts.conf +++ b/common/src/main/resources/hosts.conf @@ -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") diff --git a/services/common-ws/src/main/java/ru/javaops/web/Statistics.java b/services/common-ws/src/main/java/ru/javaops/web/Statistics.java new file mode 100644 index 000000000..e42fa1790 --- /dev/null +++ b/services/common-ws/src/main/java/ru/javaops/web/Statistics.java @@ -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 + + } + +} From 6363132228e4bb7d8d112935cccf6e25966f3950 Mon Sep 17 00:00:00 2001 From: ROleP Date: Fri, 26 May 2017 15:43:44 +0300 Subject: [PATCH 97/97] lesson 10 patches added --- patches/lesson10/10_1_HW9_handlers.patch | 345 ++++++++++++++++++++ patches/lesson10/10_2_HW9_host_config.patch | 255 +++++++++++++++ patches/lesson10/10_3_JAX_RS.patch | 128 ++++++++ patches/lesson10/10_4_jersey_logging.patch | 128 ++++++++ patches/lesson10/10_5_JMS.patch | 257 +++++++++++++++ 5 files changed, 1113 insertions(+) create mode 100644 patches/lesson10/10_1_HW9_handlers.patch create mode 100644 patches/lesson10/10_2_HW9_host_config.patch create mode 100644 patches/lesson10/10_3_JAX_RS.patch create mode 100644 patches/lesson10/10_4_jersey_logging.patch create mode 100644 patches/lesson10/10_5_JMS.patch 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 @@ +
+ +