> tasks = new ArrayList<>(matrixSize);
+ for (int j = 0; j < matrixSize; j++) {
+ final int row = j;
+ tasks.add(() -> {
+ final int[] rowC = new int[matrixSize];
+ for (int col = 0; col < matrixSize; col++) {
+ final int[] rowA = matrixA[row];
+ final int[] columnB = matrixBT[col];
+ int sum = 0;
+ for (int k = 0; k < matrixSize; k++) {
+ sum += rowA[k] * columnB[k];
+ }
+ rowC[col] = sum;
+ }
+ matrixC[row] = rowC;
+ return null;
+ });
+ }
+ executor.invokeAll(tasks);
+ return matrixC;
+ }
+
+ public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException {
+ final int matrixSize = matrixA.length;
+ final int[][] matrixC = new int[matrixSize][matrixSize];
+ final CountDownLatch latch = new CountDownLatch(matrixSize);
+
+ for (int row = 0; row < matrixSize; row++) {
+ final int[] rowA = matrixA[row];
+ final int[] rowC = matrixC[row];
+
+ executor.submit(() -> {
+ for (int idx = 0; idx < matrixSize; idx++) {
+ final int elA = rowA[idx];
+ final int[] rowB = matrixB[idx];
+ for (int col = 0; col < matrixSize; col++) {
+ rowC[col] += elA * rowB[col];
+ }
+ }
+ latch.countDown();
+ });
+ }
+ latch.await();
+ return matrixC;
+ }
+
+ public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) {
+ final int matrixSize = matrixA.length;
+ final int[][] matrixC = new int[matrixSize][matrixSize];
+
+ for (int col = 0; col < matrixSize; col++) {
+ final int[] columnB = new int[matrixSize];
+ for (int k = 0; k < matrixSize; k++) {
+ columnB[k] = matrixB[k][col];
+ }
+
+ for (int row = 0; row < matrixSize; row++) {
int sum = 0;
+ final int[] rowA = matrixA[row];
for (int k = 0; k < matrixSize; k++) {
- sum += matrixA[i][k] * matrixB[k][j];
+ sum += rowA[k] * columnB[k];
+ }
+ matrixC[row][col] = sum;
+ }
+ }
+ return matrixC;
+ }
+
+ public static int[][] singleThreadMultiplyOpt2(int[][] matrixA, int[][] matrixB) {
+ final int matrixSize = matrixA.length;
+ final int[][] matrixC = new int[matrixSize][matrixSize];
+
+ for (int row = 0; row < matrixSize; row++) {
+ final int[] rowA = matrixA[row];
+ final int[] rowC = matrixC[row];
+
+ for (int idx = 0; idx < matrixSize; idx++) {
+ final int elA = rowA[idx];
+ final int[] rowB = matrixB[idx];
+ for (int col = 0; col < matrixSize; col++) {
+ rowC[col] += elA * rowB[col];
}
- matrixC[i][j] = sum;
}
}
return matrixC;
@@ -58,4 +154,4 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) {
}
return true;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java
new file mode 100644
index 000000000..029e352cb
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java
@@ -0,0 +1,94 @@
+
+package ru.javaops.masterjava.xml.schema;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * Java class for cityType complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType name="cityType">
+ * <simpleContent>
+ * <extension base="<http://www.w3.org/2001/XMLSchema>string">
+ * <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * </extension>
+ * </simpleContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "cityType", namespace = "http://javaops.ru", propOrder = {
+ "value"
+})
+public class CityType {
+
+ @XmlValue
+ protected String value;
+ @XmlAttribute(name = "id", required = true)
+ @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+ @XmlID
+ @XmlSchemaType(name = "ID")
+ protected String id;
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setId(String value) {
+ this.id = value;
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java
new file mode 100644
index 000000000..eda39fa9a
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java
@@ -0,0 +1,54 @@
+
+package ru.javaops.masterjava.xml.schema;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for flagType.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <simpleType name="flagType">
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * <enumeration value="active"/>
+ * <enumeration value="deleted"/>
+ * <enumeration value="superuser"/>
+ * </restriction>
+ * </simpleType>
+ *
+ *
+ */
+@XmlType(name = "flagType", namespace = "http://javaops.ru")
+@XmlEnum
+public enum FlagType {
+
+ @XmlEnumValue("active")
+ ACTIVE("active"),
+ @XmlEnumValue("deleted")
+ DELETED("deleted"),
+ @XmlEnumValue("superuser")
+ SUPERUSER("superuser");
+ private final String value;
+
+ FlagType(String v) {
+ value = v;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public static FlagType fromValue(String v) {
+ for (FlagType c: FlagType.values()) {
+ if (c.value.equals(v)) {
+ return c;
+ }
+ }
+ throw new IllegalArgumentException(v);
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java
new file mode 100644
index 000000000..e8f105e2a
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java
@@ -0,0 +1,85 @@
+
+package ru.javaops.masterjava.xml.schema;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the ru.javaops.masterjava.xml.schema package.
+ * An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _City_QNAME = new QName("http://javaops.ru", "City");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ru.javaops.masterjava.xml.schema
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Payload }
+ *
+ */
+ public Payload createPayload() {
+ return new Payload();
+ }
+
+ /**
+ * Create an instance of {@link User }
+ *
+ */
+ public User createUser() {
+ return new User();
+ }
+
+ /**
+ * Create an instance of {@link Payload.Cities }
+ *
+ */
+ public Payload.Cities createPayloadCities() {
+ return new Payload.Cities();
+ }
+
+ /**
+ * Create an instance of {@link Payload.Users }
+ *
+ */
+ public Payload.Users createPayloadUsers() {
+ return new Payload.Users();
+ }
+
+ /**
+ * Create an instance of {@link CityType }
+ *
+ */
+ public CityType createCityType() {
+ return new CityType();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link CityType }{@code >}}
+ *
+ */
+ @XmlElementDecl(namespace = "http://javaops.ru", name = "City")
+ public JAXBElement createCity(CityType value) {
+ return new JAXBElement(_City_QNAME, CityType.class, null, value);
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java
new file mode 100644
index 000000000..2a6276490
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java
@@ -0,0 +1,233 @@
+
+package ru.javaops.masterjava.xml.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <all>
+ * <element name="Cities">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence maxOccurs="unbounded">
+ * <element ref="{http://javaops.ru}City"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * <element name="Users">
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence maxOccurs="unbounded" minOccurs="0">
+ * <element ref="{http://javaops.ru}User"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </element>
+ * </all>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+
+})
+@XmlRootElement(name = "Payload", namespace = "http://javaops.ru")
+public class Payload {
+
+ @XmlElement(name = "Cities", namespace = "http://javaops.ru", required = true)
+ protected Payload.Cities cities;
+ @XmlElement(name = "Users", namespace = "http://javaops.ru", required = true)
+ protected Payload.Users users;
+
+ /**
+ * Gets the value of the cities property.
+ *
+ * @return
+ * possible object is
+ * {@link Payload.Cities }
+ *
+ */
+ public Payload.Cities getCities() {
+ return cities;
+ }
+
+ /**
+ * Sets the value of the cities property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Payload.Cities }
+ *
+ */
+ public void setCities(Payload.Cities value) {
+ this.cities = value;
+ }
+
+ /**
+ * Gets the value of the users property.
+ *
+ * @return
+ * possible object is
+ * {@link Payload.Users }
+ *
+ */
+ public Payload.Users getUsers() {
+ return users;
+ }
+
+ /**
+ * Sets the value of the users property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Payload.Users }
+ *
+ */
+ public void setUsers(Payload.Users value) {
+ this.users = value;
+ }
+
+
+ /**
+ * Java class for anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence maxOccurs="unbounded">
+ * <element ref="{http://javaops.ru}City"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "city"
+ })
+ public static class Cities {
+
+ @XmlElement(name = "City", namespace = "http://javaops.ru", required = true)
+ protected List city;
+
+ /**
+ * Gets the value of the city property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set method for the city property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getCity().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link CityType }
+ *
+ *
+ */
+ public List getCity() {
+ if (city == null) {
+ city = new ArrayList();
+ }
+ return this.city;
+ }
+
+ }
+
+
+ /**
+ * Java class for anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence maxOccurs="unbounded" minOccurs="0">
+ * <element ref="{http://javaops.ru}User"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+ @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlType(name = "", propOrder = {
+ "user"
+ })
+ public static class Users {
+
+ @XmlElement(name = "User", namespace = "http://javaops.ru")
+ protected List user;
+
+ /**
+ * Gets the value of the user property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set method for the user property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getUser().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link User }
+ *
+ *
+ */
+ public List getUser() {
+ if (user == null) {
+ user = new ArrayList();
+ }
+ return this.user;
+ }
+
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java
new file mode 100644
index 000000000..b3430ce71
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java
@@ -0,0 +1,151 @@
+
+package ru.javaops.masterjava.xml.schema;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlIDREF;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
+ * <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "email",
+ "fullName"
+})
+@XmlRootElement(name = "User", namespace = "http://javaops.ru")
+public class User {
+
+ @XmlElement(namespace = "http://javaops.ru", required = true)
+ protected String email;
+ @XmlElement(namespace = "http://javaops.ru", required = true)
+ protected String fullName;
+ @XmlAttribute(name = "flag", required = true)
+ protected FlagType flag;
+ @XmlAttribute(name = "city", required = true)
+ @XmlIDREF
+ @XmlSchemaType(name = "IDREF")
+ protected Object city;
+
+ /**
+ * Gets the value of the email property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Sets the value of the email property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setEmail(String value) {
+ this.email = value;
+ }
+
+ /**
+ * Gets the value of the fullName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Sets the value of the fullName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setFullName(String value) {
+ this.fullName = value;
+ }
+
+ /**
+ * Gets the value of the flag property.
+ *
+ * @return
+ * possible object is
+ * {@link FlagType }
+ *
+ */
+ public FlagType getFlag() {
+ return flag;
+ }
+
+ /**
+ * Sets the value of the flag property.
+ *
+ * @param value
+ * allowed object is
+ * {@link FlagType }
+ *
+ */
+ public void setFlag(FlagType value) {
+ this.flag = value;
+ }
+
+ /**
+ * Gets the value of the city property.
+ *
+ * @return
+ * possible object is
+ * {@link Object }
+ *
+ */
+ public Object getCity() {
+ return city;
+ }
+
+ /**
+ * Sets the value of the city property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Object }
+ *
+ */
+ public void setCity(Object value) {
+ this.city = value;
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java
new file mode 100644
index 000000000..d6006800f
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java
@@ -0,0 +1,39 @@
+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;
+
+public class JaxbMarshaller {
+ private Marshaller marshaller;
+
+ public JaxbMarshaller(JAXBContext ctx) throws JAXBException {
+ marshaller = ctx.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
+ }
+
+ public void setProperty(String prop, Object value) throws PropertyException {
+ marshaller.setProperty(prop, value);
+ }
+
+ public synchronized void setSchema(Schema schema) {
+ marshaller.setSchema(schema);
+ }
+
+ public String marshal(Object instance) throws JAXBException {
+ StringWriter sw = new StringWriter();
+ marshal(instance, sw);
+ return sw.toString();
+ }
+
+ public synchronized void marshal(Object instance, Writer writer) throws JAXBException {
+ marshaller.marshal(instance, writer);
+ }
+
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java
new file mode 100644
index 000000000..b3a45f66c
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java
@@ -0,0 +1,88 @@
+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
+ */
+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 String marshal(Object instance) throws JAXBException {
+ return jaxbMarshaller.marshal(instance);
+ }
+
+ public void marshal(Object instance, Writer writer) throws JAXBException {
+ jaxbMarshaller.marshal(instance, writer);
+ }
+
+ public void setSchema(Schema schema) {
+ this.schema = schema;
+ jaxbUnmarshaller.setSchema(schema);
+ jaxbMarshaller.setSchema(schema);
+ }
+
+ public void validate(String str) throws IOException, SAXException {
+ validate(new StringReader(str));
+ }
+
+ public void validate(Reader reader) throws IOException, SAXException {
+ schema.newValidator().validate(new StreamSource(reader));
+ }
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java
new file mode 100644
index 000000000..7a3e13461
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java
@@ -0,0 +1,33 @@
+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;
+
+public class JaxbUnmarshaller {
+ private Unmarshaller unmarshaller;
+
+ public JaxbUnmarshaller(JAXBContext ctx) throws JAXBException {
+ unmarshaller = ctx.createUnmarshaller();
+ }
+
+ public synchronized void setSchema(Schema schema) {
+ unmarshaller.setSchema(schema);
+ }
+
+ public synchronized Object unmarshal(InputStream is) throws JAXBException {
+ return unmarshaller.unmarshal(is);
+ }
+
+ public synchronized Object unmarshal(Reader reader) throws JAXBException {
+ return unmarshaller.unmarshal(reader);
+ }
+
+ public Object unmarshal(String str) throws JAXBException {
+ return unmarshal(new StringReader(str));
+ }
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java b/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java
new file mode 100644
index 000000000..42f41df80
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/Schemas.java
@@ -0,0 +1,48 @@
+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;
+
+
+public class Schemas {
+
+ // SchemaFactory is not thread-safe
+ private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+ public static synchronized Schema ofString(String xsd) {
+ try {
+ return SCHEMA_FACTORY.newSchema(new StreamSource(new StringReader(xsd)));
+ } catch (SAXException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static synchronized Schema ofClasspath(String resource) {
+ // http://digitalsanctum.com/2012/11/30/how-to-read-file-contents-in-java-the-easy-way-with-guava/
+ return ofURL(Resources.getResource(resource));
+ }
+
+ public static synchronized Schema ofURL(URL url) {
+ try {
+ return SCHEMA_FACTORY.newSchema(url);
+ } catch (SAXException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static synchronized Schema ofFile(File file) {
+ try {
+ return SCHEMA_FACTORY.newSchema(file);
+ } catch (SAXException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java
new file mode 100644
index 000000000..921ca6aff
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java
@@ -0,0 +1,56 @@
+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;
+
+public class StaxStreamProcessor implements AutoCloseable {
+ private static final XMLInputFactory FACTORY = XMLInputFactory.newInstance();
+
+ private final XMLStreamReader reader;
+
+ public StaxStreamProcessor(InputStream is) throws XMLStreamException {
+ reader = FACTORY.createXMLStreamReader(is);
+ }
+
+ public XMLStreamReader getReader() {
+ return reader;
+ }
+
+ public boolean doUntil(int stopEvent, String value) throws XMLStreamException {
+ while (reader.hasNext()) {
+ int event = reader.next();
+ if (event == stopEvent) {
+ if (value.equals(getValue(event))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String getValue(int event) throws XMLStreamException {
+ return (event == XMLEvent.CHARACTERS) ? reader.getText() : reader.getLocalName();
+ }
+
+ public String getElementValue(String element) throws XMLStreamException {
+ return doUntil(XMLEvent.START_ELEMENT, element) ? reader.getElementText() : null;
+ }
+
+ public String getText() throws XMLStreamException {
+ return reader.getElementText();
+ }
+
+ @Override
+ public void close() {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (XMLStreamException e) {
+ // empty
+ }
+ }
+ }
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java
new file mode 100644
index 000000000..63baae5d1
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java
@@ -0,0 +1,58 @@
+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;
+
+public class XPathProcessor {
+ private static final DocumentBuilderFactory DOCUMENT_FACTORY = DocumentBuilderFactory.newInstance();
+ private static final DocumentBuilder DOCUMENT_BUILDER;
+
+ private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
+ private static final XPath XPATH = XPATH_FACTORY.newXPath();
+
+ static {
+ DOCUMENT_FACTORY.setNamespaceAware(true);
+ try {
+ DOCUMENT_BUILDER = DOCUMENT_FACTORY.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private final Document doc;
+
+ public XPathProcessor(InputStream is) {
+ try {
+ doc = DOCUMENT_BUILDER.parse(is);
+ } catch (SAXException | IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static synchronized XPathExpression getExpression(String exp) {
+ try {
+ return XPATH.compile(exp);
+ } catch (XPathExpressionException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public T evaluate(XPathExpression expression, QName type) {
+ try {
+ return (T) expression.evaluate(doc, type);
+ } catch (XPathExpressionException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java
new file mode 100644
index 000000000..019eeed3d
--- /dev/null
+++ b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java
@@ -0,0 +1,43 @@
+package ru.javaops.masterjava.xml.util;
+
+import javax.xml.transform.*;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+public class XsltProcessor {
+ private static TransformerFactory FACTORY = TransformerFactory.newInstance();
+ private final Transformer xformer;
+
+ public XsltProcessor(InputStream xslInputStream) {
+ this(new BufferedReader(new InputStreamReader(xslInputStream, StandardCharsets.UTF_8)));
+ }
+
+ public XsltProcessor(Reader xslReader) {
+ try {
+ Templates template = FACTORY.newTemplates(new StreamSource(xslReader));
+ xformer = template.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ throw new IllegalStateException("XSLT transformer creation failed: " + e.toString(), e);
+ }
+ }
+
+ public String transform(InputStream xmlInputStream) throws TransformerException {
+ StringWriter out = new StringWriter();
+ transform(xmlInputStream, out);
+ return out.getBuffer().toString();
+ }
+
+ public void transform(InputStream xmlInputStream, Writer result) throws TransformerException {
+ transform(new BufferedReader(new InputStreamReader(xmlInputStream, StandardCharsets.UTF_8)), result);
+ }
+
+ public void transform(Reader sourceReader, Writer result) throws TransformerException {
+ xformer.transform(new StreamSource(sourceReader), new StreamResult(result));
+ }
+
+ public static String getXsltHeader(String xslt) {
+ return "\n";
+ }
+}
diff --git a/src/main/resources/cities.xsl b/src/main/resources/cities.xsl
new file mode 100644
index 000000000..1c509124b
--- /dev/null
+++ b/src/main/resources/cities.xsl
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/payload.xsd b/src/main/resources/payload.xsd
new file mode 100644
index 000000000..9ef1e46eb
--- /dev/null
+++ b/src/main/resources/payload.xsd
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java b/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java
new file mode 100644
index 000000000..623265428
--- /dev/null
+++ b/src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java
@@ -0,0 +1,40 @@
+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;
+
+public class JaxbParserTest {
+ private static final JaxbParser JAXB_PARSER = new JaxbParser(ObjectFactory.class);
+
+ static {
+ JAXB_PARSER.setSchema(Schemas.ofClasspath("payload.xsd"));
+ }
+
+ @Test
+ public void testPayload() throws Exception {
+// JaxbParserTest.class.getResourceAsStream("/city.xml")
+ Payload payload = JAXB_PARSER.unmarshal(
+ Resources.getResource("payload.xml").openStream());
+ String strPayload = JAXB_PARSER.marshal(payload);
+ JAXB_PARSER.validate(strPayload);
+ System.out.println(strPayload);
+ }
+
+ @Test
+ public void testCity() throws Exception {
+ JAXBElement cityElement = JAXB_PARSER.unmarshal(
+ Resources.getResource("city.xml").openStream());
+ CityType city = cityElement.getValue();
+ JAXBElement cityElement2 =
+ new JAXBElement<>(new QName("http://javaops.ru", "City"), CityType.class, city);
+ String strCity = JAXB_PARSER.marshal(cityElement2);
+ JAXB_PARSER.validate(strCity);
+ System.out.println(strCity);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java
new file mode 100644
index 000000000..fd55963dd
--- /dev/null
+++ b/src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java
@@ -0,0 +1,36 @@
+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;
+
+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/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java
new file mode 100644
index 000000000..199f676a1
--- /dev/null
+++ b/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java
@@ -0,0 +1,26 @@
+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;
+
+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/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java
new file mode 100644
index 000000000..d7f42a699
--- /dev/null
+++ b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java
@@ -0,0 +1,18 @@
+package ru.javaops.masterjava.xml.util;
+
+import com.google.common.io.Resources;
+import org.junit.Test;
+
+import java.io.InputStream;
+
+public class XsltProcessorTest {
+ @Test
+ public void transform() throws Exception {
+ try (InputStream xslInputStream = Resources.getResource("cities.xsl").openStream();
+ InputStream xmlInputStream = Resources.getResource("payload.xml").openStream()) {
+
+ XsltProcessor processor = new XsltProcessor(xslInputStream);
+ System.out.println(processor.transform(xmlInputStream));
+ }
+ }
+}
diff --git a/src/test/resources/city.xml b/src/test/resources/city.xml
new file mode 100644
index 000000000..8b0abcf8a
--- /dev/null
+++ b/src/test/resources/city.xml
@@ -0,0 +1,4 @@
+Санкт-Петербург
+
\ No newline at end of file
diff --git a/src/test/resources/payload.xml b/src/test/resources/payload.xml
new file mode 100644
index 000000000..796e99cb3
--- /dev/null
+++ b/src/test/resources/payload.xml
@@ -0,0 +1,23 @@
+
+
+
+ gmail@gmail.com
+ Full Name
+
+
+ admin@javaops.ru
+ Admin
+
+
+ mail@yandex.ru
+ Deleted
+
+
+
+ Санкт-Петербург
+ Киев
+ Минск
+
+
\ No newline at end of file