diff --git a/doc/lesson01.md b/doc/lesson01.md new file mode 100644 index 0000000..d0b28d9 --- /dev/null +++ b/doc/lesson01.md @@ -0,0 +1,94 @@ +# Первое занятие: многопоточность. + +- **Не стоит стремится прочитать все ссылки урока, их можно использовать как справочник. Гораздо важнее пройти основной материал урока и сделать Домашнее Задание** +- **Обязательно посмотри правила работы с патчами на проекте** +- **Делать Apply Patch лучше по одному, непосредственно перед видео на эту тему, а при просмотре видео сразу отслеживать все изменения кода проекта по изменению в патче (`Version Control->Local Changes-> Ctrl+D`)** +- **Код проекта обновляется и не всегда совпадает с видео (можно увидеть как развивался проект). Изменения в проекте указываю после соответствующего патча.** + +## ![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 область памяти + > Замечание: [с JDK 7 String Pool переехал в Heap](https://topjava.ru/blog/rukovodstvo-po-string-pool-v-java) + - [Стек и куча в Java](https://topjava.ru/blog/stack-and-heap-in-java) + - Размер Java объектов + - Оптимизация памяти + - [Escape analysis и скаляризация: Пусть GC отдохнет](https://habr.com/company/jugru/blog/322348) + - [Условия для размещения объекта в стеке](https://stackoverflow.com/a/43002529/548473) + +### Ленивая инициализация +- Реализация 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? +- [The Deadlock Empire](https://deadlockempire.github.io/) +- [Реактивное программирование - как, зачем и стоит ли?](https://habr.com/ru/company/oleg-bunin/blog/543386/) + +#### 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(..)` + +Вычекать этот проект: +```git clone https://github.com/JavaOPs/masterjava.git``` + +> - [Настройка git на свой репозиторий](https://github.com/JavaOPs/basejava/blob/master/lesson/lesson1.md#настройка-проекта) +> - [Правила работы с патчами на проекте](https://github.com/JavaOPs/topjava/wiki/Git) + +#### Все изменения в проекте будут делаться на основе патчей: скачайте [1_1_MailService.patch](https://drive.google.com/open?id=0B9Ye2auQ_NsFTE5ZV3pzWElxTWM), положите его в проект, правой мышкой на нем сделайте Apply Patch ... + +---------------------------- +- [Как сделать Java код проще и нагляднее](https://habrahabr.ru/company/wrike/blog/349652/) + +### Ресурсы (основы) +- Intuit, Потоки выполнения. Синхронизация +- Алексей Владыкин, Основы многопоточность в Java +- Виталий Чибриков, Java. Многопоточность +- Computer Science Center, курс Параллельное программирование +- Юрий Ткач, курс Advanced Java - Concurrency +- Головач, курс Java Multithreading +- [Перевод «Java Memory Model»](https://habr.com/ru/post/510454/) + +--- +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Задание первого занятия + +- Применить оптимизацию к 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 +``` diff --git a/doc/lesson02.md b/doc/lesson02.md new file mode 100644 index 0000000..8b920f1 --- /dev/null +++ b/doc/lesson02.md @@ -0,0 +1,108 @@ +# Онлайн проекта Masterjava. +- **Не стоит стремится прочитать все ссылки урока, их можно впоследствии использовать как справочник. Гораздо важнее сделать Домашнее Задание** +- **Обязательно посмотри правила работы с патчами на проекте (совпадают с проектом Topjava)** +- **Делать Apply Patch лучше по одному, непосредственно перед видео на эту тему, а при просмотре видео сразу отслеживать все изменения кода проекта по изменению в патче** +- **Код проекта обновляется и не всегда совпадает с видео (можно увидеть как развивался проект). Изменения в проекте указываю после соответствующего патча.** +- 42 IntelliJ IDEA Tips and Tricks + +### В коде проекта используется JDK 8. Если у вас выше, необходимо будет включить в проект [дополнительные зависимости, исключенные в JDK 9](https://stackoverflow.com/questions/48204141/548473) + +## Материалы занятия (скачать все патчи можно через Download папки patch) +![image](https://cloud.githubusercontent.com/assets/13649199/18330295/5f2ca214-7560-11e6-8e1e-c0494f798c37.png) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1.1 Вступление. Разбор домашнего задания HW1 +#### 2_1_HW1_singleThreadMultiplyOpt.patch +#### 2_2_HW1_concurrentMultiply.patch +- Сравнение EE и Spring в комментариях +- Java array thread-safety + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1.2 [Еще одна реализация умножения, parallel() и ForkJoinPool](https://drive.google.com/file/d/0B9Ye2auQ_NsFT0FYaUdaenVMT1k) +#### 2_3_HW1_concurrentMultiply2.patch +> `Callable / executor.invokeAll` в `concurrentMultiply2` поменял на `Runnable / CountDownLatch` + +- [Fork/Join Framework в Java 7](https://habrahabr.ru/post/128985/) +- [Java Parallel Streams Are Bad for Your Health](https://zeroturnaround.com/rebellabs/java-parallel-streams-are-bad-for-your-health/) +- [Custom thread pool in Java 8 parallel stream](https://stackoverflow.com/a/21172732/548473) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Java Microbenchmark JMH (от Алексея Шипилева) +#### 2_4_JMH_Benchmark.patch +#### 2_5_JMH_main_jar.patch + +> Сделал forks=10 для большой точности измерений и убрал лишние измерения + +- JMH - Java Microbenchmark Harness, Java Performance Tuning Guide (если не работает, попробуйте перейти на Introduction to JMH [отсюда](https://d1k2jhzcfaebet.cloudfront.net/#post-750)) +- idea-jmh-plugin, Exception while trying to acquire a JMH lock +- Maven latest dependency version + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Формат XML. Создание схемы XSD. +#### 2_6_xml_scheme.patch +- [Что такое XML](https://habr.com/ru/articles/524288/) +- Attribute vs Element. +- sequence/ choice/ all/ group. Define referring to Another XML Element +- Лекции по XML + +## Работа с XML в Java + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. JAXB, JAXP +Для генерации Java схемы из xsd проверьте плагин **Jakarta EE: Web Services (JAX-WS)**. Схема генериться через главное меню: _Tools -> XML Actions -> Generate Java code from XML Schema Using JAXB..._. Возможно пакет уже будет новый `jakarta`, поправте на `javax`. +#### 2_7_JAXB.patch +> - Добавил в `maven-surefire-plugin` UTF-8 +> - Убрал лишний `synchronized` в `JaxbParser.marshal()` (уже есть в `JaxbMarshaller.marshal()`) +> - Сделал загрузку ресурсов используя context class loader +> - Different ways of loading a file as an InputStream + +- Работа с XML в Java. +- DOM, SAX +- JAXP: вспомогательный слой над SAX и DOM API +- JAXB, JAXP, Xerces, Xalan +- Валидации XML + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. StAX +#### 2_8_StAX.patch +- [Java XML API: выбираем правильно. StAX: работаем с удовольствием](https://habrahabr.ru/post/339716/) +- StAX: XMLStreamReader, XMLEventReader + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. XPath +> Поправка к видео на 2:29 - лет 10-15 назад был популярен подход рисовать квадратиками в специальном приложении логику [связываения через сообщения разных сервисов](https://www.mulesoft.com/resources/esb/what-esb). Сервисы подключались к [ESB](https://ru.wikipedia.org/wiki/ESB) по разным протоколам. Один из них был [JBI](https://hrwiki.ru/wiki/Java_Business_Integration). Все это было достаточно красиво для продаж, но очень неуклюже для разработки. Cейчас уже редко где можно встретить, хотя Spring Integration, Apache Camel и пр. для определенных приложений-процессов используют. + +#### 2_9_XPath.patch +- XPath: Java XPath API +- Примеры XPath + +В IDEA в контекстном меню на элемент XML есть пункт (2-й снизу) `Evaluate XPath...` +На имена города он выдает `/Payload/Cities/City/text()` +Чтобы это выражение работало в нашем `XPathProcessorTest` нужно отключить `NamespaceAware`: +``` +public class XPathProcessor +... +25 DOCUMENT_FACTORY.setNamespaceAware(false); +``` +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. XSLT +#### 2_10_Xslt.patch +- Преобразование XSLT, Default XSLT output +- XSLT, XSL + - XSL Transformations (XSLT) +- Дополнительно + - [What kind of language is XSLT?](https://web.archive.org/web/20201109035750/http://www.ibm.com/developerworks/xml/library/x-xslt/) + - [Saxon: Anatomy of an XSLT processor](https://web.archive.org/web/20200916195642/http://www.ibm.com/developerworks/library/x-xslt2/) + +## Домашнее задание +- 1: Изменить XML схему: + - 1.1 добавить проекты. Имеют название (например `topjava, masterjava`) и описание + - 1.2 добавить группы. Они имеют название и тип (`REGISTERING/CURRENT/FINISHED`) и принадлежат проекту. Например проект `topjava`, группы `topjava01`,`topjava02`, .. + - 1.3 сделать `User.email` аттрибутом. + - 1.4 реализовать принадлежность участников разным группам (`Admin` состоит в группах `topjava07, topjava08, masterjava01`) +- 2: Дополнить xml тестовыми данными. +- 3: Реализовать класс `MainXml`, которые принимает параметром имя проекта в тестовом xml и выводит отсортированный список его участников (использовать JAXB). + +#### Optional +- 4: Сделать реализацию `MainXml` через StAX (выводить имя/email) +- 5: Из списка участников сделать html таблицу (имя/email). Реализация- любая. +- 6: Вывести через XSLT преобразование html таблицу с группами заданного проекта + - [XSLT param](http://stackoverflow.com/questions/1667454/xsl-transformation-in-java-with-parameters) + +## Замечания: +- 1: Не используйте IDREF, где можно сделать обычную вложенность, принятую в структурах XML +- 2: Попробуйте сделать минимальное количестово XML текста на одного юзера (пользователей много, экономим) +- 3: Используйте StaxStreamProcessor! Добавляйте туда и используйте утильные методы. +- 4: Постарайтесь оптимизировать реализацию определения "находится ли пользователь в проекте". Не делать сложность (N пользователей * M групп)! diff --git a/doc/lesson03.md b/doc/lesson03.md new file mode 100644 index 0000000..6a656db --- /dev/null +++ b/doc/lesson03.md @@ -0,0 +1,141 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFSGFQZ2I0V2pmbXM) (скачать все патчи можно через Download папки patch) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW2 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Scheme, j2html, JAXB +#### Apply 3_1_HW2_schema.patch +- xs:ID restriction + +#### Apply 3_2_HW2_JAXB.patch +> - убрал второй параметр xmlName (всегда `payload.xml`) +> - в `parseByJaxb` сделал закрытие `InputStream` сразу после обработки +> - сделал методы статическими +> - вместо вложенного стрима для групп юзера сделал пересечение коллекций `Collections.disjoint` +> - результат JAXB также вывожу в HTML (в ДЗ только в Optional) +> - в `j2html` вместо `setAttribute` сделал `attr` + +- Тагир Валеев. StreamEx + странности Stream API +- StreamEx примеры +- Java HTML5 builder + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Optional: StAX +#### Apply 3_3_HW2_StAX.patch +> - зарефакторил в `StaxStreamProcessor` `doUntil()` и `getAttribute()` +> - константы вставил в код +> - вместо вложенного цикла для групп юзера сделал пересечение коллекций `Collections.disjoint` и для маскирования пустых групп `Strings.nullToEmpty` + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. StAX refactoring: startElement + JAXB +#### Apply 3_4_StAX_refactoring.patch +- [Java XML API: выбираем правильно. StAX: работаем с удовольствием](https://habrahabr.ru/post/339716/) +- [StAX + JAXB](http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html) + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Optional: XSLT +#### Apply 3_5_HW2_xslt.patch +> В `groups.xsl` добавил явный namespace. Теперь при создании xPath IDEA делает автодополнения + +- XSL Transformation in Java with parameters +- Test Cases for XSLT support in browsers + +## Занятие 3 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Обзор Guava](https://drive.google.com/open?id=0B9Ye2auQ_NsFeFB5a29JQ2tRNHM) +- [The Top 20 Most Popular Java Libraries](https://dzone.com/articles/the-top-100-java-libraries-in-2016-after-analyzing) +- [Guava Wiki](https://github.com/google/guava/wiki) + - [Apache Commons](https://commons.apache.org/) + - [Spring Boot cache providers](http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html#_supported_cache_providers) +- [Release 21.0: Java 8!](https://github.com/google/guava/wiki/Release21) +- [118 слайдов от Егора Чернышева](https://www.slideshare.net/echernyshev/guava-41982734) + + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. Монады. flatMap +- Функторы, аппликативные функторы и монады в картинках +- Монады в Java 8 + - Курс Сoursera по функциональному программированию +- Three Monad laws. +- What's Wrong in Java 8 Monads + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. SOA и Микросервисы + - Сервис-ориентированная архитектура как повышение абстракции производства ПО + - What is service-oriented architecture? + - Современное представление (SOA): Микросервисы + - [Микросервисная архитектура в разрезе](https://proglib.io/p/po-stopam-luchshih-mikroservisnaya-arhitektura-v-razreze-2019-11-07) + - Микросервисы (Microservices) + - Доклад Кирилла Толкачёва и Александра Тарасова про микросервисы + - Минск: Микросервисы - Огонь, Вода и Медные трубы + - Слайды + - CQRS + - Event Sourcing, + - CQRS + Event Sourcing, + - Event-Sourcing+CQRS example application + - Интеграция через несколько ДБ. + - Гибридные решения для эффективного хранения данных. + - PgBouncer + - Microservices with Spring, Микросервисная архитектура, Spring Cloud и Docker + - Microservices demo + - Spring Cloud Netflix + - Netflix + - Service Discovery: Eureka + - Circuit Breaker: Hystrix + - Load Balancer: Ribbon + - Declarative REST Client: Feign + - External Configuration: Archaius + - Gateway, Router and Filter: Zuul + - Metrics: Spectator, Servo, and Atlas + - RxJava with Spring MVC + - ReactiveX + - RxJava: Reactive Extensions for the JVM + - Справичник + - microservice in spring.io + - Building microservices with Spring Boot – part 1 + - Building microservices with Spring Boot – part 2 + - Deploying Spring Boot-based microservices with Docker – part 3 + - Developing Microservices With Spring Boot + - Webinar: Building "Bootiful" Microservices with Spring Boot + - Managing your Microservices on Heroku with Netflix's Eureka + - Платформы + - A comparison of Microservices Frameworks + - Lagom, Play Framework + - Микросервисе в обзоре Zeroturnaround + - Spring 5: Functional Web Framework + - Apache Camel for Micro­service Architectures + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. Многомодульный Maven проект +#### Apply 3_6_multimodule.patch +- Snapshot. The Reactor. +- Maven module inheritance vs aggregation +- Расширение кругозора: + - Антон Архипов, Евгений Борисов, Барух Садогурский — Maven vs Gradle vs SBT + - [Maven CI Friendly Versions: параметризация версии проекта](https://maven.apache.org/maven-ci-friendly.html) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW3 +- Сделать структуру проекта согласно схеме. В модулях c `packaging=pom` кода нет, корневое `src` перенести в другие модули. + - `Matrix + Benchmark` перенести в модуль `test`. + - Схемы XML/XSD в модуль `upload` + +**Внимание: название модуля `export` в видео и картинке идеологически неверно. В коде и патчах переименовал в `upload`.** + +WAR модули: +- **`mail-service`** - модуль отсылки почты. Транспорт: JAX-WS, JAX-RS, JMX, AKKA +- **`upload`** - модуль загрузки payload.xml. Заргузка и многопоточночная вставка в DB +- **`webapp`** - веб-интерфейс для отсылки почты пользователям из DB. Клиент модуля `mail-service` + +![image](https://cloud.githubusercontent.com/assets/13649199/23876457/ab01ff0a-084e-11e7-964f-49c90579fac9.png) + +- Учитывая, что web модулей в проекте предполагается много, измените структуру, чтобы не дублировать `maven-war-plugin` (и другие общие зависимости war модулей). +- Проверьте, что проект собирается! + +#### Optional +- Реализовать простую форму заргузки файла `payload.xml` в модуле `upload` (через StAX) и отобразить загруженных пользователей (имя/email/flag) + - для отображения взять любой шаблон (JSP, [Thymeleaf](http://www.concretepage.com/thymeleaf/java-thymeleaf-example-getting-started-with-thymeleaf), ...) + - загрузку сделать через любую реализацию (Servlet 3.х предпочтительнее): + - Commons FileUpload + - Tomcat fileupload copied and package renamed + - Java EE 6 Tutorial: fileupload example + - Servlet 3.0's FileUpload Sample +- Сделать загрузку через StAX+JAXB многопоточно. Сейчас `JaxbParser` реализован с `synchronize`, что означает что он потокобезопасен (может работать с несколькими запросами), но последовательно, в одном потоке. Нужен рефакторинг. + - [Thread safe of JAXBContext, Marshaller, Unmarshalleris](https://stackoverflow.com/a/37926057/548473) + +## Замечания: +- 1: имя артифакта `artifactId` как и пакеты называть только в lowercase. Обычно используют "-" как разделитель слов. Имя каталога модуля лучше делать тоже самое: [Project Directories Should Match the Artifact ID](http://blog.sonatype.com/2011/01/maven-tip-project-directories-and-artifact-ids/) +- 2: следите, чтобы пути в шаблонах были не от рута "/". Каждое приложение деплоится в свой Application Context. +- 3: чтобы не дублировать `maven-war-plugin` сделать `paren-web`. Он наследуется от `parent`, а от него наследуются все war модули. diff --git a/doc/lesson04.md b/doc/lesson04.md new file mode 100644 index 0000000..99a0b0b --- /dev/null +++ b/doc/lesson04.md @@ -0,0 +1,149 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия (скачать все патчи можно через Download папки patch)](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFVDNRNHpGU2NmcEk) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW3 + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Структура многомодульного проекта +#### 4_1_HW3_pom_structure.patch +> Вместо включения всех модулей в главный аггрегатор, сделал еще 2 аггрегатных модуля 2го уровня: `web` и `services` + +**ВНИМАНИЕ! после патча** + - проверьте правильность структуры проекта + - сделайте `mvn clean install` + - удалите пустые корневые каталоги `src` и `upload` (git не работает с каталогами) + - переименуйте модули idea (`Shift+F6`), если отличаются от имени модуля Maven + +![structure](https://user-images.githubusercontent.com/11200258/32416643-928c4e34-c25d-11e7-832d-0f72dc1f8760.png) + +#### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Вопрос: как разбивать приложение на модули](https://drive.google.com/open?id=0B9Ye2auQ_NsFTm5FX1ZZeTFpYU0) +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Реализация модуля `upload`: Thymeleaf и Upload +**ВНИМАНИЕ! перед накаткой патча создайте в папке `web` проекта каталог `\common-web\src`, иначе патч промахивается.** +#### 4_2_HW3_thymeleaf_upload.patch +- Thymeleaf: natural templates + - Thymeleaf 3 migration guide + - th:include и th:replace + - Tutorial + - URL Syntax + - Java Thymeleaf Example +- [Thread-safe TemplateEngine.process](http://stackoverflow.com/a/23007118/548473) + +#### 4_3_HW3_upload_servlet3.patch +> - Добавил проверку на отсутствие выбранного файла + +- [File upload using Servlet 3.0 API](http://www.ewebtutorials.com/file-upload-using-servlet-3-0-api-in-java.html) + +> Вопрос: если в загружаем большой файл, то он придет частями? В этом случае используем `req.getParts()` и у каждой части можно получить InputStream. А как все части файла собрать вместе и получить итоговый InputStream, который уже можно передать StAX-процессору? + +`Part` это одно поле формы и на части уже не бъется. В `@MultipartConfig` можно через аттрибуты задать лимит `fileSizeThreshold`, когда входящий поток будет сохраняться в файле. Все происходит внизу Multipart API, `InputStream` из мы получаем также: `filePart.getInputStream()` + +#### 4_4_HW3_jaxb_stax.patch +- [JAXB creating context and marshallers cost](https://stackoverflow.com/a/7400735/548473) +- [Именование private static референсных изменяемых объектов](https://google.github.io/styleguide/javaguide.html#s5.2.4-constant-names) + +---------------- +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Maven. Поиск и разрешение конфликтов зависимостей](https://drive.google.com/file/d/0B9Ye2auQ_NsFbFFpWWFzRWE3ekU) +- Пример для сборки `upload + mail-service + зависимости` из **корня проекта**: +``` + mvn -pl services\mail-service,web\upload -am install +``` +- Maven transitive dependencies +- Project Info Reports Plugin +- Disable blacklisted repository warnings +``` +mvn dependency:tree +mvn project-info-reports:dependencies +``` +#### 4_5_dependencies.patch + +- Разрешение конфликтов в транзитивных зависимостях +- Dependency hell +``` +mvn project-info-reports:dependency-convergence +``` +#### 4_6_fix_convergence.patch +#### 4_7_enforcer.patch +- Maven Enforcer Plugin +``` +mvn clean install +mvn -DincludeScope=runtime dependency:copy-dependencies +``` +- jar-hell.zip +``` +java -jar jar-hell.jar . +``` +- jHades, [Downloads WAR Duplicate Classes](http://jhades.github.io/downloads.html) +``` +java -jar jhades-standalone-report.jar path/to/war/webapp.war +``` +``` +mvn dependency:analyze +``` +- Analyze used and declared; used and undeclared; unused and declared + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Подключаем логирование с общими настройкам +#### 4_8_logging.patch +> - Перенес подключение `logback-test.xml` из `parent-web` в `parent` (он используется в JUnit тестах, которые могут быть в любом модуле) +> - Добавил в корень проекта `config_templates` с копией конфигурации. +Общие файлы конфигурации заданы в maven parent как в `/apps/masterjava/config/`. +**Нужно у себя в корне диска создать этот каталог и положить в него содержимое `config_templates`** + +UPDATE: c Maven 3.3.1 [в переменной `${maven.multiModuleProjectDirectory}` храниться рутовый каталог многомодульного проекта](https://stackoverflow.com/a/49528226/548473). Те мы можем создавать `config` и хранить его прямо в нашем репозитории (вместо `config_templates`) с путем +``` +${maven.multiModuleProjectDirectory}/config/ +``` +Если в корне проекта сделать каталог `.mvn`, то эта переменная работает при сборке из зависимых модулей. + +- Добавление зависимостей логирования +- logback.xml Example +- Справочник: + - Topjava: логирование. + - Владимир Красильщик: Что надо знать о логировании прагматичному Java‑программисту + - Java Logging: история кошмара + - Ведение лога приложения + - Log4j, Logback + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5.Библиотеки и фреймворки для работы с JDBC. + +### Выбор lightweight JDBC helper library +- Lightweight JDBC helper library +- Библиотеки для работа с JDBC +- MyBatis, MyBatis tutorial (CRUD) +- Commons DbUtils, доработка commons-dbutils +- jDBI sample + - JDBI + - JDBI tutorial (Dropwizard JDBI) + - [Combining Spring Boot and JDBI](https://www.sitepoint.com/combining-spring-boot-and-jdbi) + +### Tomcat Class Loader. Memory Leeks +#### 4_9_context.patch +> Cохранил конфигурацию Tomcat `context.xml`, в котором конфигурируется `jdbc/masterjava`. **Ее надо будет положить в ${TOMCAT_HOME}/conf** + +- Class Loader HOW-TO +- Библиотеки vs Frameworks и Tomcat Common Lib. Memory Leaks. +- Никита Сальников-Тарновский — Утечки памяти + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. Модуль `persist` +**ВНИМАНИЕ! перед накаткой патча создайте в корне проекта каталоги `persist\src\main` и `persist\src\test`, иначе патч промахивается.** +#### 4_10_persist.patch +- Postgresql enum advantages/disadvantages +- ALTER Enum types since 9.1 +- Simple EntityMapper with `@Column` support + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW4 +- в модуле **upload** сохранить всех импортированных пользователей в базе (записи просто добавляются в таблицу `users`). Делать вставку группами (chunk) в [batch моде](http://jdbi.org/jdbi2/sql_object_api_batching/). Количестово пользователей в chunk принимать с UI как параметр +- сделать отображение первых 20 пользователей в модуле **webapp** +- добавить в таблицу `users` уникальный индекс на `email` и вставлять в базу только новых пользователей. Результат импорта: пользователи, уже присутствующие в базе ([POSTGRES: INSERT ON CONFLICT](https://habrahabr.ru/post/264281/)) + +### Optional +- сделать сохранение пользователей чанками в несколько потоков (по мере чтения xml). Результат импорта: email пользователей, уже присутствующие в базе и диапазоны (начальный-конечный email) в чанке, +если обработка чанка закончилась с ошибкой (`InterruptedException / ExecutionException`) + причина отказа для пользователя/диапазона. + +- дополнительный материал: + - [Speed up insertion performance in PostgreSQL](http://stackoverflow.com/a/12207237/548473) + - [COPY — копировать данные между файлом и таблицей](https://postgrespro.ru/docs/postgrespro/9.6/sql-copy) + +## Замечания: +- 1: при вставке вам помогут JDBI аннотации `@BindBean` и `@BatchChunkSize` +- 2: чтобы при Batch вставке не нагружать базу вызовами `nextval` можно id генерить самостоятельно (используя `ALTER SEQUENCE`). +- 3: без `@GetGeneratedKeys` результат `int[]` в insertBatch возвращается с тем же размером, что и `List`. Значение 0 в возвращаемом массиве означает, что запись не вставилась. diff --git a/doc/lesson05.md b/doc/lesson05.md new file mode 100644 index 0000000..7c21167 --- /dev/null +++ b/doc/lesson05.md @@ -0,0 +1,66 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFei05cGNKbEM3eG8) (скачать все патчи можно через Download папки patch) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW4 + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Сохранение в базу в batch-моде с обработкой конфликтов](https://drive.google.com/file/d/0B9Ye2auQ_NsFZEJwR2ZqMEdVRG8) + +#### 5_1_HW4_upload_chunk.patch +> Добавил `required` в `upload.html` + +``` +mvn clean -pl web\upload -am package +cd web/upload +mvn org.codehaus.cargo:cargo-maven2-plugin:run +``` +[URL to Upload](http://localhost:8080/upload) + +**ВНИМАНИЕ! перед накаткой патча создайте каталог `web\webapp\src`** +#### 5_2_HW4_webapp_users.patch + +#### 5_3_HW4_already_present.patch +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. [Вставка в несколько потоков](https://drive.google.com/file/d/0B9Ye2auQ_NsFek5PYTdQbjBlUU0) +#### 5_4_HW4_parallel.patch +**Внимание! в postgres 10 с sequence могут быть проблемы** +> Правка для postgres 10 (`UserDao` 32): `h.execute("SELECT setval('user_seq', " + (id + step - 1) + ")")` + +> Fix: в `UserProcessor.process` нельзя делать `85: chunk.clean()`, тк этот список асинхронно используется для вставки. + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Рефакторинг](https://drive.google.com/open?id=1IYCUi8bPbP0FTp_Nylzh8Ssbu-rXahVX) +#### 5_5_HW4_parallel2.patch + +---------------- +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Конфигурирование приложения +**ВНИМАНИЕ! перед накаткой патча создейте в `common` каталог `\src` , иначе патч промахивается (от корня `common\src`).** +#### 5_6_typesafe_config.patch +> Перенес `compile/runtime` транзитивные зависимости из `parent` в `common`. Таким образом мы можен наследоваться от `parent` и не тянуть при этом все общие jar библиотеки + +**ВНИМАНИЕ!! Не забудте положить `persist.conf` в `/apps/masterjava/config` (или убрать `required` из `persist\src\main\resources\persist.conf`)** + +- Переопределение занчений в конфигурации в Spring. +- Встроенные профили Spring Boot +- Apache commons-configuration2 +- Typesafe config library , user in Playframework + - HOCON Syntax: Include, required(), Substitutions + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. Lombok +#### 5_7_lombok.patch +- Подключаем Lombok +- Фичи Lombok +- [Ten More Ways to Reduce Boilerplate with Lombok](https://www.sitepoint.com/beyond-pojos-ten-ways-reduce-boilerplate-lombok/) +- Подключение к IDEA +- Drawbacks, Call super constructor +- Declutter Your POJOs with Lombok + +## Домашнее задание +- добавить в DB и сделать DAO для городов, групп и проектов (города и группы как - foreign keys) +- добавить тесты на DAO +- добавить в модуле `upload` импорт и сохранение в базу городов (импорт групп и проектов будут в следующем ДЗ) + - загружаем `payload.xml` + - предполагается, что пользователей будет много, а городов, групп, проектов- на порядки меньше. + - если город уже есть в базе, просто пропускаем (не считаем ошибкой) + +#### Optional +- добавить при импорте пользователей связи на города + - если город юзера отсутствует в базе - ошибка импорта diff --git a/doc/lesson06.md b/doc/lesson06.md new file mode 100644 index 0000000..4dd842b --- /dev/null +++ b/doc/lesson06.md @@ -0,0 +1,127 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFVEJBS3VzVnBtMnc) + + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW5 + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Реализация модели/DAO/JUnit](https://drive.google.com/open?id=0B9Ye2auQ_NsFZzA1OHBUNExGdEk) +#### Apply 6_1_HW5_model_sql.patch +> - Перенес sql файлы в корневую папку `sql` +> - Изменения базы оставил только в файле миграции `databaseChangeLog.sql` +> - Сделал первичный ключ PK `city.ref`. Это справочник, и важно, чтобы внешние ссылки FK на него можно было вставить без заморочек. + У нас на одном проекте были проблемы, когда на разных окружениях справочные таблицы имели разные id. Данные нельзя было просто вставить скриптами миграции sql без подселектов или программного кода и + была задача привести их всех к одинаковым `id`. С `ref` как PK все упростится. Хотя у кого-то может быть другой опыт:) + +- Также см. отдельную тему **Миграция DB** в уроке. +- Скрип миграции `lb_apply.bat` (на sh переведите сами, если unix) можно запускать много раз. По истории смотрится, чтобы каждый ChangeSet накатился только 1 раз. ВНИМАНИЕ: скрипт накатывается на базу, сгенерированную `initDB.sql` +- [Liquibase](http://www.liquibase.org/) + - [Downloads](http://www.liquibase.org/download) + - [Run migration](http://www.liquibase.org/quickstart.html) + +#### Apply 6_2_HW5_dao_test.patch +> в `CityDaoTest` и `ProjectDaoTest` также выделил `init()` + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Реализация `upload` с городами +> - Классы `Result/ChunkResult/GroupResult` упростил до `List` +> - Переименовал +> - `ProcessPayload -> PayloadProcessor` +> - `CityExport -> CityProcessor` +> - `UserExport -> UserProcessor` + +#### Apply 6_3_HW5_add_PayloadProcessor.patch +#### Apply 6_4_HW5_NEW_add_CityProcessor.patch + +---------------- + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Миграция DB +- Liquibase (Dropwizard Migrations) +- Flyway, [Liquibase vs FLyway which one to use? (удалили на so, копия на русском)](https://stackoverrun.com/ru/q/10306280) +- MyBatis Migrations +- Техника безопасности при работе с PostgreSQL +- [Здоровье индексов в PostgreSQL глазами Java-разработчика](https://habr.com/ru/post/490824/) +- История про несогласованные данные +- DB Migration rules + - [Опыт 1440 миграций баз данных](https://habr.com/company/wrike/blog/414441/) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Веб-сервисы +#### Apply 6_5_web_services.patch + +- Веб-служба. Web service +- Примеры SOAP: + - Веб-сервис Центробанка, для получения ежедневных данных. + - Яндекса проверки правописания. + - Yandex каталог технологий + - Ряд веб сервисов авиастатистики, для мониторинга полетов, сведений о погоде, и.т.п. +- Resource vs. service +- REST vs SOAP. + +#### REST. +- 10 Best Practices for Better RESTful API + - JAX-RS, WADL + +#### SOAP +- SOAP веб-сервисы. +- WSDL. +- Web Services Standards. + +#### Java реализации. +- JAX-WS. SAAJ. JAX-RPC. +- JAX-WS vs Axis2 vs CXF. CFX vs AXIS. CXF vs Spring-WS +- AXIS vs CXF vs Spring WebServices +- Web Service Framework Comparison +- Contract-first and Contract-last styles +- Spring-WS Message Factories + +#### Имплементируем Mail Service +- [Introduction to JAX-WS](http://www.baeldung.com/jax-ws) +- JAX-WS Tutorial + - GlassFish » Metro » JAX-WS + - MailService WSDL / XSD +- Тестирование через SoapUI. + +---------------- +## Домашнее задание +- Реализовать `MailSender` с конфигурированием параметров в `mail.conf` + - Commons Email + - Параметры почты (yandex): +``` + mail.host: smtp.yandex.ru + mail.port: 465 + mail.username: user@yandex.ru + mail.password: password + mail.useSSL: true + mail.useTLS: false + mail.debug: true + mail.fromName: Name +``` +> Если конфигурируете почту Yandex, [перейдите в настройки](https://mail.yandex.ru/#setup/client) и поднимите галочки: + +![image](https://user-images.githubusercontent.com/11200258/113790310-c5b03b80-9749-11eb-969a-60ade652d405.png) + +> C включенным Avast были замечены проблемы с `ValidatorException: PKIX path building failed`. Avast и Avast Mail Shield для отправки требуется отключить + +> В случае DEBUG SMTP: AUTH LOGIN failed, Error: authentication failed: Invalid user or password! проверьте [Шаг 2. Создайте пароль приложения](https://yandex.ru/support/mail/mail-clients/others.html) - при галочке "Включить пароли приложений" нужно указывать пароль к приложению. + +> При попытке подключиться к хосту smtp.yandex.ru(или другому) возможен `SunCertPathBuilderException: unable to find valid certification path to requested target`. +> В таком случае нужно или выполнить [две команды в терминале](https://sky.pro/media/isklyuchenie-sun-security-provider-certpath-suncertpathbuilderexception-v-java/) +> или [сделать все как в статье](https://mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/). +> Во втором случае перед запуском пропишите в аргументах приложения имя хоста(smtp.yandex.ru:465 если через яндекс) + +- Сохранят результат отправки писем в DB (в `MailSender`). +- DAO и модель для сохранения сделать в модуле `mail-service` +- Протестировать отправку почты через SoapUI и/или `MailServiceClient` + +#### Optional +- добавить в модуле `upload` импорт и сохранение в базу групп и проектов (упрощение: только добавление без удаления/модификации) +- добавить при импорте пользователей связи на группы + - если пользователь уже есть в базе, поведение остается прежним: сразу ошибка импорта + - если пользователь новый, добавляется он и его группы + - если какая-либо группа пользователя отсутствует в базе - ошибка импорта + +## Замечания: + - пользователей много, а их групп еще больше. Если в чанке 2000 юзеров, не делайте 2001 запрос к базе при вставке 1го чанка. + - не считывате конфигурацию при каждой отсылке email + - попробуйте не дублировать инициализацию базы в `mail-service` + - Guide to using attached tests + diff --git a/doc/lesson07.md b/doc/lesson07.md new file mode 100644 index 0000000..83788f3 --- /dev/null +++ b/doc/lesson07.md @@ -0,0 +1,71 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFbXFnekNDSmJzS1k) (скачать все патчи можно через Download папки patch) +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW6 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Реализация `MailSender` +#### Apply 7_1_HW6_MailSender.patch +- List-Unsubcribe +- Amazon Simple Email Service + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Сохранение результатов отправки в DB +#### Apply 7_2_HW6_mail_history.patch +**Добавляем таблицу `mail_hist` через миграцию: после патча просто запускаем `\sql\lb_apply.bat`** + +> - В `mail_hist` удалил `body` и переименовал `date` -> `datetime` +> - Чтобы `mail-service` не зависел от `persist` можно было сделать еще один модуль `common-persist` + +- Resolving Maven circular dependencies +- Guide to using attached tests + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Импорт Проектов и Групп +#### Apply 7_3_NEW_HW6_ProjectGroupImporter.patch +> - Вынес общий `JaxbParser` в `PayloadProcessor` +> - Сделал `ProjectGroupProcessor` через `JaxbUnmarshaller` + +#### Apply 7_4_HW6_refactor_UserProcessor.patch +> - Вместо бина `List` сделал добавил 2й список `List` +> - Сделал батч вставку User и UserGroup в одной транзакции (для корректной работы повторного upload) +> - После вставки делаю очистку листов чанков (119, 120). Ссылки на них как closure попадают в `Future`, которые мы храним в `chunkFutures`, поэтому gc их не может удалить. + +- [Examples for org.skife.jdbi.v2.TransactionCallback](https://www.programcreek.com/java-api-examples/index.php?api=org.skife.jdbi.v2.TransactionCallback) +- Замечание в видео по поводу split: [Performance это праздник](https://habrahabr.ru/post/326242/) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Стили WSDL. Кастомизация WSDL +#### Apply 7_5_customize_WSDL.patch +- SOAP +- Стили WSDL + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. Публикация кастомизированного WSDL. Автогенерация. +#### Apply 7_6_publish_CustomizedWSDL.patch +- CXF + - IDEA bug of CXF integration + - accessExternalSchema property restriction + - Using the servlet transport without Spring +- Metro = JAX-WS RI + WSIT + - Web Services Interoperability Technologies (WSIT) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. Деплой в Tomcat +#### Apply 7_7_deploy_Tomcat.patch +> [http://localhost:8080/mail/mailService](http://localhost:8080/mail/mailService) + +- JAX-WS + Tomcat +- Deploy JAX-WS web services on Tomcat +- Deploying JAX-WS Services without web.xml +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. Создание клиента почтового сервиса. +#### Apply 7_8_create_client.patch +- Dynamically Change a Web Service Endpoint URL +- Fix thread safe JAX-WS client call +---------------- + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Реализация массовой и групповой отправки почты. HW7](https://drive.google.com/file/d/0B9Ye2auQ_NsFLWVfaEhFU1ctNjA) +> Подправил `GroupResult/ MailResult` для сериализации/десериализации в xml + +#### Apply 7_9_refactoring_send_to_group.patch +#### Apply 7_10_send_bulk.patch + +## Домашнее задание +- Расшарить wsdl для всех модулей в `\apps\masterjava\config\wsdl` +- Обновить `mailService.wsdl` в соответствии с реализацией (+пофиксить проблемы) и протестировать работу сервиса + +### Optional +- Сделать в модуле `web` простой интерфейс для выбора пользователей из таблицы и отправки им почты (`subject` и `body` также элементы интерфейса) diff --git a/doc/lesson08.md b/doc/lesson08.md new file mode 100644 index 0000000..174da57 --- /dev/null +++ b/doc/lesson08.md @@ -0,0 +1,56 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFeUFhRGRETk80MkE) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW7 + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Делаем общий `mailService.wsdl` +> Напомню, что общие wsdl ресурсы хранятся в `${masterjava.config}/wsdl` + +[Способы конфигурирования Maven](https://maven.apache.org/configure.html) +- `MAVEN_OPTS` +- `settings.xml` +- `.mvn` папка в корне проекта: `maven.config` с параметром `-Dmasterjava.config=/some/path/to/config` + +#### Apply 1_HW7_wsdl_share.patch +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Доступ к переменным maven в приложении +#### Apply 2_app_conf.patch +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Обновление WSDL](https://drive.google.com/file/d/0B9Ye2auQ_NsFWDFRYm5uNlJlNmM) +#### Apply 3_HW7_update_wsdl.patch +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. Отправка почты из модуля `webapp` +> Убрал обработку эксепшенов в `MailWSClient` (есть в `SendServlet`) и заменил `$.ajax` на `$.post` + +#### Apply 4_HW7_webapp.patch + +- [jQuery.post() done and success](https://stackoverflow.com/a/22213543/548473) + +---- +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. SOAP Exception. Выделение общей части схемы +> Удалил `GroupResult.failedCause` и сделал вместо него `WebStateException` (бросается из `MailServiceExecutor`) + +**ВНИМАНИЕ! перед накаткой патча создейте в `services` каталог `\common-ws` (от корня `services\common-ws`)** +#### Apply 5_soap_exceptions.patch +- Передача по SOAP Exception + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Коррекция схемы](https://drive.google.com/file/d/0B9Ye2auQ_NsFZ1FmODdWcmlKdUk) +> Анологично `Addressee` поправил `MailResult` + +#### Apply 6_fix_wsdl_and_schema.patch + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Добавление мавен плагинов](https://drive.google.com/open?id=0B9Ye2auQ_NsFYnhDWG03Z3R6Y0E) +#### Apply 8_7_mvn_plugins.patch +- [Copy Rename Maven Plugin](https://coderplus.github.io/copy-rename-maven-plugin/usage.html) +- [Maven AntRun Plugin](http://maven.apache.org/plugins/maven-antrun-plugin/usage.html) +- [Maven Liquibase Plugin](http://www.liquibase.org/documentation/maven/) + + +-------------- +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. Домашнее задание +Сделать отправку почты из модуля web c вложениями: +- Binary Data Transmission Using MTOM/XOP +- Тестирование вложений через SoapUi. +- Sending emails with attachments +> При `timeout=10s` и `debug=true` в `mail.conf` для писем со вложениями логирование будет настолько долгим (attachments тоже логируются), что сервис будет отваливаться по таймату (но письма будут нормально отправляться). +Решение: при отправке писем со вложениями отключать дебаг или увеличивать таймаут (например 30s) +### Optional +- Добавить Git revision в `version.html` diff --git a/doc/lesson09.md b/doc/lesson09.md new file mode 100644 index 0000000..4b76e19 --- /dev/null +++ b/doc/lesson09.md @@ -0,0 +1,69 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFd3pjNWZpR0QzVWs) + +### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Правка + +#### Apply 9_0_fix_package.patch +> - В модуле `common-ws` перенес пакет `ru.javaops.web` в `ru.javaops.masterjava.web` + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW8 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Реализация вложений в веб-сервисе](https://drive.google.com/open?id=0B9Ye2auQ_NsFbER6Rjc4dHRGODA) +#### Apply 9_1_HW8_service_attach.patch +> Переименовал `Attach` в `Attachment` + +- Binary Data Transmission Using MTOM/XOP +- Тестирование вложений через SoapUi. + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. [Подключение MTOM](https://drive.google.com/open?id=0B9Ye2auQ_NsFeF8yWVBUbHd6Y0k) +#### Apply 9_2_HW8_MTOM.patch + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Реализация загрузки вложений в модуле webapp](https://drive.google.com/open?id=0B9Ye2auQ_NsFaVhpMkZRV3lSUlU) +> - Реализовал загрузку вложения через jQuery `FormData()` и Servlet 3 `@MultipartConfig` + +- [Sending multipart/formdata with jQuery](https://stackoverflow.com/a/5976031/548473) + +#### Apply 9_3_HW8_webapp_attach.patch + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Реализация вложений в почте](https://drive.google.com/open?id=0B9Ye2auQ_NsFQ0RZNktReWRoYjQ) +#### Apply 9_4_HW8_mail_attach.patch + +### [Git revision](https://habrahabr.ru/post/310738/) +#### Apply 9_5_HW8_git_revision.patch +> Не забудте обновит `/apps/masterjava/config` новыми файлами конфигурации + +--------------------- + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [JAX-WS Message Context. Авторизация](https://drive.google.com/open?id=0B9Ye2auQ_NsFSEdYZzR3OGxxLVk) +#### Apply 9_6_msg_ctx_auth.patch + +- Message Context in JAX-WS +- Application Authentication with JAX-WS + - Container Authentication + +#### Асинхронный вызов через @OneWay + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [JAX-WS Handlers](https://drive.google.com/open?id=0B9Ye2auQ_NsFYjhDUGM2N0tHVDg) +#### Apply 9_7_logging_handlers.patch +> Сделал `Client/Server LoggingHandler` внутренними классами `SoapLoggingHandlers` + +- Handlers in JAX-WS + - SOAP handler sample + - Message Context + + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Домашнее задание. Статистика](https://drive.google.com/open?id=0B9Ye2auQ_NsFWGI0ejBZZ21Cc0k) +#### Apply 9_8_prepare_HW9.patch +> После обновления `hosts.conf` в `masterjava.config (/apps/masterjava/config/)` поломается конфигурация `endpoint`, в ДЗ требуется починить + + - Сделать отдельный Handler статистики трафика веб-сервиса (в статистике только логирование) + - Сделать авторизацию в `mailService` через `SoapServerSecurityHandler` + +#### Optional + - Вынести уровень логирования веб-сервисов и креденшелы авторизации в конфигурацию (`host.conf`) + - Сделать (отнаследовать) для `mail-service` свои хендлеры логирования и авторизации с настройками из конфигурации + +## Замечания: + - обновите формат `hosts.conf` в `masterjava.config (/apps/masterjava/config/)` + - в модуле `common-ws` находятся общие классы. Не хардкодьте туда `mail` сервис + - попробуйте вынести весь общий код в классы `common-ws` diff --git a/doc/lesson10.md b/doc/lesson10.md new file mode 100644 index 0000000..70d4ffc --- /dev/null +++ b/doc/lesson10.md @@ -0,0 +1,89 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFWGU0MTRQYkFQdEk) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW9 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Реализация SOAP handlers](https://drive.google.com/open?id=0B9Ye2auQ_NsFTVhpbTNCTDZ4bTA) +> - Для `SecurityHandler` в `mail-service` сделал родительский `MailHandlers` + +#### Apply 10_1_HW9_handlers.patch + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. [Конфигурирование сервисов](https://drive.google.com/open?id=0B9Ye2auQ_NsFR1lybnQyRUJUUEU) +> Поправил в конфигурации [обработку null значений](https://github.com/typesafehub/config/issues/282) + +#### Apply 10_2_HW9_host_config.patch + +- Handle defaults in config + +---------------------------- + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [JavaEE](https://drive.google.com/open?id=0B9Ye2auQ_NsFUU92ZFBEZmJjb2c) +- Java Platform, Enterprise Edition +- Холивары в комментах +- CDI +- Enterprise JavaBeans +- TomEE состав +- Application Server statistics + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [JAX-RS](https://drive.google.com/file/d/0B9Ye2auQ_NsFeWQxTUVBSDFGMGM) +#### Apply 10_3_JAX_RS.patch +> - Обновил версию JAX-RS. См. [upgrage issue](https://github.com/jersey/jersey/issues/3664) +> - В `users.html` +> - сделал проверку на `"Addresses are not selected"` +> - в `done()` объект привожу к строке (JAX-RS возвращает json) +> - в `fail()` сделал вывод `result.responseText` + +#### Apply 10_4_jersey_logging.patch +> - [JAX-RS Test URL](http://localhost:8080/mail/rest/test) +> - [JAX-RS Detail WADL URL](http://localhost:8080/mail/rest/application.wadl?detail=true) + +- Jersey: RESTful Web Services in Java +- Modules and dependencies +- Example with web.xml +- Descriptor-less deployment + - [ServletContainerInitializer](http://stackoverflow.com/a/10784700/548473) + - [Servlet 3.0 ServletContainerInitializer and Spring WebApplicationInitializer](http://www.java-allandsundry.com/2014/03/servlet-30-servletcontainerinitializer.html) +- Jersey + MOXy JSON +- Validation +- Web Application Description Language (WADL) + - mail/rest/application.wadl + - wadl2java client stub generation + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. JMS +> - Вынес в `parent-web` версию ActiveMQ +> - Переименовал `SendServlet` в `SoapSendServlet` + +#### Apply 10_5_JMS.patch +> ![Внимание](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) **Для того, чтобы по JNDI приложение работало с JMS сконфигурируйте Tomcat:** +> - Скопируйте +> - `config_templates/context.xml` в `$TOMCAT_HOME/conf` +> - `$MAVEN_REPO(~/.m2)/org/apache/activemq/activemq-all/5.15.2/activemq-all-5.15.2.jar` в `$TOMCAT_HOME/lib` + +*Для новых версий activemq-all, например `activemq-all-5.16.3.jar`, [нужно добавить в зависимости `jackson-core`, `jackson-databind`, `jackson-databind`](https://cursos.alura.com.br/forum/topico-java-11-activemq-5-15-14-java-lang-noclassdeffounderror-com-fasterxml-jackson-databind-objectmapper-141531)* + +- Java Message Service +- Queues +- JMS vs AMQP, AMQP +- ActiveMQ, HornetQ and RabbitMQ Performance Comparison +- ActiveMQ + Tomcat +- Embedded/StandAlone ActiveMQ, ActiveMQ transport, URI protocols +- Apache ActiveMQ and Tomcat sample + - [When close JMS connection/sessions](http://stackoverflow.com/questions/19772082/when-should-i-close-a-jms-connection-that-was-created-in-a-stateless-session-bea) + - [Cache JMS connections/sessions](https://developer.jboss.org/wiki/ShouldICacheJMSConnectionsAndJMSSessions) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Авторизация в контейнере Tomcat](https://drive.google.com/file/d/0B9Ye2auQ_NsFcU1FU3FTQ25NNzA) +#### Apply 10_6_tomcat_auth.patch + +- [Realm Configuration HOW-TO](http://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html) +- [Setup your own Tomcat security realm](http://www.christianschenk.org/blog/setup-your-own-tomcat-security-realm/) + + +## Домашнее задание +- Добавить аттачи в JAX-RS + - [File upload example in Jersey](http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey) **НЕ РАБОТАЕТ!** + - Jersey Multipart on Tomcat (вложения приходят, но пустые или обрезанные) +- Реализовать отсылку почты через JMS `ObjectMessage` + +#### Optional + - Починить вложения в JAX-RS (javax.mail читает поток из вложения 2 раза) + - Сделать вложения в JMS diff --git a/doc/lesson11.md b/doc/lesson11.md new file mode 100644 index 0000000..6458da9 --- /dev/null +++ b/doc/lesson11.md @@ -0,0 +1,86 @@ +# Онлайн проекта Masterjava. + +## [Материалы занятия](https://drive.google.com/drive/u/0/folders/0B9Ye2auQ_NsFd1FnME50bEt6RDA) + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Разбор домашнего задания HW10 +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. [Отправка вложений по JAX-RS](https://drive.google.com/open?id=0B9Ye2auQ_NsFT3VmNXR2djRqM1E) +#### Apply 11_1_HW10_jersey_attach.patch +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. [Отправка почты с вложениями по JMS](https://drive.google.com/open?id=0B9Ye2auQ_NsFdEZhVll2UFdCY0U) +#### Apply 11_2_HW10_JMS_attach.patch + +- [Недостатки ObjectMessage (или недостатки сериализации Java)]( http://jmesnil.net/weblog/2012/07/27/on-jms-objectmessage-and-its-pitfalls) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. [Рефакторинг. Эксепшены в Java 8 лямбда](https://drive.google.com/open?id=0B9Ye2auQ_NsFQUE4SzFQS2VDZ2M) +> Отправку по JMS листа аттачей + +#### Apply 11_3_HW10_JMS_attach_fix.patch +#### Apply 11_4_refactoring.patch +- [Pair (tuple) in Java](http://stackoverflow.com/questions/521171/a-java-collection-of-value-pairs-tuples) +- [Java 8 Lambda with exception](http://stackoverflow.com/questions/18198176/java-8-lambda-function-that-throws-exception) +- [What's Wrong in Java 8](https://dzone.com/articles/whats-wrong-java-8-part-iv) +- [Durian](https://github.com/diffplug/durian) ( [Дуриан](https://ru.wikipedia.org/wiki/Дуриан) ) + +> #### Дополнительно: +> #### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) [Николай Алименков - Нужен ли нам JMS в мире современных Java-технологий?](https://www.youtube.com/watch?v=ExjPxDxkmFo) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Concurrent and distributed applications toolkit AKKA](https://drive.google.com/open?id=0B9Ye2auQ_NsFR0tjc28tRzVHQVk) +> #### Внимание! Перед накаткой патчеа создайте в `services` каталог `akka-remote` (`services/akka-remote`) иначе файлы придется руками сюда перетаскивать. +> После патча скопируйте `akka.conf` в `${masterjava.config} (/apps/masterjava/config)` + +#### Apply 11_5_akka.patch +- [Wiki Akka (toolkit)](https://en.wikipedia.org/wiki/Akka_(toolkit)) +- [Модель акторов](https://ru.wikipedia.org/wiki/Модель_акторов) +- [Видео: Akka и его использование в Яндексе](http://2014.jpoint.ru/talks/07/) + - [Remoting](http://doc.akka.io/docs/akka/current/scala/remoting.html) + - [Remoting Sample](http://doc.akka.io/docs/akka/current/java/remoting.html#Remoting_Sample) + - [Tutorials](http://akka.io/downloads/) + - [Get started with Lightbend technologies](https://developer.lightbend.com/start) + - [Typesafe Changes Name to Lightbend](https://www.lightbend.com/blog/typesafe-changes-name-to-lightbend) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Отсылка почты через AKKA Actors](https://drive.google.com/file/d/0B9Ye2auQ_NsFQWppSmxRYnVKX3M) +#### Apply 11_6_akka_typed.patch +> **При задержке выполнения актора более чем на 5 сек. будет вываливаться `AskTimeoutException: Timed out`. В `AkkaActivator` сделал Timeout 20 сек.** + + - [Typed Actors](http://doc.akka.io/docs/akka/current/java/typed-actors.html) + - [Spring Asynchronous Methods](https://spring.io/guides/gs/async-method) + - [Spring Async support](https://spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing-servlet-3-async-support) + - [Asynchronous with JAX-RS](http://allegro.tech/2014/10/async-rest.html) + - [Currying vs Partial application](https://stackoverflow.com/a/218055/548473) + - [Serialization](http://doc.akka.io/docs/akka/current/scala/serialization.html) + + +#### Apply 11_7_akka_untyped.patch +> Переименовал `AkkaActorSendServlet` в `AkkaUntypedSendServlet` + - [Actors](http://doc.akka.io/docs/akka/current/java/actors.html) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Асинхронные сервлеты 3.0](https://drive.google.com/open?id=0B9Ye2auQ_NsFV2I2TndUT0kzT2s) +- [Tomcat 7 Async Processing](http://stackoverflow.com/questions/7287244/tomcat-7-async-processing) +- [Async in Servlet 3.0 vs NIO in Servlet 3.1](http://stackoverflow.com/questions/39802643/java-async-in-servlet-3-0-vs-nio-in-servlet-3-1) +- [AsyncContext.start in Servlet 3.0](https://stackoverflow.com/questions/10073392/whats-the-purpose-of-asynccontext-start-in-servlet-3-0) +- [The Limited Usefulness of AsyncContext.start()](https://dzone.com/articles/limited-usefulness) + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Выбор языка программирования](https://drive.google.com/file/d/0B9Ye2auQ_NsFZUVNakNxeUtGeFE) +- [Scala dependency injection (di)](http://jonasboner.com/real-world-scala-dependency-injection-di) +- [Когда появится следующий большой язык программирования](https://habrahabr.ru/company/wrike/blog/323550) +- [Как я нашел лучший в мире язык программирования](https://habrahabr.ru/post/260149/) +- [EduTools плагин от JetBrains для изучения Kotlin, Java, Python, Scala, ...](http://javaops.ru/view/story/story21#edutools) +- [Котлин рулит](https://habrahabr.ru/company/JetBrains/blog/329028/) + - [Почему следует полностью переходить на Kotlin](https://habrahabr.ru/company/mailru/blog/329294) + - [Stepik: Бесплатный Stepik курс Kotlin (доступен также через плагин JetBrains EduTools)](https://stepik.org/course/Kotlin-2852) + - [Devcolibri: Базовый курс по Kotlin](https://www.youtube.com/playlist?list=PLIU76b8Cjem4ZOt3tlWykUX1AjL9zE19t) + + +## Домашнее задание +- Сделать асинхронное ожидание и **вывод результатов отправки почты** пользователю в сервлетах: + - `AkkaTypedSendServlet` с выполнением в Tomcat `ThreadPoolExecutor` + - `AkkaActorSendServlet` с выполнением в собственном `ExecutorService` + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Разбор решения с асинхронными сервлетами](https://drive.google.com/open?id=0B9Ye2auQ_NsFTWk1VS1GV1ROY0U) +#### Apply 11_8_async_servlet.patch + +----------- + +### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Коррекция: +#### Apply 11_9_fix.patch +- `UserDao.insertWitId` поправил на `UserDao.insertWithId` +- `UserTestData.FIST5_USERS` поправил на `FIRST5_USERS`