The following schema fragment specifies the expected content contained within this class.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
city;
++
++ /**
++ * Gets the value of the city property.
++ *
++ *
++ * This accessor method returns a reference to the live list,
++ * not a snapshot. Therefore any modification you make to the
++ * returned list will be present inside the JAXB object.
++ * This is why there is not a set method for the city property.
++ *
++ *
++ * For example, to add a new item, do as follows:
++ *
++ * getCity().add(newItem);
++ *
++ *
++ *
++ *
++ * Objects of the following type(s) are allowed in the list
++ * {@link CityType }
++ *
++ *
++ */
++ public List getCity() {
++ if (city == null) {
++ city = new ArrayList();
++ }
++ return this.city;
++ }
++
++ }
++
++
++ /**
++ * Java class for anonymous complex type.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <sequence maxOccurs="unbounded" minOccurs="0">
++ * <element ref="{http://javaops.ru}User"/>
++ * </sequence>
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ *
++ *
++ *
++ */
++ @XmlAccessorType(XmlAccessType.FIELD)
++ @XmlType(name = "", propOrder = {
++ "user"
++ })
++ public static class Users {
++
++ @XmlElement(name = "User", namespace = "http://javaops.ru")
++ protected List user;
++
++ /**
++ * Gets the value of the user property.
++ *
++ *
++ * This accessor method returns a reference to the live list,
++ * not a snapshot. Therefore any modification you make to the
++ * returned list will be present inside the JAXB object.
++ * This is why there is not a set method for the user property.
++ *
++ *
++ * For example, to add a new item, do as follows:
++ *
++ * getUser().add(newItem);
++ *
++ *
++ *
++ *
++ * Objects of the following type(s) are allowed in the list
++ * {@link User }
++ *
++ *
++ */
++ public List getUser() {
++ if (user == null) {
++ user = new ArrayList();
++ }
++ return this.user;
++ }
++
++ }
++
++}
+Index: src/main/resources/payload.xsd
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/resources/payload.xsd (revision )
++++ src/main/resources/payload.xsd (revision )
+@@ -0,0 +1,56 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision )
+@@ -0,0 +1,54 @@
++
++package ru.javaops.masterjava.xml.schema;
++
++import javax.xml.bind.annotation.XmlEnum;
++import javax.xml.bind.annotation.XmlEnumValue;
++import javax.xml.bind.annotation.XmlType;
++
++
++/**
++ * Java class for flagType.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <simpleType name="flagType">
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
++ * <enumeration value="active"/>
++ * <enumeration value="deleted"/>
++ * <enumeration value="superuser"/>
++ * </restriction>
++ * </simpleType>
++ *
++ *
++ */
++@XmlType(name = "flagType", namespace = "http://javaops.ru")
++@XmlEnum
++public enum FlagType {
++
++ @XmlEnumValue("active")
++ ACTIVE("active"),
++ @XmlEnumValue("deleted")
++ DELETED("deleted"),
++ @XmlEnumValue("superuser")
++ SUPERUSER("superuser");
++ private final String value;
++
++ FlagType(String v) {
++ value = v;
++ }
++
++ public String value() {
++ return value;
++ }
++
++ public static FlagType fromValue(String v) {
++ for (FlagType c: FlagType.values()) {
++ if (c.value.equals(v)) {
++ return c;
++ }
++ }
++ throw new IllegalArgumentException(v);
++ }
++
++}
+Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision )
+@@ -0,0 +1,85 @@
++
++package ru.javaops.masterjava.xml.schema;
++
++import javax.xml.bind.JAXBElement;
++import javax.xml.bind.annotation.XmlElementDecl;
++import javax.xml.bind.annotation.XmlRegistry;
++import javax.xml.namespace.QName;
++
++
++/**
++ * This object contains factory methods for each
++ * Java content interface and Java element interface
++ * generated in the ru.javaops.masterjava.xml.schema package.
++ * An ObjectFactory allows you to programatically
++ * construct new instances of the Java representation
++ * for XML content. The Java representation of XML
++ * content can consist of schema derived interfaces
++ * and classes representing the binding of schema
++ * type definitions, element declarations and model
++ * groups. Factory methods for each of these are
++ * provided in this class.
++ *
++ */
++@XmlRegistry
++public class ObjectFactory {
++
++ private final static QName _City_QNAME = new QName("http://javaops.ru", "City");
++
++ /**
++ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ru.javaops.masterjava.xml.schema
++ *
++ */
++ public ObjectFactory() {
++ }
++
++ /**
++ * Create an instance of {@link Payload }
++ *
++ */
++ public Payload createPayload() {
++ return new Payload();
++ }
++
++ /**
++ * Create an instance of {@link User }
++ *
++ */
++ public User createUser() {
++ return new User();
++ }
++
++ /**
++ * Create an instance of {@link Payload.Cities }
++ *
++ */
++ public Payload.Cities createPayloadCities() {
++ return new Payload.Cities();
++ }
++
++ /**
++ * Create an instance of {@link Payload.Users }
++ *
++ */
++ public Payload.Users createPayloadUsers() {
++ return new Payload.Users();
++ }
++
++ /**
++ * Create an instance of {@link CityType }
++ *
++ */
++ public CityType createCityType() {
++ return new CityType();
++ }
++
++ /**
++ * Create an instance of {@link JAXBElement }{@code <}{@link CityType }{@code >}}
++ *
++ */
++ @XmlElementDecl(namespace = "http://javaops.ru", name = "City")
++ public JAXBElement createCity(CityType value) {
++ return new JAXBElement(_City_QNAME, CityType.class, null, value);
++ }
++
++}
diff --git a/patches/lesson02/2_07_JAXB.patch b/patches/lesson02/2_07_JAXB.patch
new file mode 100644
index 000000000..f319308e8
--- /dev/null
+++ b/patches/lesson02/2_07_JAXB.patch
@@ -0,0 +1,358 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision )
+@@ -0,0 +1,89 @@
++package ru.javaops.masterjava.xml.util;
++
++import org.xml.sax.SAXException;
++
++import javax.xml.bind.JAXBContext;
++import javax.xml.bind.JAXBException;
++import javax.xml.bind.PropertyException;
++import javax.xml.transform.stream.StreamSource;
++import javax.xml.validation.Schema;
++import java.io.*;
++
++
++/**
++ * Marshalling/Unmarshalling JAXB helper
++ * XML Facade
++ * @author Grigory Kislin
++ */
++public class JaxbParser {
++
++ protected JaxbMarshaller jaxbMarshaller;
++ protected JaxbUnmarshaller jaxbUnmarshaller;
++ protected Schema schema;
++
++ public JaxbParser(Class... classesToBeBound) {
++ try {
++ init(JAXBContext.newInstance(classesToBeBound));
++ } catch (JAXBException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ // http://stackoverflow.com/questions/30643802/what-is-jaxbcontext-newinstancestring-contextpath
++ public JaxbParser(String context) {
++ try {
++ init(JAXBContext.newInstance(context));
++ } catch (JAXBException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ private void init(JAXBContext ctx) throws JAXBException {
++ jaxbMarshaller = new JaxbMarshaller(ctx);
++ jaxbUnmarshaller = new JaxbUnmarshaller(ctx);
++ }
++
++ // Unmarshaller
++ public T unmarshal(InputStream is) throws JAXBException {
++ return (T) jaxbUnmarshaller.unmarshal(is);
++ }
++
++ public T unmarshal(Reader reader) throws JAXBException {
++ return (T) jaxbUnmarshaller.unmarshal(reader);
++ }
++
++ public T unmarshal(String str) throws JAXBException {
++ return (T) jaxbUnmarshaller.unmarshal(str);
++ }
++
++ // Marshaller
++ public void setMarshallerProperty(String prop, Object value) {
++ try {
++ jaxbMarshaller.setProperty(prop, value);
++ } catch (PropertyException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ public synchronized String marshal(Object instance) throws JAXBException {
++ return jaxbMarshaller.marshal(instance);
++ }
++
++ public void marshal(Object instance, Writer writer) throws JAXBException {
++ jaxbMarshaller.marshal(instance, writer);
++ }
++
++ public void setSchema(Schema schema) {
++ this.schema = schema;
++ jaxbUnmarshaller.setSchema(schema);
++ jaxbMarshaller.setSchema(schema);
++ }
++
++ public void validate(String str) throws IOException, SAXException {
++ validate(new StringReader(str));
++ }
++
++ public void validate(Reader reader) throws IOException, SAXException {
++ schema.newValidator().validate(new StreamSource(reader));
++ }
++}
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision )
+@@ -0,0 +1,37 @@
++package ru.javaops.masterjava.xml.util;
++
++import javax.xml.bind.JAXBContext;
++import javax.xml.bind.JAXBException;
++import javax.xml.bind.Unmarshaller;
++import javax.xml.validation.Schema;
++import java.io.InputStream;
++import java.io.Reader;
++import java.io.StringReader;
++
++/**
++ * @author GKislin
++ * Date: 18.11.2008
++ */
++public class JaxbUnmarshaller {
++ private Unmarshaller unmarshaller;
++
++ public JaxbUnmarshaller(JAXBContext ctx) throws JAXBException {
++ unmarshaller = ctx.createUnmarshaller();
++ }
++
++ public synchronized void setSchema(Schema schema) {
++ unmarshaller.setSchema(schema);
++ }
++
++ public synchronized Object unmarshal(InputStream is) throws JAXBException {
++ return unmarshaller.unmarshal(is);
++ }
++
++ public synchronized Object unmarshal(Reader reader) throws JAXBException {
++ return unmarshaller.unmarshal(reader);
++ }
++
++ public Object unmarshal(String str) throws JAXBException {
++ return unmarshal(new StringReader(str));
++ }
++}
+Index: src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision )
++++ src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision )
+@@ -0,0 +1,44 @@
++package ru.javaops.masterjava.xml.util;
++
++import com.google.common.io.Resources;
++import org.junit.Test;
++import ru.javaops.masterjava.xml.schema.CityType;
++import ru.javaops.masterjava.xml.schema.ObjectFactory;
++import ru.javaops.masterjava.xml.schema.Payload;
++
++import javax.xml.bind.JAXBElement;
++import javax.xml.namespace.QName;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class JaxbParserTest {
++ private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class);
++
++ static {
++ JAXB_PARSER.setSchema(Schemas.ofClasspath("payload.xsd"));
++ }
++
++ @Test
++ public void testPayload() throws Exception {
++// JaxbParserTest.class.getResourceAsStream("/city.xml")
++ Payload payload = JAXB_PARSER.unmarshal(
++ Resources.getResource("payload.xml").openStream());
++ String strPayload = JAXB_PARSER.marshal(payload);
++ JAXB_PARSER.validate(strPayload);
++ System.out.println(strPayload);
++ }
++
++ @Test
++ public void testCity() throws Exception {
++ JAXBElement cityElement = JAXB_PARSER.unmarshal(
++ Resources.getResource("city.xml").openStream());
++ CityType city = cityElement.getValue();
++ JAXBElement cityElement2 =
++ new JAXBElement<>(new QName("http://javaops.ru", "City"), CityType.class, city);
++ String strCity = JAXB_PARSER.marshal(cityElement2);
++ JAXB_PARSER.validate(strCity);
++ System.out.println(strCity);
++ }
++}
+\ No newline at end of file
+Index: src/test/resources/city.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/resources/city.xml (revision )
++++ src/test/resources/city.xml (revision )
+@@ -0,0 +1,4 @@
++Санкт-Петербург
++
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/xml/util/Schemas.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision )
+@@ -0,0 +1,51 @@
++package ru.javaops.masterjava.xml.util;
++
++import com.google.common.io.Resources;
++import org.xml.sax.SAXException;
++
++import javax.xml.XMLConstants;
++import javax.xml.transform.stream.StreamSource;
++import javax.xml.validation.Schema;
++import javax.xml.validation.SchemaFactory;
++import java.io.File;
++import java.io.StringReader;
++import java.net.URL;
++
++
++/**
++ * @author Grigory Kislin
++ */
++public class Schemas {
++
++ // SchemaFactory is not thread-safe
++ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
++
++ public static synchronized Schema ofString(String xsd) {
++ try {
++ return SCHEMA_FACTORY.newSchema(new StreamSource(new StringReader(xsd)));
++ } catch (SAXException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ public static synchronized Schema ofClasspath(String resource) {
++ // http://digitalsanctum.com/2012/11/30/how-to-read-file-contents-in-java-the-easy-way-with-guava/
++ return ofURL(Resources.getResource(resource));
++ }
++
++ public static synchronized Schema ofURL(URL url) {
++ try {
++ return SCHEMA_FACTORY.newSchema(url);
++ } catch (SAXException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ public static synchronized Schema ofFile(File file) {
++ try {
++ return SCHEMA_FACTORY.newSchema(file);
++ } catch (SAXException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++}
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision )
+@@ -0,0 +1,43 @@
++package ru.javaops.masterjava.xml.util;
++
++import javax.xml.bind.JAXBContext;
++import javax.xml.bind.JAXBException;
++import javax.xml.bind.Marshaller;
++import javax.xml.bind.PropertyException;
++import javax.xml.validation.Schema;
++import java.io.StringWriter;
++import java.io.Writer;
++
++/**
++ * @author GKislin
++ * Date: 18.11.2008
++ */
++public class JaxbMarshaller {
++ private Marshaller marshaller;
++
++ public JaxbMarshaller(JAXBContext ctx) throws JAXBException {
++ marshaller = ctx.createMarshaller();
++ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
++ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
++ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
++ }
++
++ public void setProperty(String prop, Object value) throws PropertyException {
++ marshaller.setProperty(prop, value);
++ }
++
++ public synchronized void setSchema(Schema schema) {
++ marshaller.setSchema(schema);
++ }
++
++ public String marshal(Object instance) throws JAXBException {
++ StringWriter sw = new StringWriter();
++ marshal(instance, sw);
++ return sw.toString();
++ }
++
++ public synchronized void marshal(Object instance, Writer writer) throws JAXBException {
++ marshaller.marshal(instance, writer);
++ }
++
++}
+Index: pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- pom.xml (date 1488837115000)
++++ pom.xml (revision )
+@@ -32,6 +32,14 @@
+
+
+ org.apache.maven.plugins
++ maven-surefire-plugin
++ 2.19.1
++
++ -Dfile.encoding=UTF-8
++
++
++
++ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.2
+
+@@ -79,6 +87,17 @@
+ jmh-generator-annprocess
+ RELEASE
+ provided
++
++
++ com.google.guava
++ guava
++ 21.0
++
++
++ junit
++ junit
++ 4.12
++ test
+
+
+
diff --git a/patches/lesson02/2_08_StAX.patch b/patches/lesson02/2_08_StAX.patch
new file mode 100644
index 000000000..30167fae5
--- /dev/null
+++ b/patches/lesson02/2_08_StAX.patch
@@ -0,0 +1,117 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision )
+@@ -0,0 +1,60 @@
++package ru.javaops.masterjava.xml.util;
++
++import javax.xml.stream.XMLInputFactory;
++import javax.xml.stream.XMLStreamException;
++import javax.xml.stream.XMLStreamReader;
++import javax.xml.stream.events.XMLEvent;
++import java.io.InputStream;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class StaxStreamProcessor implements AutoCloseable {
++ private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance();
++
++ private final XMLStreamReader reader;
++
++ public StaxStreamProcessor(InputStream is) throws XMLStreamException {
++ reader = FACTORY.createXMLStreamReader(is);
++ }
++
++ public XMLStreamReader getReader() {
++ return reader;
++ }
++
++ public boolean doUntil(int stopEvent, String value) throws XMLStreamException {
++ while (reader.hasNext()) {
++ int event = reader.next();
++ if (event == stopEvent) {
++ if (value.equals(getValue(event))) {
++ return true;
++ }
++ }
++ }
++ return false;
++ }
++
++ public String getValue(int event) throws XMLStreamException {
++ return (event == XMLEvent.CHARACTERS) ? reader.getText() : reader.getLocalName();
++ }
++
++ public String getElementValue(String element) throws XMLStreamException {
++ return doUntil(XMLEvent.START_ELEMENT, element) ? reader.getElementText() : null;
++ }
++
++ public String getText() throws XMLStreamException {
++ return reader.getElementText();
++ }
++
++ @Override
++ public void close() {
++ if (reader != null) {
++ try {
++ reader.close();
++ } catch (XMLStreamException e) {
++ // empty
++ }
++ }
++ }
++}
+Index: src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision )
++++ src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision )
+@@ -0,0 +1,40 @@
++package ru.javaops.masterjava.xml.util;
++
++import com.google.common.io.Resources;
++import org.junit.Test;
++
++import javax.xml.stream.XMLStreamReader;
++import javax.xml.stream.events.XMLEvent;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class StaxStreamProcessorTest {
++ @Test
++ public void readCities() throws Exception {
++ try (StaxStreamProcessor processor =
++ new StaxStreamProcessor(Resources.getResource("payload.xml").openStream())) {
++ XMLStreamReader reader = processor.getReader();
++ while (reader.hasNext()) {
++ int event = reader.next();
++ if (event == XMLEvent.START_ELEMENT) {
++ if ("City".equals(reader.getLocalName())) {
++ System.out.println(reader.getElementText());
++ }
++ }
++ }
++ }
++ }
++
++ @Test
++ public void readCities2() throws Exception {
++ try (StaxStreamProcessor processor =
++ new StaxStreamProcessor(Resources.getResource("payload.xml").openStream())) {
++ String city;
++ while ((city = processor.getElementValue("City")) != null) {
++ System.out.println(city);
++ }
++ }
++ }
++}
+\ No newline at end of file
diff --git a/patches/lesson02/2_09_XPath.patch b/patches/lesson02/2_09_XPath.patch
new file mode 100644
index 000000000..4745b852f
--- /dev/null
+++ b/patches/lesson02/2_09_XPath.patch
@@ -0,0 +1,109 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision )
++++ src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision )
+@@ -0,0 +1,62 @@
++package ru.javaops.masterjava.xml.util;
++
++import org.w3c.dom.Document;
++import org.xml.sax.SAXException;
++
++import javax.xml.namespace.QName;
++import javax.xml.parsers.DocumentBuilder;
++import javax.xml.parsers.DocumentBuilderFactory;
++import javax.xml.parsers.ParserConfigurationException;
++import javax.xml.xpath.XPath;
++import javax.xml.xpath.XPathExpression;
++import javax.xml.xpath.XPathExpressionException;
++import javax.xml.xpath.XPathFactory;
++import java.io.IOException;
++import java.io.InputStream;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class XPathProcessor {
++ private static final DocumentBuilderFactory DOCUMENT_FACTORY = DocumentBuilderFactory.newInstance();
++ private static final DocumentBuilder DOCUMENT_BUILDER;
++
++ private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
++ private static final XPath XPATH = XPATH_FACTORY.newXPath();
++
++ static {
++ DOCUMENT_FACTORY.setNamespaceAware(true);
++ try {
++ DOCUMENT_BUILDER = DOCUMENT_FACTORY.newDocumentBuilder();
++ } catch (ParserConfigurationException e) {
++ throw new IllegalStateException(e);
++ }
++ }
++
++ private final Document doc;
++
++ public XPathProcessor(InputStream is) {
++ try {
++ doc = DOCUMENT_BUILDER.parse(is);
++ } catch (SAXException | IOException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ public static synchronized XPathExpression getExpression(String exp) {
++ try {
++ return XPATH.compile(exp);
++ } catch (XPathExpressionException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++
++ public T evaluate(XPathExpression expression, QName type) {
++ try {
++ return (T) expression.evaluate(doc, type);
++ } catch (XPathExpressionException e) {
++ throw new IllegalArgumentException(e);
++ }
++ }
++}
+Index: src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision )
++++ src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision )
+@@ -0,0 +1,30 @@
++package ru.javaops.masterjava.xml.util;
++
++import com.google.common.io.Resources;
++import org.junit.Test;
++import org.w3c.dom.NodeList;
++
++import javax.xml.xpath.XPathConstants;
++import javax.xml.xpath.XPathExpression;
++import java.io.InputStream;
++import java.util.stream.IntStream;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class XPathProcessorTest {
++ @Test
++ public void getCities() throws Exception {
++ try (InputStream is =
++ Resources.getResource("payload.xml").openStream()) {
++ XPathProcessor processor = new XPathProcessor(is);
++ XPathExpression expression =
++ XPathProcessor.getExpression("/*[name()='Payload']/*[name()='Cities']/*[name()='City']/text()");
++ NodeList nodes = processor.evaluate(expression, XPathConstants.NODESET);
++ IntStream.range(0, nodes.getLength()).forEach(
++ i -> System.out.println(nodes.item(i).getNodeValue())
++ );
++ }
++ }
++}
+\ No newline at end of file
diff --git a/patches/lesson02/2_10_Xslt.patch b/patches/lesson02/2_10_Xslt.patch
new file mode 100644
index 000000000..bf72e67b2
--- /dev/null
+++ b/patches/lesson02/2_10_Xslt.patch
@@ -0,0 +1,104 @@
+Index: src/main/resources/cities.xsl
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/resources/cities.xsl (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
++++ src/main/resources/cities.xsl (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
+@@ -0,0 +1,9 @@
++
++
++
++
++
++
++
++
++
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
++++ src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
+@@ -0,0 +1,48 @@
++package ru.javaops.masterjava.xml.util;
++
++import javax.xml.transform.*;
++import javax.xml.transform.stream.StreamResult;
++import javax.xml.transform.stream.StreamSource;
++import java.io.*;
++import java.nio.charset.StandardCharsets;
++
++/**
++ * User: GKislin
++ * Date: 18.05.2009
++ */
++
++public class XsltProcessor {
++ private static TransformerFactory FACTORY = TransformerFactory.newInstance();
++ private final Transformer xformer;
++
++ public XsltProcessor(InputStream xslInputStream) {
++ this(new BufferedReader(new InputStreamReader(xslInputStream, StandardCharsets.UTF_8)));
++ }
++
++ public XsltProcessor(Reader xslReader) {
++ try {
++ Templates template = FACTORY.newTemplates(new StreamSource(xslReader));
++ xformer = template.newTransformer();
++ } catch (TransformerConfigurationException e) {
++ throw new IllegalStateException("XSLT transformer creation failed: " + e.toString(), e);
++ }
++ }
++
++ public String transform(InputStream xmlInputStream) throws TransformerException {
++ StringWriter out = new StringWriter();
++ transform(xmlInputStream, out);
++ return out.getBuffer().toString();
++ }
++
++ public void transform(InputStream xmlInputStream, Writer result) throws TransformerException {
++ transform(new BufferedReader(new InputStreamReader(xmlInputStream, StandardCharsets.UTF_8)), result);
++ }
++
++ public void transform(Reader sourceReader, Writer result) throws TransformerException {
++ xformer.transform(new StreamSource(sourceReader), new StreamResult(result));
++ }
++
++ public static String getXsltHeader(String xslt) {
++ return "\n";
++ }
++}
+Index: src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
++++ src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision 78baa61bd953eda6b18fb8d08f54646375549d66)
+@@ -0,0 +1,22 @@
++package ru.javaops.masterjava.xml.util;
++
++import com.google.common.io.Resources;
++import org.junit.Test;
++
++import java.io.InputStream;
++
++/**
++ * gkislin
++ * 23.09.2016
++ */
++public class XsltProcessorTest {
++ @Test
++ public void transform() throws Exception {
++ try (InputStream xslInputStream = Resources.getResource("cities.xsl").openStream();
++ InputStream xmlInputStream = Resources.getResource("payload.xml").openStream()) {
++
++ XsltProcessor processor = new XsltProcessor(xslInputStream);
++ System.out.println(processor.transform(xmlInputStream));
++ }
++ }
++}
diff --git a/patches/lesson03/3_1_HW2_schema.patch b/patches/lesson03/3_1_HW2_schema.patch
new file mode 100644
index 000000000..7b0bf03a5
--- /dev/null
+++ b/patches/lesson03/3_1_HW2_schema.patch
@@ -0,0 +1,782 @@
+Index: src/main/resources/payload.xsd
+===================================================================
+--- src/main/resources/payload.xsd (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1)
++++ src/main/resources/payload.xsd (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -6,7 +6,14 @@
+
+
+
+-
++
++
++
++
++
++
++
++
+
+
+
+@@ -21,18 +28,39 @@
+
+
+
+-
++
+
+
+
+-
++
+
+
+-
+-
++
++
++
++
++
++
++
++
++
+
+-
+-
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+
+
+
+@@ -44,7 +72,13 @@
+
+
+
+-
++
++
++
++
++
++
++
+
+
+
+@@ -53,4 +87,11 @@
+
+
+
++
++
++
++
++
++
++
+
+\ No newline at end of file
+Index: src/test/resources/payload.xml
+===================================================================
+--- src/test/resources/payload.xml (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1)
++++ src/test/resources/payload.xml (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -1,23 +1,31 @@
+
+-
+-
+- gmail@gmail.com
+- Full Name
+-
+-
+- admin@javaops.ru
+- Admin
+-
+-
+- mail@yandex.ru
+- Deleted
+-
+-
++
++
++
++ Topjava
++
++
++
++
++
++ Masterjava
++
++
++
+
+ Санкт-Петербург
++ Москва
+ Киев
+ Минск
+
++
++ Full Name
++ Admin
++ Deleted
++ User1
++ User2
++ User3
++
+
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1)
++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -1,14 +1,16 @@
+
+ package ru.javaops.masterjava.xml.schema;
+
++import java.util.ArrayList;
++import java.util.List;
+ import javax.xml.bind.annotation.XmlAccessType;
+ import javax.xml.bind.annotation.XmlAccessorType;
+ import javax.xml.bind.annotation.XmlAttribute;
+-import javax.xml.bind.annotation.XmlElement;
+ import javax.xml.bind.annotation.XmlIDREF;
+ import javax.xml.bind.annotation.XmlRootElement;
+ import javax.xml.bind.annotation.XmlSchemaType;
+ import javax.xml.bind.annotation.XmlType;
++import javax.xml.bind.annotation.XmlValue;
+
+
+ /**
+@@ -18,16 +20,14 @@
+ *
+ *
+ * <complexType>
+- * <complexContent>
+- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+- * <sequence>
+- * <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
+- * <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+- * </sequence>
++ * <simpleContent>
++ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
++ * <attribute name="email" type="{http://javaops.ru}emailAddressType" />
+ * <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+ * <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
+- * </restriction>
+- * </complexContent>
++ * <attribute name="groupRefs" type="{http://www.w3.org/2001/XMLSchema}IDREFS" />
++ * </extension>
++ * </simpleContent>
+ * </complexType>
+ *
+ *
+@@ -35,69 +35,72 @@
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+- "email",
+- "fullName"
++ "value"
+ })
+ @XmlRootElement(name = "User", namespace = "http://javaops.ru")
+ public class User {
+
+- @XmlElement(namespace = "http://javaops.ru", required = true)
++ @XmlValue
++ protected String value;
++ @XmlAttribute(name = "email")
+ protected String email;
+- @XmlElement(namespace = "http://javaops.ru", required = true)
+- protected String fullName;
+ @XmlAttribute(name = "flag", required = true)
+ protected FlagType flag;
+ @XmlAttribute(name = "city", required = true)
+ @XmlIDREF
+ @XmlSchemaType(name = "IDREF")
+ protected Object city;
++ @XmlAttribute(name = "groupRefs")
++ @XmlIDREF
++ @XmlSchemaType(name = "IDREFS")
++ protected List groupRefs;
+
+ /**
+- * Gets the value of the email property.
++ * Gets the value of the value property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+- public String getEmail() {
+- return email;
++ public String getValue() {
++ return value;
+ }
+
+ /**
+- * Sets the value of the email property.
++ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+- public void setEmail(String value) {
+- this.email = value;
++ public void setValue(String value) {
++ this.value = value;
+ }
+
+ /**
+- * Gets the value of the fullName property.
++ * Gets the value of the email property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+- public String getFullName() {
+- return fullName;
++ public String getEmail() {
++ return email;
+ }
+
+ /**
+- * Sets the value of the fullName property.
++ * Sets the value of the email property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+- public void setFullName(String value) {
+- this.fullName = value;
++ public void setEmail(String value) {
++ this.email = value;
+ }
+
+ /**
+@@ -148,4 +151,33 @@
+ this.city = value;
+ }
+
++ /**
++ * Gets the value of the groupRefs property.
++ *
++ *
++ * This accessor method returns a reference to the live list,
++ * not a snapshot. Therefore any modification you make to the
++ * returned list will be present inside the JAXB object.
++ * This is why there is not a set method for the groupRefs property.
++ *
++ *
++ * For example, to add a new item, do as follows:
++ *
++ * getGroupRefs().add(newItem);
++ *
++ *
++ *
++ *
++ * Objects of the following type(s) are allowed in the list
++ * {@link Object }
++ *
++ *
++ */
++ public List getGroupRefs() {
++ if (groupRefs == null) {
++ groupRefs = new ArrayList();
++ }
++ return this.groupRefs;
++ }
++
+ }
+Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1)
++++ src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -19,7 +19,18 @@
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+- * <all>
++ * <sequence>
++ * <element name="Projects">
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <sequence maxOccurs="unbounded">
++ * <element ref="{http://javaops.ru}Project"/>
++ * </sequence>
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ * </element>
+ * <element name="Cities">
+ * <complexType>
+ * <complexContent>
+@@ -42,7 +53,7 @@
+ * </complexContent>
+ * </complexType>
+ * </element>
+- * </all>
++ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+@@ -52,16 +63,44 @@
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+-
++ "projects",
++ "cities",
++ "users"
+ })
+ @XmlRootElement(name = "Payload", namespace = "http://javaops.ru")
+ public class Payload {
+
++ @XmlElement(name = "Projects", namespace = "http://javaops.ru", required = true)
++ protected Payload.Projects projects;
+ @XmlElement(name = "Cities", namespace = "http://javaops.ru", required = true)
+ protected Payload.Cities cities;
+ @XmlElement(name = "Users", namespace = "http://javaops.ru", required = true)
+ protected Payload.Users users;
+
++ /**
++ * Gets the value of the projects property.
++ *
++ * @return
++ * possible object is
++ * {@link Payload.Projects }
++ *
++ */
++ public Payload.Projects getProjects() {
++ return projects;
++ }
++
++ /**
++ * Sets the value of the projects property.
++ *
++ * @param value
++ * allowed object is
++ * {@link Payload.Projects }
++ *
++ */
++ public void setProjects(Payload.Projects value) {
++ this.projects = value;
++ }
++
+ /**
+ * Gets the value of the cities property.
+ *
+@@ -171,6 +210,66 @@
+ }
+
+
++ /**
++ * Java class for anonymous complex type.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <sequence maxOccurs="unbounded">
++ * <element ref="{http://javaops.ru}Project"/>
++ * </sequence>
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ *
++ *
++ *
++ */
++ @XmlAccessorType(XmlAccessType.FIELD)
++ @XmlType(name = "", propOrder = {
++ "project"
++ })
++ public static class Projects {
++
++ @XmlElement(name = "Project", namespace = "http://javaops.ru", required = true)
++ protected List project;
++
++ /**
++ * Gets the value of the project property.
++ *
++ *
++ * This accessor method returns a reference to the live list,
++ * not a snapshot. Therefore any modification you make to the
++ * returned list will be present inside the JAXB object.
++ * This is why there is not a set method for the project property.
++ *
++ *
++ * For example, to add a new item, do as follows:
++ *
++ * getProject().add(newItem);
++ *
++ *
++ *
++ *
++ * Objects of the following type(s) are allowed in the list
++ * {@link Project }
++ *
++ *
++ */
++ public List getProject() {
++ if (project == null) {
++ project = new ArrayList();
++ }
++ return this.project;
++ }
++
++ }
++
++
+ /**
+ * Java class for anonymous complex type.
+ *
+Index: src/main/java/ru/javaops/masterjava/xml/schema/Project.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
++++ src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -0,0 +1,223 @@
++
++package ru.javaops.masterjava.xml.schema;
++
++import java.util.ArrayList;
++import java.util.List;
++import javax.xml.bind.annotation.XmlAccessType;
++import javax.xml.bind.annotation.XmlAccessorType;
++import javax.xml.bind.annotation.XmlAttribute;
++import javax.xml.bind.annotation.XmlElement;
++import javax.xml.bind.annotation.XmlID;
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlSchemaType;
++import javax.xml.bind.annotation.XmlType;
++import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
++import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
++
++
++/**
++ *
Java class for anonymous complex type.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <sequence>
++ * <element name="description" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ * <sequence maxOccurs="unbounded">
++ * <element name="Group">
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++ * <attribute name="type" use="required" type="{http://javaops.ru}groupType" />
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ * </element>
++ * </sequence>
++ * </sequence>
++ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ *
++ *
++ *
++ */
++@XmlAccessorType(XmlAccessType.FIELD)
++@XmlType(name = "", propOrder = {
++ "description",
++ "group"
++})
++@XmlRootElement(name = "Project", namespace = "http://javaops.ru")
++public class Project {
++
++ @XmlElement(namespace = "http://javaops.ru", required = true)
++ protected String description;
++ @XmlElement(name = "Group", namespace = "http://javaops.ru", required = true)
++ protected List group;
++ @XmlAttribute(name = "name", required = true)
++ protected String name;
++
++ /**
++ * Gets the value of the description property.
++ *
++ * @return
++ * possible object is
++ * {@link String }
++ *
++ */
++ public String getDescription() {
++ return description;
++ }
++
++ /**
++ * Sets the value of the description property.
++ *
++ * @param value
++ * allowed object is
++ * {@link String }
++ *
++ */
++ public void setDescription(String value) {
++ this.description = value;
++ }
++
++ /**
++ * Gets the value of the group property.
++ *
++ *
++ * This accessor method returns a reference to the live list,
++ * not a snapshot. Therefore any modification you make to the
++ * returned list will be present inside the JAXB object.
++ * This is why there is not a set method for the group property.
++ *
++ *
++ * For example, to add a new item, do as follows:
++ *
++ * getGroup().add(newItem);
++ *
++ *
++ *
++ *
++ * Objects of the following type(s) are allowed in the list
++ * {@link Project.Group }
++ *
++ *
++ */
++ public List getGroup() {
++ if (group == null) {
++ group = new ArrayList();
++ }
++ return this.group;
++ }
++
++ /**
++ * Gets the value of the name property.
++ *
++ * @return
++ * possible object is
++ * {@link String }
++ *
++ */
++ public String getName() {
++ return name;
++ }
++
++ /**
++ * Sets the value of the name property.
++ *
++ * @param value
++ * allowed object is
++ * {@link String }
++ *
++ */
++ public void setName(String value) {
++ this.name = value;
++ }
++
++
++ /**
++ * Java class for anonymous complex type.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <complexType>
++ * <complexContent>
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++ * <attribute name="type" use="required" type="{http://javaops.ru}groupType" />
++ * </restriction>
++ * </complexContent>
++ * </complexType>
++ *
++ *
++ *
++ */
++ @XmlAccessorType(XmlAccessType.FIELD)
++ @XmlType(name = "")
++ public static class Group {
++
++ @XmlAttribute(name = "name", required = true)
++ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
++ @XmlID
++ @XmlSchemaType(name = "ID")
++ protected String name;
++ @XmlAttribute(name = "type", required = true)
++ protected GroupType type;
++
++ /**
++ * Gets the value of the name property.
++ *
++ * @return
++ * possible object is
++ * {@link String }
++ *
++ */
++ public String getName() {
++ return name;
++ }
++
++ /**
++ * Sets the value of the name property.
++ *
++ * @param value
++ * allowed object is
++ * {@link String }
++ *
++ */
++ public void setName(String value) {
++ this.name = value;
++ }
++
++ /**
++ * Gets the value of the type property.
++ *
++ * @return
++ * possible object is
++ * {@link GroupType }
++ *
++ */
++ public GroupType getType() {
++ return type;
++ }
++
++ /**
++ * Sets the value of the type property.
++ *
++ * @param value
++ * allowed object is
++ * {@link GroupType }
++ *
++ */
++ public void setType(GroupType value) {
++ this.type = value;
++ }
++
++ }
++
++}
+Index: src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
++++ src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -0,0 +1,40 @@
++
++package ru.javaops.masterjava.xml.schema;
++
++import javax.xml.bind.annotation.XmlEnum;
++import javax.xml.bind.annotation.XmlType;
++
++
++/**
++ * Java class for groupType.
++ *
++ *
The following schema fragment specifies the expected content contained within this class.
++ *
++ *
++ * <simpleType name="groupType">
++ * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
++ * <enumeration value="REGISTERING"/>
++ * <enumeration value="CURRENT"/>
++ * <enumeration value="FINISHED"/>
++ * </restriction>
++ * </simpleType>
++ *
++ *
++ */
++@XmlType(name = "groupType", namespace = "http://javaops.ru")
++@XmlEnum
++public enum GroupType {
++
++ REGISTERING,
++ CURRENT,
++ FINISHED;
++
++ public String value() {
++ return name();
++ }
++
++ public static GroupType fromValue(String v) {
++ return valueOf(v);
++ }
++
++}
+Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision e0b2ede116e7c716eb20c76d3f60619e5c13d2f1)
++++ src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision 5ab4c7a3f9b57db0d4de9671450d9a457dcd738e)
+@@ -33,6 +33,14 @@
+ public ObjectFactory() {
+ }
+
++ /**
++ * Create an instance of {@link Project }
++ *
++ */
++ public Project createProject() {
++ return new Project();
++ }
++
+ /**
+ * Create an instance of {@link Payload }
+ *
+@@ -41,6 +49,14 @@
+ return new Payload();
+ }
+
++ /**
++ * Create an instance of {@link Project.Group }
++ *
++ */
++ public Project.Group createProjectGroup() {
++ return new Project.Group();
++ }
++
+ /**
+ * Create an instance of {@link User }
+ *
+@@ -49,6 +65,14 @@
+ return new User();
+ }
+
++ /**
++ * Create an instance of {@link Payload.Projects }
++ *
++ */
++ public Payload.Projects createPayloadProjects() {
++ return new Payload.Projects();
++ }
++
+ /**
+ * Create an instance of {@link Payload.Cities }
+ *
diff --git a/patches/lesson03/3_2_HW2_JAXB_HTML.patch b/patches/lesson03/3_2_HW2_JAXB_HTML.patch
new file mode 100644
index 000000000..9f7279b70
--- /dev/null
+++ b/patches/lesson03/3_2_HW2_JAXB_HTML.patch
@@ -0,0 +1,179 @@
+Index: src/test/java/ru/javaops/masterjava/MainXml.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/MainXml.java (revision )
++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision )
+@@ -0,0 +1,81 @@
++package ru.javaops.masterjava;
++
++import com.google.common.io.Resources;
++import j2html.tags.ContainerTag;
++import one.util.streamex.StreamEx;
++import ru.javaops.masterjava.xml.schema.ObjectFactory;
++import ru.javaops.masterjava.xml.schema.Payload;
++import ru.javaops.masterjava.xml.schema.Project;
++import ru.javaops.masterjava.xml.schema.User;
++import ru.javaops.masterjava.xml.util.JaxbParser;
++import ru.javaops.masterjava.xml.util.Schemas;
++
++import java.io.InputStream;
++import java.io.Writer;
++import java.net.URL;
++import java.nio.file.Files;
++import java.nio.file.Paths;
++import java.util.*;
++import java.util.stream.Collectors;
++
++import static j2html.TagCreator.*;
++
++
++/**
++ * User: gkislin
++ */
++public class MainXml {
++ private static final Comparator USER_COMPARATOR = Comparator.comparing(User::getValue).thenComparing(User::getEmail);
++
++ public static void main(String[] args) throws Exception {
++ if (args.length != 1) {
++ System.out.println("Format: projectName");
++ System.exit(1);
++ }
++ String projectName = args[0];
++ URL payloadUrl = Resources.getResource("payload.xml");
++
++ Set users = parseByJaxb(projectName, payloadUrl);
++ users.forEach(System.out::println);
++
++ String html = toHtml(users, projectName);
++ System.out.println(html);
++ try (Writer writer = Files.newBufferedWriter(Paths.get("out/users.html"))) {
++ writer.write(html);
++ }
++ }
++
++ private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception {
++ JaxbParser parser = new JaxbParser(ObjectFactory.class);
++ parser.setSchema(Schemas.ofClasspath("payload.xsd"));
++ Payload payload;
++ try (InputStream is = payloadUrl.openStream()) {
++ payload = parser.unmarshal(is);
++ }
++
++ Project project = StreamEx.of(payload.getProjects().getProject())
++ .filter(p -> p.getName().equals(projectName))
++ .findAny()
++ .orElseThrow(() -> new IllegalArgumentException("Invalid project name '" + projectName + '\''));
++
++ final Set groups = new HashSet<>(project.getGroup()); // identity compare
++ return StreamEx.of(payload.getUsers().getUser())
++ .filter(u -> !Collections.disjoint(groups, u.getGroupRefs()))
++ .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR)));
++ }
++
++ private static String toHtml(Set users, String projectName) {
++ final ContainerTag table = table().with(
++ tr().with(th("FullName"), th("email")))
++ .attr("border", "1")
++ .attr("cellpadding", "8")
++ .attr("cellspacing", "0");
++
++ users.forEach(u -> table.with(tr().with(td(u.getValue()), td(u.getEmail()))));
++
++ return html().with(
++ head().with(title(projectName + " users")),
++ body().with(h1(projectName + " users"), table)
++ ).render();
++ }
++}
+Index: out/placeholder
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- out/placeholder (revision )
++++ out/placeholder (revision )
+@@ -0,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/Main.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/Main.java (date 1489369117000)
++++ src/main/java/ru/javaops/masterjava/Main.java (date 1489369117000)
+@@ -1,14 +0,0 @@
+-package ru.javaops.masterjava;
+-
+-/**
+- * User: gkislin
+- * Date: 05.08.2015
+- *
+- * @link http://caloriesmng.herokuapp.com/
+- * @link https://github.com/JavaOPs/topjava
+- */
+-public class Main {
+- public static void main(String[] args) {
+- System.out.format("Hello MasterJava!");
+- }
+-}
+Index: pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- pom.xml (date 1489369117000)
++++ pom.xml (revision )
+@@ -94,6 +94,19 @@
+ 21.0
+
+
++ one.util
++ streamex
++ RELEASE
++
++
++
++ com.j2html
++ j2html
++ RELEASE
++
++
++
++
+ junit
+ junit
+ 4.12
+Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (date 1489369117000)
++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision )
+@@ -1,16 +1,9 @@
+
+ package ru.javaops.masterjava.xml.schema;
+
++import javax.xml.bind.annotation.*;
+ import java.util.ArrayList;
+ import java.util.List;
+-import javax.xml.bind.annotation.XmlAccessType;
+-import javax.xml.bind.annotation.XmlAccessorType;
+-import javax.xml.bind.annotation.XmlAttribute;
+-import javax.xml.bind.annotation.XmlIDREF;
+-import javax.xml.bind.annotation.XmlRootElement;
+-import javax.xml.bind.annotation.XmlSchemaType;
+-import javax.xml.bind.annotation.XmlType;
+-import javax.xml.bind.annotation.XmlValue;
+
+
+ /**
+@@ -180,4 +173,10 @@
+ return this.groupRefs;
+ }
+
++ @Override
++ public String toString() {
++ return value + '(' + email + ')';
++ }
++
++
+ }
diff --git a/patches/lesson03/3_3_HW2_StAX.patch b/patches/lesson03/3_3_HW2_StAX.patch
new file mode 100644
index 000000000..1898adfe2
--- /dev/null
+++ b/patches/lesson03/3_3_HW2_StAX.patch
@@ -0,0 +1,127 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (date 1489431163000)
++++ src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision )
+@@ -24,15 +24,26 @@
+ }
+
+ public boolean doUntil(int stopEvent, String value) throws XMLStreamException {
++ return doUntilAny(stopEvent, value) != null;
++ }
++
++ public String getAttribute(String name) throws XMLStreamException {
++ return reader.getAttributeValue(null, name);
++ }
++
++ public String doUntilAny(int stopEvent, String... values) throws XMLStreamException {
+ while (reader.hasNext()) {
+ int event = reader.next();
+ if (event == stopEvent) {
+- if (value.equals(getValue(event))) {
+- return true;
++ String xmlValue = getValue(event);
++ for (String value : values) {
++ if (value.equals(xmlValue)) {
++ return xmlValue;
++ }
+ }
+ }
+ }
+- return false;
++ return null;
+ }
+
+ public String getValue(int event) throws XMLStreamException {
+Index: src/test/java/ru/javaops/masterjava/MainXml.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489431163000)
++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision )
+@@ -1,5 +1,6 @@
+ package ru.javaops.masterjava;
+
++import com.google.common.base.Splitter;
+ import com.google.common.io.Resources;
+ import j2html.tags.ContainerTag;
+ import one.util.streamex.StreamEx;
+@@ -9,7 +10,9 @@
+ import ru.javaops.masterjava.xml.schema.User;
+ import ru.javaops.masterjava.xml.util.JaxbParser;
+ import ru.javaops.masterjava.xml.util.Schemas;
++import ru.javaops.masterjava.xml.util.StaxStreamProcessor;
+
++import javax.xml.stream.events.XMLEvent;
+ import java.io.InputStream;
+ import java.io.Writer;
+ import java.net.URL;
+@@ -18,6 +21,7 @@
+ import java.util.*;
+ import java.util.stream.Collectors;
+
++import static com.google.common.base.Strings.nullToEmpty;
+ import static j2html.TagCreator.*;
+
+
+@@ -43,6 +47,10 @@
+ try (Writer writer = Files.newBufferedWriter(Paths.get("out/users.html"))) {
+ writer.write(html);
+ }
++
++ System.out.println();
++ users = processByStax(projectName, payloadUrl);
++ users.forEach(System.out::println);
+ }
+
+ private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception {
+@@ -64,6 +72,46 @@
+ .collect(Collectors.toCollection(() -> new TreeSet<>(USER_COMPARATOR)));
+ }
+
++ private static Set processByStax(String projectName, URL payloadUrl) throws Exception {
++
++ try (InputStream is = payloadUrl.openStream()) {
++ StaxStreamProcessor processor = new StaxStreamProcessor(is);
++ final Set groupNames = new HashSet<>();
++
++ // Projects loop
++ projects:
++ while (processor.doUntil(XMLEvent.START_ELEMENT, "Project")) {
++ if (projectName.equals(processor.getAttribute("name"))) {
++ // Groups loop
++ String element;
++ while ((element = processor.doUntilAny(XMLEvent.START_ELEMENT, "Project", "Group", "Users")) != null) {
++ if (!element.equals("Group")) {
++ break projects;
++ }
++ groupNames.add(processor.getAttribute("name"));
++ }
++ }
++ }
++ if (groupNames.isEmpty()) {
++ throw new IllegalArgumentException("Invalid " + projectName + " or no groups");
++ }
++
++ // Users loop
++ Set users = new TreeSet<>(USER_COMPARATOR);
++
++ while (processor.doUntil(XMLEvent.START_ELEMENT, "User")) {
++ String groupRefs = processor.getAttribute("groupRefs");
++ if (!Collections.disjoint(groupNames, Splitter.on(' ').splitToList(nullToEmpty(groupRefs)))) {
++ User user = new User();
++ user.setEmail(processor.getAttribute("email"));
++ user.setValue(processor.getText());
++ users.add(user);
++ }
++ }
++ return users;
++ }
++ }
++
+ private static String toHtml(Set users, String projectName) {
+ final ContainerTag table = table().with(
+ tr().with(th("FullName"), th("email")))
diff --git a/patches/lesson03/3_4_HW2_xslt.patch b/patches/lesson03/3_4_HW2_xslt.patch
new file mode 100644
index 000000000..19a0e9ce5
--- /dev/null
+++ b/patches/lesson03/3_4_HW2_xslt.patch
@@ -0,0 +1,102 @@
+Index: src/main/resources/groups.xsl
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/resources/groups.xsl (revision )
++++ src/main/resources/groups.xsl (revision )
+@@ -0,0 +1,36 @@
++
++
++
++
++
++
++
++
++ groups
++
++
++
++
++ groups
++
++
++
++ Group
++ Type
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (date 1489431506000)
++++ src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision )
+@@ -45,4 +45,8 @@
+ public static String getXsltHeader(String xslt) {
+ return "\n";
+ }
++
++ public void setParameter(String name, String value) {
++ xformer.setParameter(name, value);
++ }
+ }
+Index: src/test/java/ru/javaops/masterjava/MainXml.java
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489431506000)
++++ src/test/java/ru/javaops/masterjava/MainXml.java (revision )
+@@ -11,6 +11,7 @@
+ import ru.javaops.masterjava.xml.util.JaxbParser;
+ import ru.javaops.masterjava.xml.util.Schemas;
+ import ru.javaops.masterjava.xml.util.StaxStreamProcessor;
++import ru.javaops.masterjava.xml.util.XsltProcessor;
+
+ import javax.xml.stream.events.XMLEvent;
+ import java.io.InputStream;
+@@ -51,6 +52,11 @@
+ System.out.println();
+ users = processByStax(projectName, payloadUrl);
+ users.forEach(System.out::println);
++
++ html = transform(projectName, payloadUrl);
++ try (Writer writer = Files.newBufferedWriter(Paths.get("out/groups.html"))) {
++ writer.write(html);
++ }
+ }
+
+ private static Set parseByJaxb(String projectName, URL payloadUrl) throws Exception {
+@@ -126,4 +132,13 @@
+ body().with(h1(projectName + " users"), table)
+ ).render();
+ }
++
++ private static String transform(String projectName, URL payloadUrl) throws Exception {
++ URL xsl = Resources.getResource("groups.xsl");
++ try (InputStream xmlStream = payloadUrl.openStream(); InputStream xslStream = xsl.openStream()) {
++ XsltProcessor processor = new XsltProcessor(xslStream);
++ processor.setParameter("projectName", projectName);
++ return processor.transform(xmlStream);
++ }
++ }
+ }
diff --git a/patches/lesson03/3_5_multimodule.patch b/patches/lesson03/3_5_multimodule.patch
new file mode 100644
index 000000000..c558ac2d8
--- /dev/null
+++ b/patches/lesson03/3_5_multimodule.patch
@@ -0,0 +1,294 @@
+Index: export/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- export/pom.xml (revision )
++++ export/pom.xml (revision )
+@@ -0,0 +1,39 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent
++ ../parent/pom.xml
++ 1.0-SNAPSHOT
++
++
++ export
++ 1.0-SNAPSHOT
++ war
++ Export
++
++
++
++
++ org.apache.maven.plugins
++ maven-war-plugin
++ 3.0.0
++
++ false
++
++
++
++
++
++
++
++ ru.javaops
++ common
++ ${project.version}
++
++
++
+\ No newline at end of file
+Index: parent/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- parent/pom.xml (revision )
++++ parent/pom.xml (revision )
+@@ -0,0 +1,69 @@
++
++
++ 4.0.0
++
++ ru.javaops
++ parent
++ pom
++ 1.0-SNAPSHOT
++ Parent
++
++
++ 1.8
++ UTF-8
++ UTF-8
++
++
++
++ install
++
++
++ org.apache.maven.plugins
++ maven-compiler-plugin
++ 3.1
++
++ ${java.version}
++ ${java.version}
++
++
++
++ org.apache.maven.plugins
++ maven-surefire-plugin
++ 2.19.1
++
++ -Dfile.encoding=UTF-8
++
++
++
++
++
++
++
++ com.google.guava
++ guava
++ 21.0
++
++
++ one.util
++ streamex
++ RELEASE
++
++
++
++
++ junit
++ junit
++ 4.12
++ test
++
++
++
++
++
++
++
++
++
++
+\ No newline at end of file
+Index: common/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- common/pom.xml (revision )
++++ common/pom.xml (revision )
+@@ -0,0 +1,21 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent
++ ../parent/pom.xml
++ 1.0-SNAPSHOT
++
++
++ common
++ 1.0-SNAPSHOT
++ jar
++ Common
++
++
++
++
+\ No newline at end of file
+Index: pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- pom.xml (date 1489432214000)
++++ pom.xml (revision )
+@@ -4,119 +4,22 @@
+
+ ru.javaops
+ masterjava
+- jar
++ pom
+
+ 1.0-SNAPSHOT
+
+ Master Java
+ https://github.com/JavaOPs/masterjava
+
+-
+- 1.8
+- UTF-8
+- UTF-8
+-
++
++ export
++ common
+
+-
+- masterjava
+- install
+-
+-
+- org.apache.maven.plugins
+- maven-compiler-plugin
+- 3.1
+-
+- ${java.version}
+- ${java.version}
+-
+-
+-
+- org.apache.maven.plugins
+- maven-surefire-plugin
+- 2.19.1
+-
+- -Dfile.encoding=UTF-8
+-
+-
+-
+- org.apache.maven.plugins
+- maven-shade-plugin
+- 2.2
+-
+-
+- package
+-
+- shade
+-
+-
+- benchmarks
+-
+-
+- org.openjdk.jmh.Main
+-
+-
+-
+-
+-
+- *:*
+-
+- META-INF/*.SF
+- META-INF/*.DSA
+- META-INF/*.RSA
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+- org.openjdk.jmh
+- jmh-core
+- RELEASE
+-
+-
+- org.openjdk.jmh
+- jmh-generator-annprocess
+- RELEASE
+- provided
+-
+-
+- com.google.guava
+- guava
+- 21.0
+-
+-
+- one.util
+- streamex
+- RELEASE
+-
+-
+-
+- com.j2html
+- j2html
+- RELEASE
+-
+-
+-
+-
+- junit
+- junit
+- 4.12
+- test
+-
+-
+-
+-
+-
+-
+-
+-
++
++
+
diff --git a/patches/lesson04/4_1_HW3_pom_structure.patch b/patches/lesson04/4_1_HW3_pom_structure.patch
new file mode 100644
index 000000000..a48d1f546
--- /dev/null
+++ b/patches/lesson04/4_1_HW3_pom_structure.patch
@@ -0,0 +1,490 @@
+Index: services/mail-api/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- services/mail-api/pom.xml (revision )
++++ services/mail-api/pom.xml (revision )
+@@ -0,0 +1,26 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent
++ ../../parent/pom.xml
++ 1.0-SNAPSHOT
++
++
++ mail-api
++ 1.0-SNAPSHOT
++ Mail API
++
++
++
++ ${project.groupId}
++ common
++ ${project.version}
++
++
++
++
+\ No newline at end of file
+Index: web/webapp/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- web/webapp/pom.xml (revision )
++++ web/webapp/pom.xml (revision )
+@@ -0,0 +1,26 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent-web
++ ../../parent-web/pom.xml
++ 1.0-SNAPSHOT
++
++
++ webapp
++ 1.0-SNAPSHOT
++ war
++ WebApp
++
++
++
++ ${project.groupId}
++ common
++ ${project.version}
++
++
++
+\ No newline at end of file
+Index: web/export/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- web/export/pom.xml (revision )
++++ web/export/pom.xml (revision )
+@@ -0,0 +1,31 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent-web
++ ../../parent-web/pom.xml
++ 1.0-SNAPSHOT
++
++
++ export
++ 1.0-SNAPSHOT
++ war
++ Export
++
++
++ export
++
++
++
++
++ com.j2html
++ j2html
++ 0.7
++
++
++
++
+\ No newline at end of file
+Index: web/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- web/pom.xml (revision )
++++ web/pom.xml (revision )
+@@ -0,0 +1,15 @@
++
++ 4.0.0
++
++ ru.javaops
++ web
++ pom
++ 1.0-SNAPSHOT
++ MasterJava Web
++
++
++ export
++ webapp
++
++
+Index: services/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- services/pom.xml (revision )
++++ services/pom.xml (revision )
+@@ -0,0 +1,15 @@
++
++ 4.0.0
++
++ ru.javaops
++ services
++ pom
++ 1.0-SNAPSHOT
++
++ MasterJava Services
++
++ mail-api
++ mail-service
++
++
+Index: test/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- test/pom.xml (revision )
++++ test/pom.xml (revision )
+@@ -0,0 +1,76 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent
++ ../parent/pom.xml
++ 1.0-SNAPSHOT
++
++
++ test
++ 1.0-SNAPSHOT
++ Test
++
++
++
++
++ org.apache.maven.plugins
++ maven-shade-plugin
++ 2.2
++
++
++ package
++
++ shade
++
++
++ benchmarks
++
++
++ org.openjdk.jmh.Main
++
++
++
++
++
++ *:*
++
++ META-INF/*.SF
++ META-INF/*.DSA
++ META-INF/*.RSA
++
++
++
++
++
++
++
++
++
++
++
++ ${project.groupId}
++ common
++ ${project.version}
++
++
++ org.openjdk.jmh
++ jmh-core
++ RELEASE
++
++
++ org.openjdk.jmh
++ jmh-generator-annprocess
++ RELEASE
++ provided
++
++
++
+\ No newline at end of file
+Index: services/mail-service/pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- services/mail-service/pom.xml (revision )
++++ services/mail-service/pom.xml (revision )
+@@ -0,0 +1,26 @@
++
++
++ 4.0.0
++
++
++ ru.javaops
++ parent-web
++ ../../parent-web/pom.xml
++ 1.0-SNAPSHOT
++
++
++ mail-service
++ 1.0-SNAPSHOT
++ war
++ Mail Service
++
++
++
++ ${project.groupId}
++ mail-api
++ ${project.version}
++
++
++
+\ No newline at end of file
+Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (date 1489440274000)
++++ test/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (date 1489440274000)
++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (date 1489440274000)
++++ test/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/resources/groups.xsl
+===================================================================
+--- src/main/resources/groups.xsl (date 1489440274000)
++++ web/export/src/main/resources/groups.xsl (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (date 1489440274000)
++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/service/MailService.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/service/MailService.java (date 1489440274000)
++++ services/mail-service/src/main/java/ru/javaops/masterjava/service/mail/MailService.java (revision )
+@@ -1,4 +1,4 @@
+-package ru.javaops.masterjava.service;
++package ru.javaops.masterjava.service.mail;
+
+ import java.util.ArrayList;
+ import java.util.List;
+Index: src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/resources/cities.xsl
+===================================================================
+--- src/main/resources/cities.xsl (date 1489440274000)
++++ web/export/src/main/resources/cities.xsl (revision )
+@@ -1,0 +1,0 @@
+Index: pom.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- pom.xml (date 1489440274000)
++++ pom.xml (revision )
+@@ -8,18 +8,14 @@
+
+ 1.0-SNAPSHOT
+
+- Master Java
++ MasterJava Root
+ https://github.com/JavaOPs/masterjava
+
+
+- export
+ common
+-
+-
++
++ web
++ services
+
+
+Index: src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1489440274000)
++++ test/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/Schemas.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/Project.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/Project.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/Project.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (date 1489440274000)
++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java (revision )
+@@ -1,0 +1,0 @@
+Index: export/pom.xml
+===================================================================
+--- export/pom.xml (date 1489440274000)
++++ parent-web/pom.xml (revision )
+@@ -11,10 +11,10 @@
+ 1.0-SNAPSHOT
+
+
+- export
++ parent-web
++ pom
+ 1.0-SNAPSHOT
+- war
+- Export
++ Parent Web
+
+
+
+@@ -31,9 +31,16 @@
+
+
+
+- ru.javaops
+- common
+- ${project.version}
++ javax.servlet
++ javax.servlet-api
++ 3.1.0
++ provided
+
+
++
++
++
++
++
++
+
+\ No newline at end of file
+Index: src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java
+===================================================================
+--- src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (date 1489440274000)
++++ web/export/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/resources/payload.xsd
+===================================================================
+--- src/main/resources/payload.xsd (date 1489440274000)
++++ web/export/src/main/resources/payload.xsd (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/resources/city.xml
+===================================================================
+--- src/test/resources/city.xml (date 1489440274000)
++++ web/export/src/test/resources/city.xml (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/resources/payload.xml
+===================================================================
+--- src/test/resources/payload.xml (date 1489440274000)
++++ web/export/src/test/resources/payload.xml (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/test/java/ru/javaops/masterjava/MainXml.java
+===================================================================
+--- src/test/java/ru/javaops/masterjava/MainXml.java (date 1489440274000)
++++ web/export/src/test/java/ru/javaops/masterjava/MainXml.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/CityType.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision )
+@@ -1,0 +1,0 @@
+Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java
+===================================================================
+--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (date 1489440274000)
++++ web/export/src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision )
+@@ -1,0 +1,0 @@
diff --git a/patches/lesson04/4_2_HW3_thymeleaf_upload.patch b/patches/lesson04/4_2_HW3_thymeleaf_upload.patch
new file mode 100644
index 000000000..c42d4ff8b
--- /dev/null
+++ b/patches/lesson04/4_2_HW3_thymeleaf_upload.patch
@@ -0,0 +1,428 @@
+Index: web/export/src/main/webapp/WEB-INF/templates/exception.html
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- web/export/src/main/webapp/WEB-INF/templates/exception.html (revision )
++++ web/export/src/main/webapp/WEB-INF/templates/exception.html (revision )
+@@ -0,0 +1,19 @@
++
++
++
++ Export XML
++
++
++
++
++
++
++
Application error:
++
exception.message
++
++
++
++
++
+\ No newline at end of file
+Index: web/export/src/main/webapp/WEB-INF/templates/export.html
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
+<+>UTF-8
+===================================================================
+--- web/export/src/main/webapp/WEB-INF/templates/export.html (revision )
++++ web/export/src/main/webapp/WEB-INF/templates/export.html (revision )
+@@ -0,0 +1,16 @@
++
++
++ Export XML
++
++
++
++
++