From 555e6c91e6fec1b76c008d390e4f6c9d50c15609 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Tue, 21 Feb 2017 17:32:43 +0300 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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 cbee99f61c34685ada708c5820f81bd5581621fc Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 15 Mar 2017 22:55:22 +0200 Subject: [PATCH 06/19] Prepare to Matrix implementation --- desktop.ini | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 desktop.ini diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 000000000..fa2217ec1 --- /dev/null +++ b/desktop.ini @@ -0,0 +1,6 @@ +[.ShellClassInfo] +IconResource=C:\Windows\system32\SHELL32.dll,137 +[ViewState] +Mode= +Vid= +FolderType=Generic From 3c78d437beff19639cb150ca8ac9c8dfbb2cc07a Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 15 Mar 2017 23:08:24 +0200 Subject: [PATCH 07/19] 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 31288defb7109abdd17d583c78074be29fdf60fc Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 15 Mar 2017 23:12:21 +0200 Subject: [PATCH 08/19] Prepare to Matrix implementation --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ad02a2599..c7757bd0e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ out target *.iml -log \ No newline at end of file +log +*.patch From 0afbc329452c9e704940f7310e7e6499ef9d2279 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Thu, 16 Mar 2017 08:14:41 +0200 Subject: [PATCH 09/19] 2 01 HW1 singleThreadMultiplyOpt --- .../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 5d6b74c355f3bfd735e0fa9626fad4914693539c Mon Sep 17 00:00:00 2001 From: kotecoder Date: Thu, 16 Mar 2017 08:32:12 +0200 Subject: [PATCH 10/19] 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 9a5bc24430c84e2d77a4208ab9ba86daec00e667 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Thu, 16 Mar 2017 08:54:19 +0200 Subject: [PATCH 11/19] 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 a7910584a9b6b2a88269370768d8e221f0ff15be Mon Sep 17 00:00:00 2001 From: kotecoder Date: Thu, 16 Mar 2017 12:40:32 +0200 Subject: [PATCH 12/19] 2 04 JMH Benchmark patch --- pom.xml | 11 ++++ .../masterjava/matrix/MatrixBenchmark.java | 62 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java diff --git a/pom.xml b/pom.xml index 39e811e08..a3cb2d7b2 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,17 @@ + + org.openjdk.jmh + jmh-core + RELEASE + + + org.openjdk.jmh + jmh-generator-annprocess + RELEASE + provided + 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 716956c976ec6b4bf833673d056b76699ba6eda8 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Fri, 17 Mar 2017 14:14:23 +0200 Subject: [PATCH 13/19] 2 05 JMH main jar --- pom.xml | 35 +++++++++++++++++++ .../masterjava/matrix/MatrixBenchmark.java | 23 +++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index a3cb2d7b2..2dbccb332 100644 --- a/pom.xml +++ b/pom.xml @@ -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 + + + + + + + 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 d2075ca7fe2d8f8549a82cbcbac6214f4523a40f Mon Sep 17 00:00:00 2001 From: kotecoder Date: Fri, 24 Mar 2017 17:12:05 +0200 Subject: [PATCH 14/19] 2 05_1 refactoring --- README.md | 164 ------------------------------------------------------ 1 file changed, 164 deletions(-) diff --git a/README.md b/README.md index de162e88f..e12793ea9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ -# Многомодульный maven. Многопоточность. XML. Веб сервисы. Удаленное взаимодействие -## Регистрация -## [Программа проекта](#Программа-проекта) - ### _Разработка полнофункционального многомодульного Maven проекта_ - веб приложение (Tomcat, Thymleaf, jQuery) - модуль экспорта из XML (JAXB, StAX) @@ -10,163 +6,3 @@ - сохранение данных в 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(..)` - -### ![](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 ... - ----------------------------- - -### Ресурсы (основы) -- Intuit, Потоки выполнения. Синхронизация -- Алексей Владыкин, Основы многопоточность в Java -- Виталий Чибриков, Java. Многопоточность -- Computer Science Center, курс Параллельное программирование -- Юрий Ткач, курс Advanced Java - Concurrency -- Головач, курс Java Multithreading - ---- -## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Задание первого занятия - -Вычекать этот проект: -```git clone https://github.com/JavaOPs/masterjava.git``` - -- Применить оптимизацию к MatrixUtil.singleThreadMultiply -- Реализовать метод `MatrixUtil.concurrentMultiply`, позволяющий многопоточно перемножать квадратные матрицы N*N. -- Количество дочерних потоков ограничено `MainMatrix.THREAD_NUMBER`. -- Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной - ------ -## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по HW1 -- не делайте 1000 000 тасок, лучше их сделать крупнее -- у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно -- наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply3`). Мои результаты: -``` -Benchmark (matrixSize) Mode Cnt Score Error Units -MatrixBenchmark.singleThreadMultiplyOpt 1000 ss 100 837,867 ± 25,530 ms/op -MatrixBenchmark.concurrentMultiply2 1000 ss 100 394,294 ± 21,657 ms/op -MatrixBenchmark.concurrentMultiply3 1000 ss 100 186,827 ± 11,882 ms/op -``` ------ -# Программа проекта - -## Занятие 2 -- Разбор ДЗ (многопоточная реализация умножения матриц) -- Java Microbenchmark JMH (от Алексея Шипилева) -- Обзор Guava -- Формат XML. Создание схемы XSD. -- Работа с XML в Java - - JAXB, JAXP - - StAX - - XPath - - XSLT - -## Занятие 3 -- Разбор ДЗ (работа с XML) -- Обзор StreamEx (от Тагира Валеева) -- Монады. flatMap -- SOA и Микросервисы -- Многомодульный Maven проект - -## Занятие 4 -- Разбор ДЗ (реализация структуры проекта, загрузка и разбор xml) -- Thymleaf -- Maven. Поиск и разрешение конфликтов зависимостей -- Логирование -- Выбор lightweight JDBC helper library. JDBI -- Tomcat Class Loader. Memory Leaks - -## Занятие 5 -- Разбор ДЗ (реализуем модули persist, export и web) -- Конфигурирование приложения (Typesafe config) -- Lombook - -## Занятие 6 -- Разбор ДЗ (доработка модели и модуля export) -- Миграция DB -- Веб-сервисы (REST/SOAP) - - Java реализации SOAP - - Имплементируем Mail Service - -## Занятие 7 -- Разбор ДЗ (реализация MailSender, сохранение результатов отправки) -- Стили WSDL. Кастомизация WSDL -- Публикация кастомизированного WSDL. Автогенерация. -- Деплой в Tomcat -- Создание клиента почтового сервиса - -## Занятие 8 -- Разбор ДЗ (отправка почты через Executor из модуля web) -- Доступ к переменным maven в приложении -- SOAP Exception. Выделение общей части схемы -- Передача двоичных данных в веб-сервисах. MTOM - -## Занятие 9 -- Разбор ДЗ (реализация загрузки и отправки вложений по почте) -- JAX-WS Message Context -- JAX-WS Handlers (логирование SOAP) - -## Занятие 10 -- Разбор ДЗ (реализация авторизации и статистики) -- JavaEE - - CDI - - JAX-RS. Интеграция с Jersey - - EJB - - JMS - -## Занятие 11 (предварительно) -- Асинхронные сервлеты 3.x в Tomcat -- Maven Groovy cкрптинг (groovy-maven-plugin) -- AKKA -- Redis From 182830fbce6bbf1c44732b269fb802af43352156 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 5 Apr 2017 20:03:02 +0300 Subject: [PATCH 15/19] 2 06 xml scheme --- .../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 ++++++++++++ src/test/resources/payload.xml | 23 ++ src/test/resources/payload.xsd | 56 +++++ 7 files changed, 696 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 create mode 100644 src/test/resources/payload.xml create mode 100644 src/test/resources/payload.xsd 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..b3430ce71 --- /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="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; + } + +} diff --git a/src/test/resources/payload.xml b/src/test/resources/payload.xml new file mode 100644 index 000000000..796e99cb3 --- /dev/null +++ b/src/test/resources/payload.xml @@ -0,0 +1,23 @@ + + + + gmail@gmail.com + Full Name + + + admin@javaops.ru + Admin + + + mail@yandex.ru + Deleted + + + + Санкт-Петербург + Киев + Минск + + \ No newline at end of file diff --git a/src/test/resources/payload.xsd b/src/test/resources/payload.xsd new file mode 100644 index 000000000..9ef1e46eb --- /dev/null +++ b/src/test/resources/payload.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From d1bfbc3c0f14f2a95cadedcbdd084c434b16e158 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 5 Apr 2017 22:13:24 +0300 Subject: [PATCH 16/19] 2 07 JAXB --- pom.xml | 19 ++++ .../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 +++++++++++ src/{test => main}/resources/payload.xsd | 0 .../masterjava/xml/util/JaxbParserTest.java | 44 +++++++++ src/test/resources/city.xml | 4 + 8 files changed, 287 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 rename src/{test => main}/resources/payload.xsd (100%) create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java create mode 100644 src/test/resources/city.xml diff --git a/pom.xml b/pom.xml index 2dbccb332..c02f4e349 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,14 @@ ${java.version} + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + -Dfile.encoding=UTF-8 + + org.apache.maven.plugins maven-shade-plugin @@ -80,6 +88,17 @@ RELEASE provided + + com.google.guava + guava + 21.0 + + + junit + junit + 4.12 + test + 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/resources/payload.xsd b/src/main/resources/payload.xsd similarity index 100% rename from src/test/resources/payload.xsd rename to src/main/resources/payload.xsd 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 2d4ec837408f11205ff5e52597a6ab3fb195a640 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 5 Apr 2017 22:34:52 +0300 Subject: [PATCH 17/19] 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 0a6df1a8f9589bb21f710e5ecc6a05c8432c52f1 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Wed, 5 Apr 2017 22:48:41 +0300 Subject: [PATCH 18/19] 2 08 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 d187fa85f3493ae36dddbe0355bb8d132c2384e9 Mon Sep 17 00:00:00 2001 From: kotecoder Date: Thu, 6 Apr 2017 19:39:56 +0300 Subject: [PATCH 19/19] 2 08 Xslt --- .../masterjava/xml/util/XsltProcessor.java | 45 +++++++++++++++++++ src/main/resources/cities.xsl | 9 ++++ .../xml/util/XsltProcessorTest.java | 19 ++++++++ 3 files changed, 73 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..7b56f8ffc --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java @@ -0,0 +1,45 @@ +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; + + + +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..089b6d2f7 --- /dev/null +++ b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java @@ -0,0 +1,19 @@ +package ru.javaops.masterjava.xml.util; + +import com.google.common.io.Resources; +import org.junit.Test; + +import java.io.InputStream; + + +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)); + } + } +}