From ebbfbe87e127dc30dacebe87f5881fe70ad76188 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 22 Feb 2023 12:28:47 +0300 Subject: [PATCH 01/17] HW1: implemented parallel multiplication matrixA*matrixB --- .../javaops/masterjava/matrix/MainMatrix.java | 9 ++-- .../javaops/masterjava/matrix/MatrixUtil.java | 41 ++++++++++++++++++- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index ec1c8a6..6bee4e6 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -4,15 +4,16 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static ru.javaops.masterjava.matrix.MatrixUtil.MATRIX_SIZE; +import static ru.javaops.masterjava.matrix.MatrixUtil.THREAD_NUMBER; + /** * gkislin * 03.07.2016 */ public class MainMatrix { - private static final int MATRIX_SIZE = 1000; - private static final int THREAD_NUMBER = 10; - private final static ExecutorService executor = Executors.newFixedThreadPool(MainMatrix.THREAD_NUMBER); + private final static ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMBER); public static void main(String[] args) throws ExecutionException, InterruptedException { final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE); @@ -47,6 +48,6 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc } private static void out(String format, double ms) { - System.out.println(String.format(format, ms)); + System.out.printf((format) + "%n", ms); } } diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 80a344a..f32f53e 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -1,20 +1,32 @@ package ru.javaops.masterjava.matrix; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; /** * gkislin * 03.07.2016 */ public class MatrixUtil { + static final int MATRIX_SIZE = 1000; + static final int THREAD_NUMBER = 10; - // TODO implement parallel multiplication matrixA*matrixB + // T_O_D_O implement parallel multiplication matrixA*matrixB public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - +// List tasks = new ArrayList<>(); +// executor.invokeAll(tasks); + for (int i = 0; i < MATRIX_SIZE; i++) { + for (int j = 0; j < MATRIX_SIZE; j++) { + executor.submit(new Task(matrixA, matrixB, matrixC, i, j)); + } + } + while (((ThreadPoolExecutor) executor).getQueue().size() > 0) ; return matrixC; } @@ -58,4 +70,29 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { } return true; } + + static class Task implements Runnable { + private final int[][] matrixA; + private final int[][] matrixB; + private final int[][] matrixC; + private final int i; + private final int j; + + public Task(int[][] matrixA, int[][] matrixB, int[][] matrixC, int i, int j) { + this.matrixA = matrixA; + this.matrixB = matrixB; + this.matrixC = matrixC; + this.i = i; + this.j = j; + } + + @Override + public void run() { + int sum = 0; + for (int k = 0; k < matrixA.length; k++) { + sum += matrixA[i][k] * matrixB[k][j]; + } + matrixC[i][j] = sum; + } + } } From 294c9f1bbdf0826e494752a8d242efa7cbc3868f Mon Sep 17 00:00:00 2001 From: user Date: Fri, 24 Feb 2023 09:04:43 +0300 Subject: [PATCH 02/17] HW1: implemented parallel multiplication matrixA*matrixB --- .../javaops/masterjava/matrix/MainMatrix.java | 17 ++++-- .../javaops/masterjava/matrix/MatrixUtil.java | 53 ++++++++++++++----- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index 6bee4e6..6dfafb3 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -4,20 +4,25 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import static ru.javaops.masterjava.matrix.MatrixUtil.MATRIX_SIZE; -import static ru.javaops.masterjava.matrix.MatrixUtil.THREAD_NUMBER; - /** * gkislin * 03.07.2016 */ public class MainMatrix { + static final int MATRIX_SIZE = 1000; + static final int THREAD_NUMBER = 10; + static final int NUMBER_OF_TASKS = 1; + static int[][] matrixA; + static int[][] matrixB; private final static ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMBER); + static{ + matrixA = MatrixUtil.create(MATRIX_SIZE); + matrixB = MatrixUtil.create(MATRIX_SIZE); + } + public static void main(String[] args) throws ExecutionException, InterruptedException { - final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE); - final int[][] matrixB = MatrixUtil.create(MATRIX_SIZE); double singleThreadSum = 0.; double concurrentThreadSum = 0.; @@ -36,6 +41,8 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc out("Concurrent thread time, sec: %.3f", duration); concurrentThreadSum += duration; + Thread.sleep(0, 1); + if (!MatrixUtil.compare(matrixC, concurrentMatrixC)) { System.err.println("Comparison failed"); break; diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index f32f53e..a7641d9 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -7,24 +7,31 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; +import static ru.javaops.masterjava.matrix.MainMatrix.MATRIX_SIZE; +import static ru.javaops.masterjava.matrix.MainMatrix.NUMBER_OF_TASKS; + /** * gkislin * 03.07.2016 */ public class MatrixUtil { - static final int MATRIX_SIZE = 1000; - static final int THREAD_NUMBER = 10; // T_O_D_O implement parallel multiplication matrixA*matrixB public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; -// List tasks = new ArrayList<>(); -// executor.invokeAll(tasks); - for (int i = 0; i < MATRIX_SIZE; i++) { +/* + List tasks = new ArrayList<>(); + tasks.add(new Task(matrixA, matrixB, matrixC, i + n, j)); + executor.invokeAll(tasks); +*/ + for (int i = 0; i < MATRIX_SIZE; i += NUMBER_OF_TASKS) { for (int j = 0; j < MATRIX_SIZE; j++) { - executor.submit(new Task(matrixA, matrixB, matrixC, i, j)); + for (int n = 0; i + n < MATRIX_SIZE && n < NUMBER_OF_TASKS; n++) { + executor.submit(new Task(matrixA, matrixB, matrixC, i + n, j)); + } } + } while (((ThreadPoolExecutor) executor).getQueue().size() > 0) ; return matrixC; @@ -34,15 +41,24 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; + final int[][] matrixBTransponed = transpone(matrixB); - for (int i = 0; i < matrixSize; i++) { - for (int j = 0; j < matrixSize; j++) { - int sum = 0; - for (int k = 0; k < matrixSize; k++) { - sum += matrixA[i][k] * matrixB[k][j]; + int[] columnMatrixB = new int[MATRIX_SIZE]; + try { + for (int i = 0; ; i++) { + for (int k = 0; k < MATRIX_SIZE; k++) { + columnMatrixB[k] = matrixB[k][i]; + } + for (int j = 0; j < MATRIX_SIZE; j++) { + int[] rowMatrixA = matrixA[j]; + int sum = 0; + for (int k = 0; k < MATRIX_SIZE; k++) { + sum += rowMatrixA[k] * columnMatrixB[k]; + } + matrixC[j][i] = sum; } - matrixC[i][j] = sum; } + } catch (IndexOutOfBoundsException ignored) { } return matrixC; } @@ -64,6 +80,7 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { if (matrixA[i][j] != matrixB[i][j]) { + System.out.printf("matrixA[%d][%d] = %d != matrixB[%d][%d] = %d", i, j, matrixA[i][j], i, j, matrixB[i][j]); return false; } } @@ -71,6 +88,16 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { return true; } + public static int[][] transpone(int[][] matrix) { + int[][] matrixTransponed = new int[MATRIX_SIZE][MATRIX_SIZE]; + for (int i = 0; i < MATRIX_SIZE; i++) { + for (int j = 0; j < MATRIX_SIZE; j++) { + matrixTransponed[j][i] = matrix[i][j]; + } + } + return matrixTransponed; + } + static class Task implements Runnable { private final int[][] matrixA; private final int[][] matrixB; @@ -88,11 +115,13 @@ public Task(int[][] matrixA, int[][] matrixB, int[][] matrixC, int i, int j) { @Override public void run() { +// System.out.printf("[%d][%d] Thread %20s started : %d%n", i, j, Thread.currentThread().getName(), System.nanoTime()); int sum = 0; for (int k = 0; k < matrixA.length; k++) { sum += matrixA[i][k] * matrixB[k][j]; } matrixC[i][j] = sum; +// System.out.printf("[%d][%d] Thread %20s finished: %d%n", i, j, Thread.currentThread().getName(), System.nanoTime()); } } } From 67fa19e9ef78b12318b6c54e05d0c22fc4ce7224 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 3 Mar 2023 18:44:45 +0300 Subject: [PATCH 03/17] HW1: implemented parallel multiplication matrixA*matrixB ThreadPoolExecutor + CyclicBarrier + ForkJoinPool --- .../javaops/masterjava/matrix/MainMatrix.java | 72 +++++--- .../javaops/masterjava/matrix/MatrixUtil.java | 169 ++++++++++++++---- 2 files changed, 183 insertions(+), 58 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index 6dfafb3..59757e6 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -1,8 +1,6 @@ package ru.javaops.masterjava.matrix; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.*; /** * gkislin @@ -10,48 +8,80 @@ */ public class MainMatrix { static final int MATRIX_SIZE = 1000; + static final int TASK_SIZE = 100; static final int THREAD_NUMBER = 10; - static final int NUMBER_OF_TASKS = 1; static int[][] matrixA; static int[][] matrixB; - private final static ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMBER); - - static{ + static { matrixA = MatrixUtil.create(MATRIX_SIZE); matrixB = MatrixUtil.create(MATRIX_SIZE); } - public static void main(String[] args) throws ExecutionException, InterruptedException { - + public static void main(String[] args) { double singleThreadSum = 0.; double concurrentThreadSum = 0.; + double concurrentThreadSumCB = 0.; + double concurrentThreadSumFJP = 0.; int count = 1; while (count < 6) { System.out.println("Pass " + count); - long start = System.currentTimeMillis(); + + long start = System.nanoTime(); final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); - double duration = (System.currentTimeMillis() - start) / 1000.; - out("Single thread time, sec: %.3f", duration); + double duration = (System.nanoTime() - start) / 1000000.; + out("Single thread time, msec: %,.3f", duration); singleThreadSum += duration; - start = System.currentTimeMillis(); + ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMBER); +// ExecutorService executor = Executors.newWorkStealingPool(THREAD_NUMBER); +// ExecutorService executor = Executors.newCachedThreadPool(); + start = System.nanoTime(); final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); - duration = (System.currentTimeMillis() - start) / 1000.; - out("Concurrent thread time, sec: %.3f", duration); + duration = (System.nanoTime() - start) / 1000000.; + out("Concurrent thread time, msec: %,.3f", duration); concurrentThreadSum += duration; + executor.shutdown(); + while (!executor.isTerminated()) ; + + if (MatrixUtil.compare(matrixC, concurrentMatrixC)) { + System.err.println("Comparison (executor) failed"); + break; + } - Thread.sleep(0, 1); + CyclicBarrier barrier = new CyclicBarrier(THREAD_NUMBER); + start = System.nanoTime(); + final int[][] concurrentMatrixCCB = MatrixUtil.concurrentMultiplyCB(matrixA, matrixB, barrier); + duration = (System.nanoTime() - start) / 1000000.; + out("Concurrent CB thread time, msec: %,.3f", duration); + concurrentThreadSumCB += duration; + barrier.reset(); - if (!MatrixUtil.compare(matrixC, concurrentMatrixC)) { - System.err.println("Comparison failed"); + if (MatrixUtil.compare(matrixC, concurrentMatrixCCB)) { + System.err.println("Comparison (CyclicBarrier) failed"); break; } + + ForkJoinPool fjp = new ForkJoinPool(THREAD_NUMBER); + start = System.nanoTime(); + final int[][] concurrentMatrixFJP = MatrixUtil.concurrentMultiplyFJP(matrixA, matrixB, fjp); + duration = (System.nanoTime() - start) / 1000000.; + out("Concurrent ForkJoinPool thread time, msec: %,.3f", duration); + concurrentThreadSumFJP += duration; + fjp.shutdown(); + while(!fjp.isTerminated()); + + if (MatrixUtil.compare(matrixC, concurrentMatrixFJP)) { + System.err.println("Comparison (ForkJoinPool) failed"); + break; + } + count++; } - executor.shutdown(); - out("\nAverage single thread time, sec: %.3f", singleThreadSum / 5.); - out("Average concurrent thread time, sec: %.3f", concurrentThreadSum / 5.); + out("\nAverage single thread time, msec: %,9.3f", singleThreadSum / 5.); + out("Average concurrent thread (executor) time, msec: %,9.3f", concurrentThreadSum / 5.); + out("Average concurrent thread (CB) time, msec: %,9.3f", concurrentThreadSumCB / 5.); + out("Average concurrent thread (ForkJoinPool) time, msec: %,9.3f", concurrentThreadSumFJP / 5.); } private static void out(String format, double ms) { diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index a7641d9..11bf561 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -3,12 +3,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.*; -import static ru.javaops.masterjava.matrix.MainMatrix.MATRIX_SIZE; -import static ru.javaops.masterjava.matrix.MainMatrix.NUMBER_OF_TASKS; +import static ru.javaops.masterjava.matrix.MainMatrix.*; /** * gkislin @@ -17,31 +14,49 @@ public class MatrixUtil { // T_O_D_O implement parallel multiplication matrixA*matrixB - public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { - final int matrixSize = matrixA.length; - final int[][] matrixC = new int[matrixSize][matrixSize]; -/* - List tasks = new ArrayList<>(); - tasks.add(new Task(matrixA, matrixB, matrixC, i + n, j)); - executor.invokeAll(tasks); -*/ - for (int i = 0; i < MATRIX_SIZE; i += NUMBER_OF_TASKS) { - for (int j = 0; j < MATRIX_SIZE; j++) { - for (int n = 0; i + n < MATRIX_SIZE && n < NUMBER_OF_TASKS; n++) { - executor.submit(new Task(matrixA, matrixB, matrixC, i + n, j)); + public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) { + int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; + for (int rowA = 0; rowA < MATRIX_SIZE; rowA += TASK_SIZE) { + executor.submit(new Task(matrixA, matrixB, matrixC, rowA)); + } + return matrixC; + } + + public static int[][] concurrentMultiplyCB(int[][] matrixA, int[][] matrixB, CyclicBarrier barrier) { + int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; + List threads = new ArrayList<>(THREAD_NUMBER); + for (int rowA = 0; rowA < MATRIX_SIZE; rowA++) { + threads.add(new TaskCB(matrixA, matrixB, matrixC, rowA, barrier)); + if (threads.size() == THREAD_NUMBER) { + for (Thread thread : threads) { + thread.start(); } + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + threads.clear(); } - } - while (((ThreadPoolExecutor) executor).getQueue().size() > 0) ; return matrixC; } - // TODO optimize by https://habrahabr.ru/post/114797/ + private static int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; + + public static int[][] concurrentMultiplyFJP(int[][] matrixA, int[][] matrixB, ForkJoinPool fjp) { + int[][] matrixC = MatrixUtil.matrixC; + TaskFJP task = new TaskFJP(matrixC, 0, MATRIX_SIZE); + fjp.invoke(task); + return matrixC; + } + // T_O_D_O optimize by https://habrahabr.ru/post/114797/ + public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - final int[][] matrixBTransponed = transpone(matrixB); int[] columnMatrixB = new int[MATRIX_SIZE]; try { @@ -69,7 +84,7 @@ public static int[][] create(int size) { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { - matrix[i][j] = rn.nextInt(10); + matrix[i][j] = rn.nextInt(6); } } return matrix; @@ -80,12 +95,12 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { if (matrixA[i][j] != matrixB[i][j]) { - System.out.printf("matrixA[%d][%d] = %d != matrixB[%d][%d] = %d", i, j, matrixA[i][j], i, j, matrixB[i][j]); - return false; + System.out.printf("matrix[%d][%d] = %d != concurrentMatrix[%d][%d] = %d", i, j, matrixA[i][j], i, j, matrixB[i][j]); + return true; } } } - return true; + return false; } public static int[][] transpone(int[][] matrix) { @@ -98,30 +113,110 @@ public static int[][] transpone(int[][] matrix) { return matrixTransponed; } - static class Task implements Runnable { + private static void calculate(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA) { + int[] columnMatrixB = new int[MATRIX_SIZE]; + for (int i = rowA; i < rowA + TASK_SIZE; ++i) { + calcIJ(matrixA, matrixB, matrixC, columnMatrixB, i); + } + } + + private static void calculate(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA, int r) { + int[] columnMatrixB = new int[MATRIX_SIZE]; + for (int i = rowA; i < r; i++) { + calcIJ(matrixA, matrixB, matrixC, columnMatrixB, i); + } + } + + private static void calculateCB(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA) { + int[] columnMatrixB = new int[MATRIX_SIZE]; + calcIJ(matrixA, matrixB, matrixC, columnMatrixB, rowA); + } + + private static void calcIJ(int[][] matrixA, int[][] matrixB, int[][] matrixC, int[] columnMatrixB, int column) { + for (int k = 0; k < MATRIX_SIZE; k++) { + columnMatrixB[k] = matrixB[k][column]; + } + for (int j = 0; j < MATRIX_SIZE; j++) { + int[] rowMatrixA = matrixA[j]; + int sum = 0; + for (int k = 0; k < MATRIX_SIZE; k++) { + sum += rowMatrixA[k] * columnMatrixB[k]; + } + matrixC[j][column] = sum; + } + } + + private static class Task implements Runnable { private final int[][] matrixA; private final int[][] matrixB; private final int[][] matrixC; - private final int i; - private final int j; - public Task(int[][] matrixA, int[][] matrixB, int[][] matrixC, int i, int j) { + private final int rowA; + + public Task(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA) { this.matrixA = matrixA; this.matrixB = matrixB; this.matrixC = matrixC; - this.i = i; - this.j = j; + this.rowA = rowA; } @Override public void run() { -// System.out.printf("[%d][%d] Thread %20s started : %d%n", i, j, Thread.currentThread().getName(), System.nanoTime()); - int sum = 0; - for (int k = 0; k < matrixA.length; k++) { - sum += matrixA[i][k] * matrixB[k][j]; + calculate(matrixA, matrixB, matrixC, rowA); + } + + } + + private static class TaskCB extends Thread { + private final int[][] matrixA; + private final int[][] matrixB; + private final int[][] matrixC; + private final int rowA; + + private final CyclicBarrier barrier; + + public TaskCB(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA, CyclicBarrier barrier) { + this.matrixA = matrixA; + this.matrixB = matrixB; + this.matrixC = matrixC; + this.rowA = rowA; + this.barrier = barrier; + } + + @Override + public void run() { + try { + barrier.await(); + calculateCB(matrixA, matrixB, matrixC, rowA); + } catch (InterruptedException | BrokenBarrierException e) { + e.printStackTrace(); + } + } + } + + private static class TaskFJP extends RecursiveAction { + private final int[][] matrixA = MainMatrix.matrixA; + private final int[][] matrixB = MainMatrix.matrixB; + private final int[][] matrixC; + + final int lo, hi; + + TaskFJP(int[][] matrixC, int lo, int hi) { + this.matrixC = matrixC; + this.lo = lo; + this.hi = hi; + } + + protected void compute() { + if (hi - lo <= TASK_SIZE / 64) { + for (int i = lo; i < hi; i++) { + calculate(matrixA, matrixB, matrixC, i, hi); + } + } else { + int mid = (lo + hi) >>> 1; + invokeAll(new TaskFJP(matrixC, lo, mid), + new TaskFJP(matrixC, mid, hi)); } - matrixC[i][j] = sum; -// System.out.printf("[%d][%d] Thread %20s finished: %d%n", i, j, Thread.currentThread().getName(), System.nanoTime()); } } } From 0e49493d6465118ee1785a6f5993c91cd0ab65d0 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 2 Apr 2023 21:57:39 +0300 Subject: [PATCH 04/17] HW1: implemented parallel multiplication matrixA*matrixB ThreadPoolExecutor + CyclicBarrier + ForkJoinPool+parallelStream --- pom.xml | 10 +++ .../javaops/masterjava/matrix/MainMatrix.java | 26 ++++-- .../javaops/masterjava/matrix/MatrixUtil.java | 80 ++++++++++++++----- 3 files changed, 89 insertions(+), 27 deletions(-) diff --git a/pom.xml b/pom.xml index 39e811e..cda8208 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,16 @@ + + org.openjdk.jmh + jmh-core + 1.35 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.35 + diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index 59757e6..291c8c5 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -1,15 +1,17 @@ package ru.javaops.masterjava.matrix; import java.util.concurrent.*; +import java.util.stream.IntStream; /** * gkislin * 03.07.2016 */ public class MainMatrix { - static final int MATRIX_SIZE = 1000; + public static final int MATRIX_SIZE = 1000; static final int TASK_SIZE = 100; - static final int THREAD_NUMBER = 10; + public static final int THREAD_NUMBER = 10; + public static final int THRESH = 64; static int[][] matrixA; static int[][] matrixB; @@ -23,6 +25,7 @@ public static void main(String[] args) { double concurrentThreadSum = 0.; double concurrentThreadSumCB = 0.; double concurrentThreadSumFJP = 0.; + double concurrentSumParallelStream = 0.; int count = 1; while (count < 6) { System.out.println("Pass " + count); @@ -64,27 +67,40 @@ public static void main(String[] args) { ForkJoinPool fjp = new ForkJoinPool(THREAD_NUMBER); start = System.nanoTime(); - final int[][] concurrentMatrixFJP = MatrixUtil.concurrentMultiplyFJP(matrixA, matrixB, fjp); + final int[][] concurrentMatrixFJP = MatrixUtil.concurrentMultiplyFJP(fjp); duration = (System.nanoTime() - start) / 1000000.; out("Concurrent ForkJoinPool thread time, msec: %,.3f", duration); concurrentThreadSumFJP += duration; fjp.shutdown(); - while(!fjp.isTerminated()); + while (!fjp.isTerminated()) ; if (MatrixUtil.compare(matrixC, concurrentMatrixFJP)) { System.err.println("Comparison (ForkJoinPool) failed"); break; } + IntStream stream = IntStream.rangeClosed(0, MATRIX_SIZE - 1).parallel().filter(n -> n % TASK_SIZE == 0); + start = System.nanoTime(); + final int[][] concurrentMatrixParallelStream = MatrixUtil.concurrentMultiplyParallelStream(matrixA, matrixB, stream); + duration = (System.nanoTime() - start) / 1000000.; + out("Concurrent concurrentMatrixParralelStream time, msec: %,.3f", duration); + concurrentSumParallelStream += duration; + + if (MatrixUtil.compare(matrixC, concurrentMatrixParallelStream)) { + System.err.println("Comparison (ParallelStream) failed"); + break; + } + count++; } out("\nAverage single thread time, msec: %,9.3f", singleThreadSum / 5.); out("Average concurrent thread (executor) time, msec: %,9.3f", concurrentThreadSum / 5.); out("Average concurrent thread (CB) time, msec: %,9.3f", concurrentThreadSumCB / 5.); out("Average concurrent thread (ForkJoinPool) time, msec: %,9.3f", concurrentThreadSumFJP / 5.); + out("Average concurrent thread (ParallelStream) time, msec: %,9.3f", concurrentSumParallelStream / 5.); } - private static void out(String format, double ms) { + public static void out(String format, double ms) { System.out.printf((format) + "%n", ms); } } diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 11bf561..dcd0171 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -1,9 +1,12 @@ package ru.javaops.masterjava.matrix; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.*; +import java.util.stream.IntStream; +import java.util.stream.LongStream; import static ru.javaops.masterjava.matrix.MainMatrix.*; @@ -23,7 +26,7 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu } public static int[][] concurrentMultiplyCB(int[][] matrixA, int[][] matrixB, CyclicBarrier barrier) { - int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; + final int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; List threads = new ArrayList<>(THREAD_NUMBER); for (int rowA = 0; rowA < MATRIX_SIZE; rowA++) { threads.add(new TaskCB(matrixA, matrixB, matrixC, rowA, barrier)); @@ -44,30 +47,28 @@ public static int[][] concurrentMultiplyCB(int[][] matrixA, int[][] matrixB, Cyc return matrixC; } - private static int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; - - public static int[][] concurrentMultiplyFJP(int[][] matrixA, int[][] matrixB, ForkJoinPool fjp) { - int[][] matrixC = MatrixUtil.matrixC; + public static int[][] concurrentMultiplyFJP(ForkJoinPool fjp) { + final int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; TaskFJP task = new TaskFJP(matrixC, 0, MATRIX_SIZE); fjp.invoke(task); return matrixC; } - // T_O_D_O optimize by https://habrahabr.ru/post/114797/ + // T_O_D_O optimize by https://habrahabr.ru/post/114797/ public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - int[] columnMatrixB = new int[MATRIX_SIZE]; + int[] columnMatrixB = new int[MainMatrix.MATRIX_SIZE]; try { for (int i = 0; ; i++) { - for (int k = 0; k < MATRIX_SIZE; k++) { + for (int k = 0; k < MainMatrix.MATRIX_SIZE; k++) { columnMatrixB[k] = matrixB[k][i]; } - for (int j = 0; j < MATRIX_SIZE; j++) { + for (int j = 0; j < MainMatrix.MATRIX_SIZE; j++) { int[] rowMatrixA = matrixA[j]; int sum = 0; - for (int k = 0; k < MATRIX_SIZE; k++) { + for (int k = 0; k < MainMatrix.MATRIX_SIZE; k++) { sum += rowMatrixA[k] * columnMatrixB[k]; } matrixC[j][i] = sum; @@ -95,7 +96,6 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { if (matrixA[i][j] != matrixB[i][j]) { - System.out.printf("matrix[%d][%d] = %d != concurrentMatrix[%d][%d] = %d", i, j, matrixA[i][j], i, j, matrixB[i][j]); return true; } } @@ -120,19 +120,29 @@ private static void calculate(int[][] matrixA, int[][] matrixB, int[][] matrixC, } } - private static void calculate(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA, int r) { + private static void calculate(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowFrom, int rowTo) { int[] columnMatrixB = new int[MATRIX_SIZE]; - for (int i = rowA; i < r; i++) { - calcIJ(matrixA, matrixB, matrixC, columnMatrixB, i); + for (int row = rowFrom; row < rowTo; row++) { + calcIJ(matrixA, matrixB, matrixC, columnMatrixB, row); } } - private static void calculateCB(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA) { - int[] columnMatrixB = new int[MATRIX_SIZE]; - calcIJ(matrixA, matrixB, matrixC, columnMatrixB, rowA); + static void calcIJ(int[][] matrixA, int[][] matrixB, int[][] matrixC, int[] columnMatrixB, int column) { + for (int k = 0; k < MATRIX_SIZE; k++) { + columnMatrixB[k] = matrixB[k][column]; + } + for (int j = 0; j < MATRIX_SIZE; j++) { + int[] rowMatrixA = matrixA[j]; + int sum = 0; + for (int k = 0; k < MATRIX_SIZE; k++) { + sum += rowMatrixA[k] * columnMatrixB[k]; + } + matrixC[j][column] = sum; + } } - private static void calcIJ(int[][] matrixA, int[][] matrixB, int[][] matrixC, int[] columnMatrixB, int column) { + private static void calcIJ1(int[][] matrixA, int[][] matrixB, int[][] matrixC, int column) { + int[] columnMatrixB = new int[MATRIX_SIZE]; for (int k = 0; k < MATRIX_SIZE; k++) { columnMatrixB[k] = matrixB[k][column]; } @@ -146,7 +156,33 @@ private static void calcIJ(int[][] matrixA, int[][] matrixB, int[][] matrixC, in } } - private static class Task implements Runnable { + private static void calculateCB(int[][] matrixA, int[][] matrixB, int[][] matrixC, int rowA) { + int[] columnMatrixB = new int[MATRIX_SIZE]; + calcIJ(matrixA, matrixB, matrixC, columnMatrixB, rowA); + } + + public static int[][] concurrentMultiplyParallelStream(final int[][] matrixA, final int[][] matrixB, IntStream stream) { + final int[][] matrixC = new int[MATRIX_SIZE][MATRIX_SIZE]; + stream.forEach(row -> { + calculate(matrixA, matrixB, matrixC, row); + }); + return matrixC; + } + + //concurrentMatrixParralelStream time, msec: 17 943,034 + public static int[][] concurrentMultiplyParallelStream1(final int[][] matrixA, final int[][] matrixB) { + return Arrays.stream(matrixA) + .parallel() + .map(AMatrixRow -> IntStream.range(0, matrixB[0].length) + .map(i -> IntStream.range(0, matrixB.length) + .map(j -> AMatrixRow[j] * matrixB[j][i]) + .sum() + ) + .toArray()) + .toArray(int[][]::new); + } + + static class Task implements Runnable { private final int[][] matrixA; private final int[][] matrixB; private final int[][] matrixC; @@ -167,7 +203,7 @@ public void run() { } - private static class TaskCB extends Thread { + static class TaskCB extends Thread { private final int[][] matrixA; private final int[][] matrixB; private final int[][] matrixC; @@ -194,7 +230,7 @@ public void run() { } } - private static class TaskFJP extends RecursiveAction { + static class TaskFJP extends RecursiveAction { private final int[][] matrixA = MainMatrix.matrixA; private final int[][] matrixB = MainMatrix.matrixB; private final int[][] matrixC; @@ -208,7 +244,7 @@ private static class TaskFJP extends RecursiveAction { } protected void compute() { - if (hi - lo <= TASK_SIZE / 64) { + if (hi - lo <= TASK_SIZE / THRESH) { for (int i = lo; i < hi; i++) { calculate(matrixA, matrixB, matrixC, i, hi); } From 821224ba88daab045b57fcafac1d0f76bb165a88 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 10:38:06 +0300 Subject: [PATCH 05/17] 2_01_HW1_singleThreadMultiplyOpt --- .../javaops/masterjava/matrix/MainMatrix.java | 2 +- .../javaops/masterjava/matrix/MatrixUtil.java | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index ec1c8a6..0695132 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -24,7 +24,7 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc while (count < 6) { System.out.println("Pass " + count); long start = System.currentTimeMillis(); - final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); + final int[][] matrixC = MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); double duration = (System.currentTimeMillis() - start) / 1000.; out("Single thread time, sec: %.3f", duration); singleThreadSum += duration; diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 80a344a..64cfdbe 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -18,18 +18,24 @@ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, Execu return matrixC; } - // TODO optimize by https://habrahabr.ru/post/114797/ - public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { + // Optimized by https://habrahabr.ru/post/114797/ + public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - for (int i = 0; i < matrixSize; i++) { - for (int j = 0; j < matrixSize; j++) { + for (int col = 0; col < matrixSize; col++) { + final int[] columnB = new int[matrixSize]; + for (int k = 0; k < matrixSize; k++) { + columnB[k] = matrixB[k][col]; + } + + for (int row = 0; row < matrixSize; row++) { int sum = 0; + final int[] rowA = matrixA[row]; for (int k = 0; k < matrixSize; k++) { - sum += matrixA[i][k] * matrixB[k][j]; + sum += rowA[k] * columnB[k]; } - matrixC[i][j] = sum; + matrixC[row][col] = sum; } } return matrixC; From 86bbef54904dd7d6bffced9965dd991a2088ac6d Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 10:41:31 +0300 Subject: [PATCH 06/17] 2_02_HW1_concurrentMultiply --- .../javaops/masterjava/matrix/MatrixUtil.java | 153 +++++++++++++++++- 1 file changed, 148 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 64cfdbe..46fd00e 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -1,8 +1,9 @@ package ru.javaops.masterjava.matrix; -import java.util.Random; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; +import java.util.*; +import java.util.concurrent.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * gkislin @@ -10,11 +11,153 @@ */ public class MatrixUtil { - // TODO implement parallel multiplication matrixA*matrixB public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; + class ColumnMultipleResult { + private final int col; + private final int[] columnC; + + private ColumnMultipleResult(int col, int[] columnC) { + this.col = col; + this.columnC = columnC; + } + } + + final CompletionService completionService = new ExecutorCompletionService<>(executor); + + for (int j = 0; j < matrixSize; j++) { + final int col = j; + final int[] columnB = new int[matrixSize]; + for (int k = 0; k < matrixSize; k++) { + columnB[k] = matrixB[k][col]; + } + completionService.submit(() -> { + final int[] columnC = new int[matrixSize]; + + for (int row = 0; row < matrixSize; row++) { + final int[] rowA = matrixA[row]; + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += rowA[k] * columnB[k]; + } + columnC[row] = sum; + } + return new ColumnMultipleResult(col, columnC); + }); + } + + for (int i = 0; i < matrixSize; i++) { + ColumnMultipleResult res = completionService.take().get(); + for (int k = 0; k < matrixSize; k++) { + matrixC[k][res.col] = res.columnC[k]; + } + } + return matrixC; + } + + public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixResult = new int[matrixSize][matrixSize]; + final int threadCount = Runtime.getRuntime().availableProcessors(); + final int maxIndex = matrixSize * matrixSize; + final int cellsInThread = maxIndex / threadCount; + final int[][] matrixBFinal = new int[matrixSize][matrixSize]; + + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + matrixBFinal[i][j] = matrixB[j][i]; + } + } + + Set> threads = new HashSet<>(); + int fromIndex = 0; + for (int i = 1; i <= threadCount; i++) { + final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; + final int firstIndexFinal = fromIndex; + threads.add(() -> { + for (int j = firstIndexFinal; j < toIndex; j++) { + final int row = j / matrixSize; + final int col = j % matrixSize; + + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += matrixA[row][k] * matrixBFinal[col][k]; + } + matrixResult[row][col] = sum; + } + return true; + }); + fromIndex = toIndex; + } + executor.invokeAll(threads); + return matrixResult; + } + + public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) + throws InterruptedException, ExecutionException { + + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + + List> tasks = IntStream.range(0, matrixSize) + .parallel() + .mapToObj(i -> new Callable() { + private final int[] tempColumn = new int[matrixSize]; + + @Override + public Void call() throws Exception { + for (int c = 0; c < matrixSize; c++) { + tempColumn[c] = matrixB[c][i]; + } + for (int j = 0; j < matrixSize; j++) { + int row[] = matrixA[j]; + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += tempColumn[k] * row[k]; + } + matrixC[j][i] = sum; + } + return null; + } + }) + .collect(Collectors.toList()); + + executor.invokeAll(tasks); + return matrixC; + } + + public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][]; + + final int[][] matrixBT = new int[matrixSize][matrixSize]; + for (int i = 0; i < matrixSize; i++) { + for (int j = 0; j < matrixSize; j++) { + matrixBT[i][j] = matrixB[j][i]; + } + } + + List> tasks = new ArrayList<>(matrixSize); + for (int j = 0; j < matrixSize; j++) { + final int row = j; + tasks.add(() -> { + final int[] rowC = new int[matrixSize]; + for (int col = 0; col < matrixSize; col++) { + final int[] rowA = matrixA[row]; + final int[] columnB = matrixBT[col]; + int sum = 0; + for (int k = 0; k < matrixSize; k++) { + sum += rowA[k] * columnB[k]; + } + rowC[col] = sum; + } + matrixC[row] = rowC; + return null; + }); + } + executor.invokeAll(tasks); return matrixC; } @@ -64,4 +207,4 @@ public static boolean compare(int[][] matrixA, int[][] matrixB) { } return true; } -} +} \ No newline at end of file From 190d075b4fd7a1aa8bcc03721f0361f92c78bf6d Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 10:42:57 +0300 Subject: [PATCH 07/17] 2_02_HW1_concurrentMultiply --- .../javaops/masterjava/matrix/MainMatrix.java | 6 +- .../javaops/masterjava/matrix/MatrixUtil.java | 177 ++++++------------ 2 files changed, 63 insertions(+), 120 deletions(-) diff --git a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java index 0695132..1f13806 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java @@ -4,10 +4,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -/** - * gkislin - * 03.07.2016 - */ public class MainMatrix { private static final int MATRIX_SIZE = 1000; private static final int THREAD_NUMBER = 10; @@ -30,7 +26,7 @@ public static void main(String[] args) throws ExecutionException, InterruptedExc singleThreadSum += duration; start = System.currentTimeMillis(); - final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); + final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, Runtime.getRuntime().availableProcessors() - 1); duration = (System.currentTimeMillis() - start) / 1000.; out("Concurrent thread time, sec: %.3f", duration); concurrentThreadSum += duration; diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java index 46fd00e..d00a67a 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java @@ -1,134 +1,39 @@ package ru.javaops.masterjava.matrix; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import java.util.concurrent.*; -import java.util.stream.Collectors; import java.util.stream.IntStream; -/** - * gkislin - * 03.07.2016 - */ public class MatrixUtil { - public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { - final int matrixSize = matrixA.length; - final int[][] matrixC = new int[matrixSize][matrixSize]; - - class ColumnMultipleResult { - private final int col; - private final int[] columnC; - - private ColumnMultipleResult(int col, int[] columnC) { - this.col = col; - this.columnC = columnC; - } - } - - final CompletionService completionService = new ExecutorCompletionService<>(executor); - - for (int j = 0; j < matrixSize; j++) { - final int col = j; - final int[] columnB = new int[matrixSize]; - for (int k = 0; k < matrixSize; k++) { - columnB[k] = matrixB[k][col]; - } - completionService.submit(() -> { - final int[] columnC = new int[matrixSize]; - - for (int row = 0; row < matrixSize; row++) { - final int[] rowA = matrixA[row]; - int sum = 0; - for (int k = 0; k < matrixSize; k++) { - sum += rowA[k] * columnB[k]; - } - columnC[row] = sum; - } - return new ColumnMultipleResult(col, columnC); - }); - } - - for (int i = 0; i < matrixSize; i++) { - ColumnMultipleResult res = completionService.take().get(); - for (int k = 0; k < matrixSize; k++) { - matrixC[k][res.col] = res.columnC[k]; - } - } - return matrixC; - } - - public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { - final int matrixSize = matrixA.length; - final int[][] matrixResult = new int[matrixSize][matrixSize]; - final int threadCount = Runtime.getRuntime().availableProcessors(); - final int maxIndex = matrixSize * matrixSize; - final int cellsInThread = maxIndex / threadCount; - final int[][] matrixBFinal = new int[matrixSize][matrixSize]; - - for (int i = 0; i < matrixSize; i++) { - for (int j = 0; j < matrixSize; j++) { - matrixBFinal[i][j] = matrixB[j][i]; - } - } - - Set> threads = new HashSet<>(); - int fromIndex = 0; - for (int i = 1; i <= threadCount; i++) { - final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; - final int firstIndexFinal = fromIndex; - threads.add(() -> { - for (int j = firstIndexFinal; j < toIndex; j++) { - final int row = j / matrixSize; - final int col = j % matrixSize; - - int sum = 0; - for (int k = 0; k < matrixSize; k++) { - sum += matrixA[row][k] * matrixBFinal[col][k]; - } - matrixResult[row][col] = sum; - } - return true; - }); - fromIndex = toIndex; - } - executor.invokeAll(threads); - return matrixResult; - } - - public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) + public static int[][] concurrentMultiplyStreams(int[][] matrixA, int[][] matrixB, int threadNumber) throws InterruptedException, ExecutionException { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][matrixSize]; - List> tasks = IntStream.range(0, matrixSize) - .parallel() - .mapToObj(i -> new Callable() { - private final int[] tempColumn = new int[matrixSize]; - - @Override - public Void call() throws Exception { - for (int c = 0; c < matrixSize; c++) { - tempColumn[c] = matrixB[c][i]; - } - for (int j = 0; j < matrixSize; j++) { - int row[] = matrixA[j]; - int sum = 0; - for (int k = 0; k < matrixSize; k++) { - sum += tempColumn[k] * row[k]; + new ForkJoinPool(threadNumber).submit( + () -> IntStream.range(0, matrixSize) + .parallel() + .forEach(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[j][i] = sum; - } - return null; - } - }) - .collect(Collectors.toList()); + })).get(); - executor.invokeAll(tasks); return matrixC; } - public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { final int matrixSize = matrixA.length; final int[][] matrixC = new int[matrixSize][]; @@ -161,7 +66,30 @@ public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, Exec return matrixC; } - // Optimized by https://habrahabr.ru/post/114797/ + 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]; @@ -184,6 +112,25 @@ public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) 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]; + } + } + } + return matrixC; + } + public static int[][] create(int size) { int[][] matrix = new int[size][size]; Random rn = new Random(); From 87a59b2da9a8f5b20f6d576ea53db6b62a605669 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 13:05:35 +0300 Subject: [PATCH 08/17] 2_04_JMH_Benchmark --- pom.xml | 13 +++- .../masterjava/matrix/MatrixBenchmark.java | 70 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java diff --git a/pom.xml b/pom.xml index 39e811e..9f0832e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.7.0 ${java.version} ${java.version} @@ -34,6 +34,17 @@ + + org.openjdk.jmh + jmh-core + RELEASE + + + org.openjdk.jmh + jmh-generator-annprocess + RELEASE + provided + diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java new file mode 100644 index 0000000..65fc528 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java @@ -0,0 +1,70 @@ +package ru.javaops.masterjava.matrix; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@BenchmarkMode({Mode.SingleShotTime}) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Threads(1) +@Fork(10) +@Timeout(time = 5, timeUnit = TimeUnit.MINUTES) +public class MatrixBenchmark { + + // Matrix size + private static final int MATRIX_SIZE = 1000; + + @Param({"3", "4", "10"}) + private int threadNumber; + + private static int[][] matrixA; + private static int[][] matrixB; + + @Setup + public void setUp() { + matrixA = MatrixUtil.create(MATRIX_SIZE); + matrixB = MatrixUtil.create(MATRIX_SIZE); + } + + private ExecutorService executor; + + // @Benchmark + public int[][] singleThreadMultiplyOpt() throws Exception { + return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); + } + + // @Benchmark + public int[][] singleThreadMultiplyOpt2() throws Exception { + return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); + } + + @Benchmark + public int[][] concurrentMultiplyStreams() throws Exception { + return MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, threadNumber); + } + + // @Benchmark + public int[][] concurrentMultiply() throws Exception { + return MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); + } + + @Benchmark + public int[][] concurrentMultiply2() throws Exception { + return MatrixUtil.concurrentMultiply2(matrixA, matrixB, executor); + } + + @Setup + public void setup() { + executor = Executors.newFixedThreadPool(threadNumber); + } + + @TearDown + public void tearDown() { + executor.shutdown(); + } +} \ No newline at end of file From e4486a566a5efb80171e5620931937b2b8d41ca1 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 13:06:07 +0300 Subject: [PATCH 09/17] 2_05_JMH_main_jar --- pom.xml | 35 +++++++++++++++++++ .../masterjava/matrix/MatrixBenchmark.java | 15 ++++++++ 2 files changed, 50 insertions(+) diff --git a/pom.xml b/pom.xml index 9f0832e..4cadaf8 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,41 @@ ${java.version} + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + benchmarks + + + org.openjdk.jmh.Main + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java index 65fc528..2df2fc6 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java @@ -1,6 +1,11 @@ package ru.javaops.masterjava.matrix; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.runner.options.TimeValue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -33,6 +38,16 @@ public void setUp() { private ExecutorService executor; + public static void main(String[] args) throws RunnerException { + Options options = new OptionsBuilder() + .include(MatrixBenchmark.class.getSimpleName()) + .threads(1) + .forks(10) + .timeout(TimeValue.minutes(5)) + .build(); + new Runner(options).run(); + } + // @Benchmark public int[][] singleThreadMultiplyOpt() throws Exception { return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); From 86d6bd43f2c0034bc479a031e4dbb35c61d82d3a Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 13:07:03 +0300 Subject: [PATCH 10/17] 2_06_xml_scheme --- .../masterjava/xml/schema/CityType.java | 94 +++++++ .../masterjava/xml/schema/FlagType.java | 54 ++++ .../masterjava/xml/schema/ObjectFactory.java | 85 +++++++ .../masterjava/xml/schema/Payload.java | 233 ++++++++++++++++++ .../javaops/masterjava/xml/schema/User.java | 151 ++++++++++++ src/main/resources/payload.xsd | 56 +++++ src/test/resources/payload.xml | 23 ++ 7 files changed, 696 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/CityType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/Payload.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/User.java create mode 100644 src/main/resources/payload.xsd create mode 100644 src/test/resources/payload.xml 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 0000000..029e352 --- /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 0000000..eda39fa --- /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 0000000..e8f105e --- /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 0000000..2a62764 --- /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 0000000..b3430ce --- /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/resources/payload.xsd b/src/main/resources/payload.xsd new file mode 100644 index 0000000..9ef1e46 --- /dev/null +++ b/src/main/resources/payload.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 0000000..796e99c --- /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 From aa426bb920e337da26b7e5ec58474d2eb88b284a Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 15:36:04 +0300 Subject: [PATCH 11/17] \2_07_JAXB --- .gitignore | 3 +- pom.xml | 24 +++++ .../masterjava/matrix/MatrixBenchmark.java | 2 +- .../masterjava/xml/util/JaxbMarshaller.java | 39 ++++++++ .../masterjava/xml/util/JaxbParser.java | 88 +++++++++++++++++++ .../masterjava/xml/util/JaxbUnmarshaller.java | 33 +++++++ .../javaops/masterjava/xml/util/Schemas.java | 48 ++++++++++ .../masterjava/xml/util/JaxbParserTest.java | 40 +++++++++ src/test/resources/city.xml | 4 + 9 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbParser.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/JaxbUnmarshaller.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/Schemas.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/JaxbParserTest.java create mode 100644 src/test/resources/city.xml diff --git a/.gitignore b/.gitignore index ad02a25..bc9c716 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ out target *.iml -log \ No newline at end of file +log +lib \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4cadaf8..cc4fe8c 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,14 @@ ${java.version} + + org.apache.maven.plugins + maven-surefire-plugin + 2.20.1 + + -Dfile.encoding=UTF-8 + + org.apache.maven.plugins maven-shade-plugin @@ -80,6 +88,22 @@ RELEASE provided + + com.google.guava + guava + 21.0 + + + junit + junit + 4.12 + test + + + javax.xml.bind + jaxb-api + 2.4.0-b180830.0359 + diff --git a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java index 2df2fc6..9b83d79 100644 --- a/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +++ b/src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java @@ -52,7 +52,7 @@ public static void main(String[] args) throws RunnerException { public int[][] singleThreadMultiplyOpt() throws Exception { return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); } - +//3c7aec4a7d241ec2254c862d621b81c80d8b07239fd907f76b309a4f27180fe3 *jetbrains-toolbox-1.28.1.15219.exe // @Benchmark public int[][] singleThreadMultiplyOpt2() throws Exception { return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); 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 0000000..d600680 --- /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 0000000..b3a45f6 --- /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 0000000..7a3e134 --- /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 0000000..42f41df --- /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/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 0000000..6232654 --- /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/resources/city.xml b/src/test/resources/city.xml new file mode 100644 index 0000000..8b0abcf --- /dev/null +++ b/src/test/resources/city.xml @@ -0,0 +1,4 @@ +Санкт-Петербург + \ No newline at end of file From e58b1392f68c9f09fcdca70cff2b583d37e3c45a Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 15:39:47 +0300 Subject: [PATCH 12/17] \2_07_JAXB --- .../xml/util/StaxStreamProcessor.java | 56 +++++++++++++++++++ .../xml/util/StaxStreamProcessorTest.java | 36 ++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/StaxStreamProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java new file mode 100644 index 0000000..921ca6a --- /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/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 0000000..fd55963 --- /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 From a1d9f8ae7f740316ec5ebaab377575e6c8aa8f33 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 16:11:01 +0300 Subject: [PATCH 13/17] 2_08_StAX --- .../masterjava/xml/util/XPathProcessor.java | 58 +++++++++++++++++++ .../xml/util/XPathProcessorTest.java | 26 +++++++++ 2 files changed, 84 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XPathProcessor.java new file mode 100644 index 0000000..63baae5 --- /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/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 0000000..199f676 --- /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 From a97ae12d013eebf12156cdc4ab60a20870bd9b62 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 18 May 2023 16:32:23 +0300 Subject: [PATCH 14/17] 2_10_Xslt --- .../masterjava/xml/util/XsltProcessor.java | 43 +++++++++++++++++++ src/main/resources/cities.xsl | 9 ++++ .../xml/util/XsltProcessorTest.java | 18 ++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java create mode 100644 src/main/resources/cities.xsl create mode 100644 src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java new file mode 100644 index 0000000..019eeed --- /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 0000000..1c50912 --- /dev/null +++ b/src/main/resources/cities.xsl @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java new file mode 100644 index 0000000..d7f42a6 --- /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)); + } + } +} From 9bd1d469c62ee4f8df077500398cc46bd719eb0d Mon Sep 17 00:00:00 2001 From: user Date: Sun, 21 May 2023 16:22:25 +0300 Subject: [PATCH 15/17] 2_10_Xslt --- .gitignore | 7 +- patch/2_01_HW1_singleThreadMultiplyOpt.patch | 54 ++ patch/2_02_HW1_concurrentMultiply.patch | 182 +++++ patch/2_03_HW1_concurrentMultiply2.patch | 245 ++++++ patch/2_04_JMH_Benchmark.patch | 113 +++ patch/2_05_JMH_main_jar.patch | 85 ++ patch/2_06_xml_scheme.patch | 754 ++++++++++++++++++ patch/2_07_JAXB.patch | 342 ++++++++ patch/2_08_StAX.patch | 109 +++ patch/2_09_XPath.patch | 101 +++ patch/2_10_Xslt.patch | 95 +++ .../java/ru/javaops/masterjava/MainXml.java | 111 +++ .../masterjava/xml/schema/CityType.java | 9 +- .../masterjava/xml/schema/FlagType.java | 9 +- .../masterjava/xml/schema/GroupType.java | 46 ++ .../masterjava/xml/schema/ObjectFactory.java | 35 +- .../masterjava/xml/schema/Payload.java | 134 +++- .../masterjava/xml/schema/Project.java | 230 ++++++ .../javaops/masterjava/xml/schema/User.java | 105 ++- .../masterjava/xml/schema/package-info.java | 9 + .../masterjava/xml/util/JaxbMarshaller.java | 2 +- .../xml/util/StaxStreamProcessor.java | 4 + src/main/resources/payload.xml | 39 + src/main/resources/payload.xsd | 50 +- src/test/resources/payload.xml | 25 +- 25 files changed, 2837 insertions(+), 58 deletions(-) create mode 100644 patch/2_01_HW1_singleThreadMultiplyOpt.patch create mode 100644 patch/2_02_HW1_concurrentMultiply.patch create mode 100644 patch/2_03_HW1_concurrentMultiply2.patch create mode 100644 patch/2_04_JMH_Benchmark.patch create mode 100644 patch/2_05_JMH_main_jar.patch create mode 100644 patch/2_06_xml_scheme.patch create mode 100644 patch/2_07_JAXB.patch create mode 100644 patch/2_08_StAX.patch create mode 100644 patch/2_09_XPath.patch create mode 100644 patch/2_10_Xslt.patch create mode 100644 src/main/java/ru/javaops/masterjava/MainXml.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/Project.java create mode 100644 src/main/java/ru/javaops/masterjava/xml/schema/package-info.java create mode 100644 src/main/resources/payload.xml diff --git a/.gitignore b/.gitignore index bc9c716..10ed5b5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,9 @@ out target *.iml log -lib \ No newline at end of file +lib +patch +.patch +.zip +.gitignor +.pdf \ No newline at end of file diff --git a/patch/2_01_HW1_singleThreadMultiplyOpt.patch b/patch/2_01_HW1_singleThreadMultiplyOpt.patch new file mode 100644 index 0000000..c0661a1 --- /dev/null +++ b/patch/2_01_HW1_singleThreadMultiplyOpt.patch @@ -0,0 +1,54 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision d9b13eb2b75334b7485b55a83399716ab1899b7e) ++++ src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision bbace72e8bb84842d5ca73ba331e84d8e8d5ca6c) +@@ -24,7 +24,7 @@ + while (count < 6) { + System.out.println("Pass " + count); + long start = System.currentTimeMillis(); +- final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB); ++ final int[][] matrixC = MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); + double duration = (System.currentTimeMillis() - start) / 1000.; + out("Single thread time, sec: %.3f", duration); + singleThreadSum += duration; +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision d9b13eb2b75334b7485b55a83399716ab1899b7e) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision bbace72e8bb84842d5ca73ba331e84d8e8d5ca6c) +@@ -18,18 +18,24 @@ + return matrixC; + } + +- // TODO optimize by https://habrahabr.ru/post/114797/ +- public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) { ++ // Optimized by https://habrahabr.ru/post/114797/ ++ public static int[][] singleThreadMultiplyOpt(int[][] matrixA, int[][] matrixB) { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + +- for (int i = 0; i < matrixSize; i++) { +- for (int j = 0; j < matrixSize; j++) { ++ for (int col = 0; col < matrixSize; col++) { ++ final int[] columnB = new int[matrixSize]; ++ for (int k = 0; k < matrixSize; k++) { ++ columnB[k] = matrixB[k][col]; ++ } ++ ++ for (int row = 0; row < matrixSize; row++) { + int sum = 0; ++ final int[] rowA = matrixA[row]; + for (int k = 0; k < matrixSize; k++) { +- sum += matrixA[i][k] * matrixB[k][j]; ++ sum += rowA[k] * columnB[k]; + } +- matrixC[i][j] = sum; ++ matrixC[row][col] = sum; + } + } + return matrixC; diff --git a/patch/2_02_HW1_concurrentMultiply.patch b/patch/2_02_HW1_concurrentMultiply.patch new file mode 100644 index 0000000..125962b --- /dev/null +++ b/patch/2_02_HW1_concurrentMultiply.patch @@ -0,0 +1,182 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1508266595000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1508268723000) +@@ -1,8 +1,9 @@ + package ru.javaops.masterjava.matrix; + +-import java.util.Random; +-import java.util.concurrent.ExecutionException; +-import java.util.concurrent.ExecutorService; ++import java.util.*; ++import java.util.concurrent.*; ++import java.util.stream.Collectors; ++import java.util.stream.IntStream; + + /** + * gkislin +@@ -10,11 +11,153 @@ + */ + public class MatrixUtil { + +- // TODO implement parallel multiplication matrixA*matrixB + public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + ++ class ColumnMultipleResult { ++ private final int col; ++ private final int[] columnC; ++ ++ private ColumnMultipleResult(int col, int[] columnC) { ++ this.col = col; ++ this.columnC = columnC; ++ } ++ } ++ ++ final CompletionService completionService = new ExecutorCompletionService<>(executor); ++ ++ for (int j = 0; j < matrixSize; j++) { ++ final int col = j; ++ final int[] columnB = new int[matrixSize]; ++ for (int k = 0; k < matrixSize; k++) { ++ columnB[k] = matrixB[k][col]; ++ } ++ completionService.submit(() -> { ++ final int[] columnC = new int[matrixSize]; ++ ++ for (int row = 0; row < matrixSize; row++) { ++ final int[] rowA = matrixA[row]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += rowA[k] * columnB[k]; ++ } ++ columnC[row] = sum; ++ } ++ return new ColumnMultipleResult(col, columnC); ++ }); ++ } ++ ++ for (int i = 0; i < matrixSize; i++) { ++ ColumnMultipleResult res = completionService.take().get(); ++ for (int k = 0; k < matrixSize; k++) { ++ matrixC[k][res.col] = res.columnC[k]; ++ } ++ } ++ return matrixC; ++ } ++ ++ public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { ++ final int matrixSize = matrixA.length; ++ final int[][] matrixResult = new int[matrixSize][matrixSize]; ++ final int threadCount = Runtime.getRuntime().availableProcessors(); ++ final int maxIndex = matrixSize * matrixSize; ++ final int cellsInThread = maxIndex / threadCount; ++ final int[][] matrixBFinal = new int[matrixSize][matrixSize]; ++ ++ for (int i = 0; i < matrixSize; i++) { ++ for (int j = 0; j < matrixSize; j++) { ++ matrixBFinal[i][j] = matrixB[j][i]; ++ } ++ } ++ ++ Set> threads = new HashSet<>(); ++ int fromIndex = 0; ++ for (int i = 1; i <= threadCount; i++) { ++ final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; ++ final int firstIndexFinal = fromIndex; ++ threads.add(() -> { ++ for (int j = firstIndexFinal; j < toIndex; j++) { ++ final int row = j / matrixSize; ++ final int col = j % matrixSize; ++ ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += matrixA[row][k] * matrixBFinal[col][k]; ++ } ++ matrixResult[row][col] = sum; ++ } ++ return true; ++ }); ++ fromIndex = toIndex; ++ } ++ executor.invokeAll(threads); ++ return matrixResult; ++ } ++ ++ public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) ++ throws InterruptedException, ExecutionException { ++ ++ final int matrixSize = matrixA.length; ++ final int[][] matrixC = new int[matrixSize][matrixSize]; ++ ++ List> tasks = IntStream.range(0, matrixSize) ++ .parallel() ++ .mapToObj(i -> new Callable() { ++ private final int[] tempColumn = new int[matrixSize]; ++ ++ @Override ++ public Void call() throws Exception { ++ for (int c = 0; c < matrixSize; c++) { ++ tempColumn[c] = matrixB[c][i]; ++ } ++ for (int j = 0; j < matrixSize; j++) { ++ int row[] = matrixA[j]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += tempColumn[k] * row[k]; ++ } ++ matrixC[j][i] = sum; ++ } ++ return null; ++ } ++ }) ++ .collect(Collectors.toList()); ++ ++ executor.invokeAll(tasks); ++ return matrixC; ++ } ++ ++ public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { ++ final int matrixSize = matrixA.length; ++ final int[][] matrixC = new int[matrixSize][]; ++ ++ final int[][] matrixBT = new int[matrixSize][matrixSize]; ++ for (int i = 0; i < matrixSize; i++) { ++ for (int j = 0; j < matrixSize; j++) { ++ matrixBT[i][j] = matrixB[j][i]; ++ } ++ } ++ ++ List> tasks = new ArrayList<>(matrixSize); ++ for (int j = 0; j < matrixSize; j++) { ++ final int row = j; ++ tasks.add(() -> { ++ final int[] rowC = new int[matrixSize]; ++ for (int col = 0; col < matrixSize; col++) { ++ final int[] rowA = matrixA[row]; ++ final int[] columnB = matrixBT[col]; ++ int sum = 0; ++ for (int k = 0; k < matrixSize; k++) { ++ sum += rowA[k] * columnB[k]; ++ } ++ rowC[col] = sum; ++ } ++ matrixC[row] = rowC; ++ return null; ++ }); ++ } ++ executor.invokeAll(tasks); + return matrixC; + } + +@@ -64,4 +207,4 @@ + } + return true; + } +-} ++} +\ No newline at end of file diff --git a/patch/2_03_HW1_concurrentMultiply2.patch b/patch/2_03_HW1_concurrentMultiply2.patch new file mode 100644 index 0000000..867926b --- /dev/null +++ b/patch/2_03_HW1_concurrentMultiply2.patch @@ -0,0 +1,245 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (date 1508268723000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java (revision ) +@@ -1,134 +1,39 @@ + package ru.javaops.masterjava.matrix; + +-import java.util.*; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Random; + import java.util.concurrent.*; +-import java.util.stream.Collectors; + import java.util.stream.IntStream; + +-/** +- * gkislin +- * 03.07.2016 +- */ + public class MatrixUtil { + +- public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { +- final int matrixSize = matrixA.length; +- final int[][] matrixC = new int[matrixSize][matrixSize]; +- +- class ColumnMultipleResult { +- private final int col; +- private final int[] columnC; +- +- private ColumnMultipleResult(int col, int[] columnC) { +- this.col = col; +- this.columnC = columnC; +- } +- } +- +- final CompletionService completionService = new ExecutorCompletionService<>(executor); +- +- for (int j = 0; j < matrixSize; j++) { +- final int col = j; +- final int[] columnB = new int[matrixSize]; +- for (int k = 0; k < matrixSize; k++) { +- columnB[k] = matrixB[k][col]; +- } +- completionService.submit(() -> { +- final int[] columnC = new int[matrixSize]; +- +- for (int row = 0; row < matrixSize; row++) { +- final int[] rowA = matrixA[row]; +- int sum = 0; +- for (int k = 0; k < matrixSize; k++) { +- sum += rowA[k] * columnB[k]; +- } +- columnC[row] = sum; +- } +- return new ColumnMultipleResult(col, columnC); +- }); +- } +- +- for (int i = 0; i < matrixSize; i++) { +- ColumnMultipleResult res = completionService.take().get(); +- for (int k = 0; k < matrixSize; k++) { +- matrixC[k][res.col] = res.columnC[k]; +- } +- } +- return matrixC; +- } +- +- public static int[][] concurrentMultiplyCayman(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { +- final int matrixSize = matrixA.length; +- final int[][] matrixResult = new int[matrixSize][matrixSize]; +- final int threadCount = Runtime.getRuntime().availableProcessors(); +- final int maxIndex = matrixSize * matrixSize; +- final int cellsInThread = maxIndex / threadCount; +- final int[][] matrixBFinal = new int[matrixSize][matrixSize]; +- +- for (int i = 0; i < matrixSize; i++) { +- for (int j = 0; j < matrixSize; j++) { +- matrixBFinal[i][j] = matrixB[j][i]; +- } +- } +- +- Set> threads = new HashSet<>(); +- int fromIndex = 0; +- for (int i = 1; i <= threadCount; i++) { +- final int toIndex = i == threadCount ? maxIndex : fromIndex + cellsInThread; +- final int firstIndexFinal = fromIndex; +- threads.add(() -> { +- for (int j = firstIndexFinal; j < toIndex; j++) { +- final int row = j / matrixSize; +- final int col = j % matrixSize; +- +- int sum = 0; +- for (int k = 0; k < matrixSize; k++) { +- sum += matrixA[row][k] * matrixBFinal[col][k]; +- } +- matrixResult[row][col] = sum; +- } +- return true; +- }); +- fromIndex = toIndex; +- } +- executor.invokeAll(threads); +- return matrixResult; +- } +- +- public static int[][] concurrentMultiplyDarthVader(int[][] matrixA, int[][] matrixB, ExecutorService executor) ++ public static int[][] concurrentMultiplyStreams(int[][] matrixA, int[][] matrixB, int threadNumber) + throws InterruptedException, ExecutionException { + + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][matrixSize]; + +- List> tasks = IntStream.range(0, matrixSize) +- .parallel() +- .mapToObj(i -> new Callable() { +- private final int[] tempColumn = new int[matrixSize]; ++ new ForkJoinPool(threadNumber).submit( ++ () -> IntStream.range(0, matrixSize) ++ .parallel() ++ .forEach(row -> { ++ final int[] rowA = matrixA[row]; ++ final int[] rowC = matrixC[row]; + +- @Override +- public Void call() throws Exception { +- for (int c = 0; c < matrixSize; c++) { +- tempColumn[c] = matrixB[c][i]; +- } +- for (int j = 0; j < matrixSize; j++) { +- int row[] = matrixA[j]; +- int sum = 0; +- for (int k = 0; k < matrixSize; k++) { +- sum += tempColumn[k] * row[k]; ++ 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[j][i] = sum; +- } +- return null; +- } +- }) +- .collect(Collectors.toList()); ++ })).get(); + +- executor.invokeAll(tasks); + return matrixC; + } + +- public static int[][] concurrentMultiply2(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { ++ public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException { + final int matrixSize = matrixA.length; + final int[][] matrixC = new int[matrixSize][]; + +@@ -161,7 +66,30 @@ + return matrixC; + } + +- // Optimized by https://habrahabr.ru/post/114797/ ++ 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]; +@@ -183,6 +111,25 @@ + } + 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]; ++ } ++ } ++ } ++ return matrixC; ++ } + + public static int[][] create(int size) { + int[][] matrix = new int[size][size]; +Index: src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (date 1508268723000) ++++ src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java (revision ) +@@ -4,10 +4,6 @@ + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; + +-/** +- * gkislin +- * 03.07.2016 +- */ + public class MainMatrix { + private static final int MATRIX_SIZE = 1000; + private static final int THREAD_NUMBER = 10; +@@ -30,7 +26,7 @@ + singleThreadSum += duration; + + start = System.currentTimeMillis(); +- final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); ++ final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, Runtime.getRuntime().availableProcessors() - 1); + duration = (System.currentTimeMillis() - start) / 1000.; + out("Concurrent thread time, sec: %.3f", duration); + concurrentThreadSum += duration; diff --git a/patch/2_04_JMH_Benchmark.patch b/patch/2_04_JMH_Benchmark.patch new file mode 100644 index 0000000..d5bd75f --- /dev/null +++ b/patch/2_04_JMH_Benchmark.patch @@ -0,0 +1,113 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) +@@ -0,0 +1,70 @@ ++package ru.javaops.masterjava.matrix; ++ ++import org.openjdk.jmh.annotations.*; ++ ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; ++import java.util.concurrent.TimeUnit; ++ ++@Warmup(iterations = 10) ++@Measurement(iterations = 10) ++@BenchmarkMode({Mode.SingleShotTime}) ++@OutputTimeUnit(TimeUnit.MILLISECONDS) ++@State(Scope.Benchmark) ++@Threads(1) ++@Fork(10) ++@Timeout(time = 5, timeUnit = TimeUnit.MINUTES) ++public class MatrixBenchmark { ++ ++ // Matrix size ++ private static final int MATRIX_SIZE = 1000; ++ ++ @Param({"3", "4", "10"}) ++ private int threadNumber; ++ ++ private static int[][] matrixA; ++ private static int[][] matrixB; ++ ++ @Setup ++ public void setUp() { ++ matrixA = MatrixUtil.create(MATRIX_SIZE); ++ matrixB = MatrixUtil.create(MATRIX_SIZE); ++ } ++ ++ private ExecutorService executor; ++ ++ // @Benchmark ++ public int[][] singleThreadMultiplyOpt() throws Exception { ++ return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); ++ } ++ ++ // @Benchmark ++ public int[][] singleThreadMultiplyOpt2() throws Exception { ++ return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); ++ } ++ ++ @Benchmark ++ public int[][] concurrentMultiplyStreams() throws Exception { ++ return MatrixUtil.concurrentMultiplyStreams(matrixA, matrixB, threadNumber); ++ } ++ ++ // @Benchmark ++ public int[][] concurrentMultiply() throws Exception { ++ return MatrixUtil.concurrentMultiply(matrixA, matrixB, executor); ++ } ++ ++ @Benchmark ++ public int[][] concurrentMultiply2() throws Exception { ++ return MatrixUtil.concurrentMultiply2(matrixA, matrixB, executor); ++ } ++ ++ @Setup ++ public void setup() { ++ executor = Executors.newFixedThreadPool(threadNumber); ++ } ++ ++ @TearDown ++ public void tearDown() { ++ executor.shutdown(); ++ } ++} +\ 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 1508790464000) ++++ pom.xml (revision ) +@@ -24,7 +24,7 @@ + + org.apache.maven.plugins + maven-compiler-plugin +- 3.1 ++ 3.7.0 + + ${java.version} + ${java.version} +@@ -34,6 +34,17 @@ + + + ++ ++ org.openjdk.jmh ++ jmh-core ++ RELEASE ++ ++ ++ org.openjdk.jmh ++ jmh-generator-annprocess ++ RELEASE ++ provided ++ + + + diff --git a/patch/2_05_JMH_main_jar.patch b/patch/2_05_JMH_main_jar.patch new file mode 100644 index 0000000..1ad9083 --- /dev/null +++ b/patch/2_05_JMH_main_jar.patch @@ -0,0 +1,85 @@ +Index: src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (date 1508792580000) ++++ src/main/java/ru/javaops/masterjava/matrix/MatrixBenchmark.java (revision ) +@@ -1,6 +1,11 @@ + package ru.javaops.masterjava.matrix; + + import org.openjdk.jmh.annotations.*; ++import org.openjdk.jmh.runner.Runner; ++import org.openjdk.jmh.runner.RunnerException; ++import org.openjdk.jmh.runner.options.Options; ++import org.openjdk.jmh.runner.options.OptionsBuilder; ++import org.openjdk.jmh.runner.options.TimeValue; + + import java.util.concurrent.ExecutorService; + import java.util.concurrent.Executors; +@@ -33,6 +38,16 @@ + + private ExecutorService executor; + ++ public static void main(String[] args) throws RunnerException { ++ Options options = new OptionsBuilder() ++ .include(MatrixBenchmark.class.getSimpleName()) ++ .threads(1) ++ .forks(10) ++ .timeout(TimeValue.minutes(5)) ++ .build(); ++ new Runner(options).run(); ++ } ++ + // @Benchmark + public int[][] singleThreadMultiplyOpt() throws Exception { + return MatrixUtil.singleThreadMultiplyOpt(matrixA, matrixB); +Index: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1508792580000) ++++ pom.xml (revision ) +@@ -30,6 +30,41 @@ + ${java.version} + + ++ ++ org.apache.maven.plugins ++ maven-shade-plugin ++ 3.1.0 ++ ++ ++ package ++ ++ shade ++ ++ ++ benchmarks ++ ++ ++ org.openjdk.jmh.Main ++ ++ ++ ++ ++ ++ *:* ++ ++ META-INF/*.SF ++ META-INF/*.DSA ++ META-INF/*.RSA ++ ++ ++ ++ ++ ++ ++ + + + diff --git a/patch/2_06_xml_scheme.patch b/patch/2_06_xml_scheme.patch new file mode 100644 index 0000000..9650668 --- /dev/null +++ b/patch/2_06_xml_scheme.patch @@ -0,0 +1,754 @@ +Index: src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java (revision ) +@@ -0,0 +1,85 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.JAXBElement; ++import javax.xml.bind.annotation.XmlElementDecl; ++import javax.xml.bind.annotation.XmlRegistry; ++import javax.xml.namespace.QName; ++ ++ ++/** ++ * This object contains factory methods for each ++ * Java content interface and Java element interface ++ * generated in the ru.javaops.masterjava.xml.schema package. ++ *

An ObjectFactory allows you to programatically ++ * construct new instances of the Java representation ++ * for XML content. The Java representation of XML ++ * content can consist of schema derived interfaces ++ * and classes representing the binding of schema ++ * type definitions, element declarations and model ++ * groups. Factory methods for each of these are ++ * provided in this class. ++ * ++ */ ++@XmlRegistry ++public class ObjectFactory { ++ ++ private final static QName _City_QNAME = new QName("http://javaops.ru", "City"); ++ ++ /** ++ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ru.javaops.masterjava.xml.schema ++ * ++ */ ++ public ObjectFactory() { ++ } ++ ++ /** ++ * Create an instance of {@link Payload } ++ * ++ */ ++ public Payload createPayload() { ++ return new Payload(); ++ } ++ ++ /** ++ * Create an instance of {@link User } ++ * ++ */ ++ public User createUser() { ++ return new User(); ++ } ++ ++ /** ++ * Create an instance of {@link Payload.Cities } ++ * ++ */ ++ public Payload.Cities createPayloadCities() { ++ return new Payload.Cities(); ++ } ++ ++ /** ++ * Create an instance of {@link Payload.Users } ++ * ++ */ ++ public Payload.Users createPayloadUsers() { ++ return new Payload.Users(); ++ } ++ ++ /** ++ * Create an instance of {@link CityType } ++ * ++ */ ++ public CityType createCityType() { ++ return new CityType(); ++ } ++ ++ /** ++ * Create an instance of {@link JAXBElement }{@code <}{@link CityType }{@code >}} ++ * ++ */ ++ @XmlElementDecl(namespace = "http://javaops.ru", name = "City") ++ public JAXBElement createCity(CityType value) { ++ return new JAXBElement(_City_QNAME, CityType.class, null, value); ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/Payload.java (revision ) +@@ -0,0 +1,233 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import java.util.ArrayList; ++import java.util.List; ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlElement; ++import javax.xml.bind.annotation.XmlRootElement; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for anonymous complex type. ++ * ++ *

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

++ * <complexType>
++ *   <complexContent>
++ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *       <all>
++ *         <element name="Cities">
++ *           <complexType>
++ *             <complexContent>
++ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *                 <sequence maxOccurs="unbounded">
++ *                   <element ref="{http://javaops.ru}City"/>
++ *                 </sequence>
++ *               </restriction>
++ *             </complexContent>
++ *           </complexType>
++ *         </element>
++ *         <element name="Users">
++ *           <complexType>
++ *             <complexContent>
++ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *                 <sequence maxOccurs="unbounded" minOccurs="0">
++ *                   <element ref="{http://javaops.ru}User"/>
++ *                 </sequence>
++ *               </restriction>
++ *             </complexContent>
++ *           </complexType>
++ *         </element>
++ *       </all>
++ *     </restriction>
++ *   </complexContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "", propOrder = { ++ ++}) ++@XmlRootElement(name = "Payload", namespace = "http://javaops.ru") ++public class Payload { ++ ++ @XmlElement(name = "Cities", namespace = "http://javaops.ru", required = true) ++ protected Payload.Cities cities; ++ @XmlElement(name = "Users", namespace = "http://javaops.ru", required = true) ++ protected Payload.Users users; ++ ++ /** ++ * Gets the value of the cities property. ++ * ++ * @return ++ * possible object is ++ * {@link Payload.Cities } ++ * ++ */ ++ public Payload.Cities getCities() { ++ return cities; ++ } ++ ++ /** ++ * Sets the value of the cities property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Payload.Cities } ++ * ++ */ ++ public void setCities(Payload.Cities value) { ++ this.cities = value; ++ } ++ ++ /** ++ * Gets the value of the users property. ++ * ++ * @return ++ * possible object is ++ * {@link Payload.Users } ++ * ++ */ ++ public Payload.Users getUsers() { ++ return users; ++ } ++ ++ /** ++ * Sets the value of the users property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Payload.Users } ++ * ++ */ ++ public void setUsers(Payload.Users value) { ++ this.users = value; ++ } ++ ++ ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

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

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <sequence maxOccurs="unbounded">
++     *         <element ref="{http://javaops.ru}City"/>
++     *       </sequence>
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "", propOrder = { ++ "city" ++ }) ++ public static class Cities { ++ ++ @XmlElement(name = "City", namespace = "http://javaops.ru", required = true) ++ protected List city; ++ ++ /** ++ * Gets the value of the city property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the city property. ++ * ++ *

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

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

++ * Objects of the following type(s) are allowed in the list ++ * {@link CityType } ++ * ++ * ++ */ ++ public List getCity() { ++ if (city == null) { ++ city = new ArrayList(); ++ } ++ return this.city; ++ } ++ ++ } ++ ++ ++ /** ++ *

Java class for anonymous complex type. ++ * ++ *

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

++     * <complexType>
++     *   <complexContent>
++     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++     *       <sequence maxOccurs="unbounded" minOccurs="0">
++     *         <element ref="{http://javaops.ru}User"/>
++     *       </sequence>
++     *     </restriction>
++     *   </complexContent>
++     * </complexType>
++     * 
++ * ++ * ++ */ ++ @XmlAccessorType(XmlAccessType.FIELD) ++ @XmlType(name = "", propOrder = { ++ "user" ++ }) ++ public static class Users { ++ ++ @XmlElement(name = "User", namespace = "http://javaops.ru") ++ protected List user; ++ ++ /** ++ * Gets the value of the user property. ++ * ++ *

++ * This accessor method returns a reference to the live list, ++ * not a snapshot. Therefore any modification you make to the ++ * returned list will be present inside the JAXB object. ++ * This is why there is not a set method for the user property. ++ * ++ *

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

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

++ * Objects of the following type(s) are allowed in the list ++ * {@link User } ++ * ++ * ++ */ ++ public List getUser() { ++ if (user == null) { ++ user = new ArrayList(); ++ } ++ return this.user; ++ } ++ ++ } ++ ++} +Index: src/main/java/ru/javaops/masterjava/xml/schema/User.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/User.java (revision ) +@@ -0,0 +1,151 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlElement; ++import javax.xml.bind.annotation.XmlIDREF; ++import javax.xml.bind.annotation.XmlRootElement; ++import javax.xml.bind.annotation.XmlSchemaType; ++import javax.xml.bind.annotation.XmlType; ++ ++ ++/** ++ *

Java class for anonymous complex type. ++ * ++ *

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

++ * <complexType>
++ *   <complexContent>
++ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
++ *       <sequence>
++ *         <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ *         <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/>
++ *       </sequence>
++ *       <attribute name="flag" use="required" type="{http://javaops.ru}flagType" />
++ *       <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" />
++ *     </restriction>
++ *   </complexContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "", propOrder = { ++ "email", ++ "fullName" ++}) ++@XmlRootElement(name = "User", namespace = "http://javaops.ru") ++public class User { ++ ++ @XmlElement(namespace = "http://javaops.ru", required = true) ++ protected String email; ++ @XmlElement(namespace = "http://javaops.ru", required = true) ++ protected String fullName; ++ @XmlAttribute(name = "flag", required = true) ++ protected FlagType flag; ++ @XmlAttribute(name = "city", required = true) ++ @XmlIDREF ++ @XmlSchemaType(name = "IDREF") ++ protected Object city; ++ ++ /** ++ * Gets the value of the email property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getEmail() { ++ return email; ++ } ++ ++ /** ++ * Sets the value of the email property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setEmail(String value) { ++ this.email = value; ++ } ++ ++ /** ++ * Gets the value of the fullName property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getFullName() { ++ return fullName; ++ } ++ ++ /** ++ * Sets the value of the fullName property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setFullName(String value) { ++ this.fullName = value; ++ } ++ ++ /** ++ * Gets the value of the flag property. ++ * ++ * @return ++ * possible object is ++ * {@link FlagType } ++ * ++ */ ++ public FlagType getFlag() { ++ return flag; ++ } ++ ++ /** ++ * Sets the value of the flag property. ++ * ++ * @param value ++ * allowed object is ++ * {@link FlagType } ++ * ++ */ ++ public void setFlag(FlagType value) { ++ this.flag = value; ++ } ++ ++ /** ++ * Gets the value of the city property. ++ * ++ * @return ++ * possible object is ++ * {@link Object } ++ * ++ */ ++ public Object getCity() { ++ return city; ++ } ++ ++ /** ++ * Sets the value of the city property. ++ * ++ * @param value ++ * allowed object is ++ * {@link Object } ++ * ++ */ ++ public void setCity(Object value) { ++ this.city = value; ++ } ++ ++} +Index: src/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/test/resources/payload.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/resources/payload.xml (revision ) ++++ src/test/resources/payload.xml (revision ) +@@ -0,0 +1,23 @@ ++ ++ ++ ++ gmail@gmail.com ++ Full Name ++ ++ ++ admin@javaops.ru ++ Admin ++ ++ ++ mail@yandex.ru ++ Deleted ++ ++ ++ ++ Санкт-Петербург ++ Киев ++ Минск ++ ++ +\ No newline at end of file +Index: src/main/java/ru/javaops/masterjava/xml/schema/CityType.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision ) ++++ src/main/java/ru/javaops/masterjava/xml/schema/CityType.java (revision ) +@@ -0,0 +1,94 @@ ++ ++package ru.javaops.masterjava.xml.schema; ++ ++import javax.xml.bind.annotation.XmlAccessType; ++import javax.xml.bind.annotation.XmlAccessorType; ++import javax.xml.bind.annotation.XmlAttribute; ++import javax.xml.bind.annotation.XmlID; ++import javax.xml.bind.annotation.XmlSchemaType; ++import javax.xml.bind.annotation.XmlType; ++import javax.xml.bind.annotation.XmlValue; ++import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; ++import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; ++ ++ ++/** ++ *

Java class for cityType complex type. ++ * ++ *

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

++ * <complexType name="cityType">
++ *   <simpleContent>
++ *     <extension base="<http://www.w3.org/2001/XMLSchema>string">
++ *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
++ *     </extension>
++ *   </simpleContent>
++ * </complexType>
++ * 
++ * ++ * ++ */ ++@XmlAccessorType(XmlAccessType.FIELD) ++@XmlType(name = "cityType", namespace = "http://javaops.ru", propOrder = { ++ "value" ++}) ++public class CityType { ++ ++ @XmlValue ++ protected String value; ++ @XmlAttribute(name = "id", required = true) ++ @XmlJavaTypeAdapter(CollapsedStringAdapter.class) ++ @XmlID ++ @XmlSchemaType(name = "ID") ++ protected String id; ++ ++ /** ++ * Gets the value of the value property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getValue() { ++ return value; ++ } ++ ++ /** ++ * Sets the value of the value property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setValue(String value) { ++ this.value = value; ++ } ++ ++ /** ++ * Gets the value of the id property. ++ * ++ * @return ++ * possible object is ++ * {@link String } ++ * ++ */ ++ public String getId() { ++ return id; ++ } ++ ++ /** ++ * Sets the value of the id property. ++ * ++ * @param value ++ * allowed object is ++ * {@link String } ++ * ++ */ ++ public void setId(String value) { ++ this.id = value; ++ } ++ ++} +Index: src/main/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 diff --git a/patch/2_07_JAXB.patch b/patch/2_07_JAXB.patch new file mode 100644 index 0000000..5dfafec --- /dev/null +++ b/patch/2_07_JAXB.patch @@ -0,0 +1,342 @@ +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,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); ++ } ++ ++} +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,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); ++ } ++ } ++} +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,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 +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,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)); ++ } ++} +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,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)); ++ } ++} +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: pom.xml +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- pom.xml (date 1508793189000) ++++ pom.xml (revision ) +@@ -32,6 +32,14 @@ +
+ + org.apache.maven.plugins ++ maven-surefire-plugin ++ 2.20.1 ++ ++ -Dfile.encoding=UTF-8 ++ ++ ++ ++ org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + +@@ -79,6 +87,17 @@ + jmh-generator-annprocess + RELEASE + provided ++ ++ ++ com.google.guava ++ guava ++ 21.0 ++ ++ ++ junit ++ junit ++ 4.12 ++ test + + + diff --git a/patch/2_08_StAX.patch b/patch/2_08_StAX.patch new file mode 100644 index 0000000..228cca7 --- /dev/null +++ b/patch/2_08_StAX.patch @@ -0,0 +1,109 @@ +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,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 ++ } ++ } ++ } ++} +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,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/patch/2_09_XPath.patch b/patch/2_09_XPath.patch new file mode 100644 index 0000000..f662f3b --- /dev/null +++ b/patch/2_09_XPath.patch @@ -0,0 +1,101 @@ +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,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); ++ } ++ } ++} +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,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/patch/2_10_Xslt.patch b/patch/2_10_Xslt.patch new file mode 100644 index 0000000..fceab9e --- /dev/null +++ b/patch/2_10_Xslt.patch @@ -0,0 +1,95 @@ +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 ) ++++ src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java (revision ) +@@ -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"; ++ } ++} +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 ) ++++ src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java (revision ) +@@ -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)); ++ } ++ } ++} +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 ) ++++ src/main/resources/cities.xsl (revision ) +@@ -0,0 +1,9 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file diff --git a/src/main/java/ru/javaops/masterjava/MainXml.java b/src/main/java/ru/javaops/masterjava/MainXml.java new file mode 100644 index 0000000..aef6bbf --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/MainXml.java @@ -0,0 +1,111 @@ +package ru.javaops.masterjava; + +import org.xml.sax.SAXException; +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 javax.xml.bind.JAXBException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; + +import static com.google.common.io.Resources.getResource; + +public class MainXml { + + public static void main(String[] args) throws IOException, JAXBException, SAXException, XMLStreamException { + String projectName = args[0]; + getUsersJaxb(projectName).forEach(user -> System.out.println(user.getFullName())); + System.out.println("----------------------------------"); + getUsersStax(projectName).forEach(System.out::println); + } + + private static Set getUsersJaxb(String projectName) throws JAXBException, IOException { + JaxbParser jaxbParser = new JaxbParser(ObjectFactory.class); + jaxbParser.setSchema(Schemas.ofClasspath("payload.xsd")); + + Payload payLoad = jaxbParser.unmarshal(getResource("payload.xml").openStream()); + + Project project = payLoad.getProjects().getProject().stream().filter(p -> p.getName().equals(projectName)).findFirst() + .orElseThrow(() -> new RuntimeException("Project not found: " + projectName)); + + Set groups = new HashSet<>(project.getGroup()); + + Set users = new HashSet<>(Collections.unmodifiableList(payLoad.getUsers().getUser())); + + return users.stream() + .filter(user -> !Collections.disjoint(groups, user.getUserGroup())) + .sorted(Comparator.comparing(User::getFullName)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + private static Set getUsersStax(String projectName) throws XMLStreamException, IOException { + URL url = getResource("payload.xml"); + InputStream is = url.openStream(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLStreamReader parser = factory.createXMLStreamReader(is); + Map> projectGroups = new HashMap<>(); + Map> userGroups = new HashMap<>(); + WHILE_HAS_NEXT_UP: + while (parser.hasNext()) { + if (parser.next() == XMLStreamReader.START_ELEMENT) { + if (parser.getLocalName().equalsIgnoreCase("project")) { + if (parser.getAttributeValue(null, "name").equals(projectName)) { + Set groups = new HashSet<>(); + projectGroups.put(projectName, groups); + INSIDE_GROUP: + while (parser.hasNext()) { + int eventType = parser.next(); + if (eventType == XMLStreamReader.START_ELEMENT) { + if (parser.getLocalName().equalsIgnoreCase("group")) { + String groupName = parser.getAttributeValue(null, "name"); + groups.add(groupName); + } + } + if (eventType == XMLStreamReader.END_ELEMENT) { + if (parser.getLocalName().equalsIgnoreCase("project")) { + break INSIDE_GROUP; + } + } + } + } + } + if (parser.getLocalName().equalsIgnoreCase("user")) { + String groups = parser.getAttributeValue(null, "userGroup"); + INSIDE_USER: + while (parser.hasNext()) { + int event = parser.next(); + switch (event) { + case XMLStreamReader.START_ELEMENT: + String elementText = parser.getElementText(); + if (groups != null && !groups.isEmpty()) { + Set set = Arrays.stream(groups.split(" ")).collect(Collectors.toSet()); + userGroups.put(elementText, set); + } + break; + case XMLStreamReader.END_ELEMENT: + break INSIDE_USER; + } + } + } + } + } + Set projectUsers = new TreeSet<>(); + userGroups.forEach((name, groups) -> { + Collection> values = projectGroups.values(); + if (!Collections.disjoint(groups, projectGroups.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()))) { + projectUsers.add(name); + } + }); + return projectUsers; + } +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java index 029e352..4840b5b 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/CityType.java @@ -1,3 +1,10 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 02:07:06 PM MSK +// + package ru.javaops.masterjava.xml.schema; @@ -30,7 +37,7 @@ * */ @XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "cityType", namespace = "http://javaops.ru", propOrder = { +@XmlType(name = "cityType", propOrder = { "value" }) public class CityType { diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java index eda39fa..295ba80 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/FlagType.java @@ -1,3 +1,10 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + package ru.javaops.masterjava.xml.schema; @@ -22,7 +29,7 @@ * * */ -@XmlType(name = "flagType", namespace = "http://javaops.ru") +@XmlType(name = "flagType") @XmlEnum public enum FlagType { diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java b/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java new file mode 100644 index 0000000..c2d555e --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/GroupType.java @@ -0,0 +1,46 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + + +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") +@XmlEnum +public enum GroupType { + + REGISTERING, + CURRENT, + FINISHED; + + public String value() { + return name(); + } + + public static GroupType fromValue(String v) { + return valueOf(v); + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java index e8f105e..51bcc7d 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/ObjectFactory.java @@ -1,3 +1,10 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + package ru.javaops.masterjava.xml.schema; @@ -10,7 +17,7 @@ /** * This object contains factory methods for each * Java content interface and Java element interface - * generated in the ru.javaops.masterjava.xml.schema package. + * generated in the ru.javaops package. *

An ObjectFactory allows you to programatically * construct new instances of the Java representation * for XML content. The Java representation of XML @@ -27,12 +34,20 @@ 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 + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ru.javaops * */ public ObjectFactory() { } + /** + * Create an instance of {@link Project } + * + */ + public Project createProject() { + return new Project(); + } + /** * Create an instance of {@link Payload } * @@ -41,6 +56,14 @@ public Payload createPayload() { return new Payload(); } + /** + * Create an instance of {@link Project.Group } + * + */ + public Project.Group createProjectGroup() { + return new Project.Group(); + } + /** * Create an instance of {@link User } * @@ -49,6 +72,14 @@ public User createUser() { return new User(); } + /** + * Create an instance of {@link Payload.Projects } + * + */ + public Payload.Projects createPayloadProjects() { + return new Payload.Projects(); + } + /** * Create an instance of {@link Payload.Cities } * diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java index 2a62764..354f11b 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/Payload.java @@ -1,3 +1,10 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + package ru.javaops.masterjava.xml.schema; @@ -20,6 +27,17 @@ * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <all> + * <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> @@ -54,23 +72,49 @@ @XmlType(name = "", propOrder = { }) -@XmlRootElement(name = "Payload", namespace = "http://javaops.ru") +@XmlRootElement(name = "Payload") 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; + @XmlElement(name = "Projects", required = true) + protected Projects projects; + @XmlElement(name = "Cities", required = true) + protected Cities cities; + @XmlElement(name = "Users", required = true) + protected Users users; + + /** + * Gets the value of the projects property. + * + * @return + * possible object is + * {@link Projects } + * + */ + public Projects getProjects() { + return projects; + } + + /** + * Sets the value of the projects property. + * + * @param value + * allowed object is + * {@link Projects } + * + */ + public void setProjects(Projects value) { + this.projects = value; + } /** * Gets the value of the cities property. * * @return * possible object is - * {@link Payload.Cities } + * {@link Cities } * */ - public Payload.Cities getCities() { + public Cities getCities() { return cities; } @@ -79,10 +123,10 @@ public Payload.Cities getCities() { * * @param value * allowed object is - * {@link Payload.Cities } + * {@link Cities } * */ - public void setCities(Payload.Cities value) { + public void setCities(Cities value) { this.cities = value; } @@ -91,10 +135,10 @@ public void setCities(Payload.Cities value) { * * @return * possible object is - * {@link Payload.Users } + * {@link Users } * */ - public Payload.Users getUsers() { + public Users getUsers() { return users; } @@ -103,10 +147,10 @@ public Payload.Users getUsers() { * * @param value * allowed object is - * {@link Payload.Users } + * {@link Users } * */ - public void setUsers(Payload.Users value) { + public void setUsers(Users value) { this.users = value; } @@ -136,7 +180,7 @@ public void setUsers(Payload.Users value) { }) public static class Cities { - @XmlElement(name = "City", namespace = "http://javaops.ru", required = true) + @XmlElement(name = "City", required = true) protected List city; /** @@ -171,6 +215,66 @@ public List getCity() { } + /** + *

Java class for anonymous complex type. + * + *

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

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <sequence maxOccurs="unbounded">
+     *         <element ref="{http://javaops.ru}Project"/>
+     *       </sequence>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + "project" + }) + public static class Projects { + + @XmlElement(name = "Project", 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. * @@ -196,7 +300,7 @@ public List getCity() { }) public static class Users { - @XmlElement(name = "User", namespace = "http://javaops.ru") + @XmlElement(name = "User") protected List user; /** diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/Project.java b/src/main/java/ru/javaops/masterjava/xml/schema/Project.java new file mode 100644 index 0000000..fc28629 --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/Project.java @@ -0,0 +1,230 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + + +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="5">
+ *           <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") +public class Project { + + @XmlElement(required = true) + protected String description; + @XmlElement(name = "Group", 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 Group } + * + * + */ + public List getGroup() { + if (group == null) { + group = new ArrayList(); + } + return this.group; + } + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } + + + /** + *

Java class for anonymous complex type. + * + *

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

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+     *       <attribute name="type" use="required" type="{http://javaops.ru}groupType" />
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "") + public static class Group { + + @XmlAttribute(name = "name", required = true) + @XmlJavaTypeAdapter(CollapsedStringAdapter.class) + @XmlID + @XmlSchemaType(name = "ID") + protected String name; + @XmlAttribute(name = "type", required = true) + protected GroupType type; + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } + + /** + * Gets the value of the type property. + * + * @return + * possible object is + * {@link GroupType } + * + */ + public GroupType getType() { + return type; + } + + /** + * Sets the value of the type property. + * + * @param value + * allowed object is + * {@link GroupType } + * + */ + public void setType(GroupType value) { + this.type = value; + } + + } + +} diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java index b3430ce..604a115 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/User.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -1,6 +1,15 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + 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; @@ -9,6 +18,8 @@ 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; /** @@ -21,11 +32,12 @@ * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> - * <element name="email" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="fullName" type="{http://www.w3.org/2001/XMLSchema}string"/> * </sequence> * <attribute name="flag" use="required" type="{http://javaops.ru}flagType" /> * <attribute name="city" use="required" type="{http://www.w3.org/2001/XMLSchema}IDREF" /> + * <attribute name="email" type="{http://javaops.ru}emailAddress" /> + * <attribute name="userGroup" type="{http://www.w3.org/2001/XMLSchema}IDREFS" /> * </restriction> * </complexContent> * </complexType> @@ -35,15 +47,12 @@ */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { - "email", "fullName" }) -@XmlRootElement(name = "User", namespace = "http://javaops.ru") +@XmlRootElement(name = "User") public class User { - @XmlElement(namespace = "http://javaops.ru", required = true) - protected String email; - @XmlElement(namespace = "http://javaops.ru", required = true) + @XmlElement(required = true) protected String fullName; @XmlAttribute(name = "flag", required = true) protected FlagType flag; @@ -51,30 +60,13 @@ public class User { @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; - } + @XmlAttribute(name = "email") + @XmlJavaTypeAdapter(CollapsedStringAdapter.class) + protected String email; + @XmlAttribute(name = "userGroup") + @XmlIDREF + @XmlSchemaType(name = "IDREFS") + protected List userGroup; /** * Gets the value of the fullName property. @@ -148,4 +140,57 @@ public void setCity(Object value) { this.city = value; } + /** + * Gets the value of the email property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getEmail() { + return email; + } + + /** + * Sets the value of the email property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setEmail(String value) { + this.email = value; + } + + /** + * Gets the value of the userGroup 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 userGroup property. + * + *

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

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

+ * Objects of the following type(s) are allowed in the list + * {@link Object } + * + * + */ + public List getUserGroup() { + if (userGroup == null) { + userGroup = new ArrayList<>(); + } + return this.userGroup; + } + } diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/package-info.java b/src/main/java/ru/javaops/masterjava/xml/schema/package-info.java new file mode 100644 index 0000000..1d0d11b --- /dev/null +++ b/src/main/java/ru/javaops/masterjava/xml/schema/package-info.java @@ -0,0 +1,9 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2023.05.20 at 01:01:58 PM MSK +// + +@javax.xml.bind.annotation.XmlSchema(namespace = "http://javaops.ru", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) +package ru.javaops.masterjava.xml.schema; diff --git a/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java index d600680..bd155d0 100644 --- a/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java +++ b/src/main/java/ru/javaops/masterjava/xml/util/JaxbMarshaller.java @@ -9,7 +9,7 @@ import java.io.Writer; public class JaxbMarshaller { - private Marshaller marshaller; + private final Marshaller marshaller; public JaxbMarshaller(JAXBContext ctx) throws JAXBException { marshaller = ctx.createMarshaller(); diff --git a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java index 921ca6a..ab4b820 100644 --- a/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java +++ b/src/main/java/ru/javaops/masterjava/xml/util/StaxStreamProcessor.java @@ -4,6 +4,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.events.XMLEvent; +import javax.xml.validation.Schema; import java.io.InputStream; public class StaxStreamProcessor implements AutoCloseable { @@ -53,4 +54,7 @@ public void close() { } } } + + public void setSchema(Schema ofClasspath) { + } } diff --git a/src/main/resources/payload.xml b/src/main/resources/payload.xml new file mode 100644 index 0000000..f63efa4 --- /dev/null +++ b/src/main/resources/payload.xml @@ -0,0 +1,39 @@ + + + + + Enterprise Java-разработчик (TopJava) + + + + + + + Многомодульный Maven, многопоточность, JavaEE + + + + + + + + full Name + + + another User + + + Axmin + + + Deleted + + + + Санкт-Петербург + Киев + Минск + + \ No newline at end of file diff --git a/src/main/resources/payload.xsd b/src/main/resources/payload.xsd index 9ef1e46..602575d 100644 --- a/src/main/resources/payload.xsd +++ b/src/main/resources/payload.xsd @@ -7,6 +7,14 @@ + + + + + + + + @@ -28,11 +36,15 @@ - + + + + + @@ -53,4 +65,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/payload.xml b/src/test/resources/payload.xml index 796e99c..fc8bf78 100644 --- a/src/test/resources/payload.xml +++ b/src/test/resources/payload.xml @@ -1,17 +1,30 @@ + + + + Enterprise Java-разработчик (TopJava) + + + + + + + Многомодульный Maven, многопоточность, JavaEE + + + - - gmail@gmail.com + + + Full Name - - admin@javaops.ru + Admin - - mail@yandex.ru + Deleted From 7d17795c664dc5d31159eed493fd126155a13978 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 21 May 2023 19:28:00 +0300 Subject: [PATCH 16/17] 2_10_Xslt --- .gitignore | 2 +- .../java/ru/javaops/masterjava/MainXml.java | 34 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 10ed5b5..aaa35a9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,5 @@ lib patch .patch .zip -.gitignor +.gitignore .pdf \ No newline at end of file diff --git a/src/main/java/ru/javaops/masterjava/MainXml.java b/src/main/java/ru/javaops/masterjava/MainXml.java index aef6bbf..d9b8178 100644 --- a/src/main/java/ru/javaops/masterjava/MainXml.java +++ b/src/main/java/ru/javaops/masterjava/MainXml.java @@ -55,7 +55,6 @@ private static Set getUsersStax(String projectName) throws XMLStreamExce XMLStreamReader parser = factory.createXMLStreamReader(is); Map> projectGroups = new HashMap<>(); Map> userGroups = new HashMap<>(); - WHILE_HAS_NEXT_UP: while (parser.hasNext()) { if (parser.next() == XMLStreamReader.START_ELEMENT) { if (parser.getLocalName().equalsIgnoreCase("project")) { @@ -65,31 +64,31 @@ private static Set getUsersStax(String projectName) throws XMLStreamExce INSIDE_GROUP: while (parser.hasNext()) { int eventType = parser.next(); - if (eventType == XMLStreamReader.START_ELEMENT) { - if (parser.getLocalName().equalsIgnoreCase("group")) { - String groupName = parser.getAttributeValue(null, "name"); - groups.add(groupName); - } - } - if (eventType == XMLStreamReader.END_ELEMENT) { - if (parser.getLocalName().equalsIgnoreCase("project")) { - break INSIDE_GROUP; - } + switch (eventType) { + case XMLStreamReader.START_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("group")) { + groups.add(parser.getAttributeValue(null, "name")); + } + break; + case XMLStreamReader.END_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("project")) { + break INSIDE_GROUP; + } + break; } } } } if (parser.getLocalName().equalsIgnoreCase("user")) { - String groups = parser.getAttributeValue(null, "userGroup"); + String groupsString = parser.getAttributeValue(null, "userGroup"); INSIDE_USER: while (parser.hasNext()) { int event = parser.next(); switch (event) { case XMLStreamReader.START_ELEMENT: - String elementText = parser.getElementText(); - if (groups != null && !groups.isEmpty()) { - Set set = Arrays.stream(groups.split(" ")).collect(Collectors.toSet()); - userGroups.put(elementText, set); + String user = parser.getElementText(); + if (groupsString != null && !groupsString.isEmpty()) { + userGroups.put(user, Arrays.stream(groupsString.split(" ")).collect(Collectors.toSet())); } break; case XMLStreamReader.END_ELEMENT: @@ -99,9 +98,8 @@ private static Set getUsersStax(String projectName) throws XMLStreamExce } } } - Set projectUsers = new TreeSet<>(); + Set projectUsers = new TreeSet<>(Comparator.comparing(String::toLowerCase)); userGroups.forEach((name, groups) -> { - Collection> values = projectGroups.values(); if (!Collections.disjoint(groups, projectGroups.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()))) { projectUsers.add(name); } From cf5fac3ab79528d91d5fa7ca1502a4e03305a2c5 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 24 May 2023 16:04:17 +0300 Subject: [PATCH 17/17] HW2 --- pom.xml | 7 + .../java/ru/javaops/masterjava/MainXml.java | 218 ++++++++++++++---- .../javaops/masterjava/xml/schema/User.java | 12 + .../masterjava/xml/util/XsltProcessor.java | 4 + src/main/resources/cities.xsl | 10 +- src/main/resources/projects.xsl | 10 + .../xml/util/XPathProcessorTest.java | 13 ++ .../xml/util/XsltProcessorTest.java | 15 +- 8 files changed, 240 insertions(+), 49 deletions(-) create mode 100644 src/main/resources/projects.xsl diff --git a/pom.xml b/pom.xml index cc4fe8c..9aee59f 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,13 @@ jaxb-api 2.4.0-b180830.0359 + + + com.j2html + j2html + 1.6.0 + + diff --git a/src/main/java/ru/javaops/masterjava/MainXml.java b/src/main/java/ru/javaops/masterjava/MainXml.java index d9b8178..2839c7a 100644 --- a/src/main/java/ru/javaops/masterjava/MainXml.java +++ b/src/main/java/ru/javaops/masterjava/MainXml.java @@ -1,5 +1,8 @@ package ru.javaops.masterjava; +import com.google.common.io.Resources; +import j2html.tags.ContainerTag; +import j2html.tags.specialized.HtmlTag; import org.xml.sax.SAXException; import ru.javaops.masterjava.xml.schema.ObjectFactory; import ru.javaops.masterjava.xml.schema.Payload; @@ -7,33 +10,48 @@ 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.XsltProcessor; import javax.xml.bind.JAXBException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.TransformerException; +import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; +import java.io.Writer; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import static com.google.common.io.Resources.getResource; +import static j2html.TagCreator.*; public class MainXml { + private static final URL URL = getResource("payload.xml"); - public static void main(String[] args) throws IOException, JAXBException, SAXException, XMLStreamException { + public static void main(String[] args) throws IOException, JAXBException, SAXException, XMLStreamException, TransformerException { String projectName = args[0]; - getUsersJaxb(projectName).forEach(user -> System.out.println(user.getFullName())); + getProjectUsersJaxb(projectName).forEach(user -> System.out.println(user.getFullName())); System.out.println("----------------------------------"); getUsersStax(projectName).forEach(System.out::println); + System.out.println("----------------------------------"); + Writer bw = Files.newBufferedWriter(Paths.get("users.html")); + bw.write(toHtml(getProjectUsersByStax(projectName), projectName).toString()); + bw.close(); + try (Writer writer = Files.newBufferedWriter(Paths.get("groups.html"))) { + writer.write(xsltTransform(projectName)); + } } - private static Set getUsersJaxb(String projectName) throws JAXBException, IOException { + private static Set getProjectUsersJaxb(String projectName) throws JAXBException, IOException { JaxbParser jaxbParser = new JaxbParser(ObjectFactory.class); jaxbParser.setSchema(Schemas.ofClasspath("payload.xsd")); - Payload payLoad = jaxbParser.unmarshal(getResource("payload.xml").openStream()); + Payload payLoad = jaxbParser.unmarshal(URL.openStream()); Project project = payLoad.getProjects().getProject().stream().filter(p -> p.getName().equals(projectName)).findFirst() .orElseThrow(() -> new RuntimeException("Project not found: " + projectName)); @@ -44,66 +62,182 @@ private static Set getUsersJaxb(String projectName) throws JAXBException, return users.stream() .filter(user -> !Collections.disjoint(groups, user.getUserGroup())) - .sorted(Comparator.comparing(User::getFullName)) + .sorted(Comparator.comparing(user -> user.getFullName().toLowerCase())) .collect(Collectors.toCollection(LinkedHashSet::new)); } private static Set getUsersStax(String projectName) throws XMLStreamException, IOException { - URL url = getResource("payload.xml"); - InputStream is = url.openStream(); + InputStream is = URL.openStream(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader parser = factory.createXMLStreamReader(is); Map> projectGroups = new HashMap<>(); Map> userGroups = new HashMap<>(); + Map> userGroupsMap = new HashMap<>(); while (parser.hasNext()) { - if (parser.next() == XMLStreamReader.START_ELEMENT) { - if (parser.getLocalName().equalsIgnoreCase("project")) { - if (parser.getAttributeValue(null, "name").equals(projectName)) { - Set groups = new HashSet<>(); - projectGroups.put(projectName, groups); - INSIDE_GROUP: + switch (parser.next()) { + case XMLStreamReader.START_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("project")) { + if (parser.getAttributeValue(null, "name").equals(projectName)) { + Set groups = new HashSet<>(); + projectGroups.put(projectName, groups); + INSIDE_GROUP: + while (parser.hasNext()) { + switch (parser.next()) { + case XMLStreamReader.START_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("group")) { + groups.add(parser.getAttributeValue(null, "name")); + } + break; + case XMLStreamReader.END_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("project")) { + break INSIDE_GROUP; + } + break; + } + } + } + } + if (parser.getLocalName().equalsIgnoreCase("user")) { + String userGroupsAsString = parser.getAttributeValue(null, "userGroup"); + String userEmail = parser.getAttributeValue(null, "email"); + INSIDE_USER: while (parser.hasNext()) { - int eventType = parser.next(); - switch (eventType) { + switch (parser.next()) { case XMLStreamReader.START_ELEMENT: - if (parser.getLocalName().equalsIgnoreCase("group")) { - groups.add(parser.getAttributeValue(null, "name")); + String userName = parser.getElementText(); + if (userGroupsAsString != null && !userGroupsAsString.isEmpty()) { + Set groupsOfUser = Arrays.stream(userGroupsAsString.split(" ")).collect(Collectors.toSet()); + userGroups.put(userName, groupsOfUser); + User user = new User(); + user.setFullName(userName); + user.setEmail(userEmail); + user.setUserGroup(new ArrayList<>(groupsOfUser)); + userGroupsMap.put(user, groupsOfUser); } break; case XMLStreamReader.END_ELEMENT: - if (parser.getLocalName().equalsIgnoreCase("project")) { - break INSIDE_GROUP; - } - break; + break INSIDE_USER; } } } - } - if (parser.getLocalName().equalsIgnoreCase("user")) { - String groupsString = parser.getAttributeValue(null, "userGroup"); - INSIDE_USER: - while (parser.hasNext()) { - int event = parser.next(); - switch (event) { - case XMLStreamReader.START_ELEMENT: - String user = parser.getElementText(); - if (groupsString != null && !groupsString.isEmpty()) { - userGroups.put(user, Arrays.stream(groupsString.split(" ")).collect(Collectors.toSet())); - } - break; - case XMLStreamReader.END_ELEMENT: - break INSIDE_USER; - } - } - } + break; + case XMLStreamReader.END_DOCUMENT: + default: + break; } } + Set projectUsers = new TreeSet<>(Comparator.comparing(String::toLowerCase)); - userGroups.forEach((name, groups) -> { - if (!Collections.disjoint(groups, projectGroups.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()))) { - projectUsers.add(name); + userGroups.forEach((userName, usersGroups) -> { + if (!Collections.disjoint(usersGroups, projectGroups.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()))) { + projectUsers.add(userName); } }); +// userGroupsMap.forEach((user, groups) -> System.out.printf("user: name = %s, email = %s, groups = %s <-> %s%n", +// user.getFullName(), user.getEmail(), user.getUserGroup(), groups)); +// System.out.println("-----------"); +// // 4: Сделать реализацию MainXml через StAX (выводить имя/email) +// Set users = userGroupsMap.keySet(); +// userGroupsMap.entrySet().stream() +// .filter(entry -> !Collections.disjoint(users.stream() +// .map(User::getUserGroup) +// .flatMap(Collection::stream) +// .collect(Collectors.toSet()), entry.getValue())) +// .map(Map.Entry::getKey) +// .collect(Collectors.toList()) +// .stream() +// .sorted(Comparator.comparing((User user) -> user.getFullName().toLowerCase()) +// .thenComparing(user -> user.getEmail().toLowerCase())) +// .forEach(user -> System.out.printf("%20s %20s%n", user.getFullName(), user.getEmail())); return projectUsers; } + + private static Set getProjectUsersByStax(String projectName) throws XMLStreamException, IOException { + InputStream is = URL.openStream(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLStreamReader parser = factory.createXMLStreamReader(is); + Map> projectGroups = new HashMap<>(); + Map> userGroupsMap = new HashMap<>(); + while (parser.hasNext()) { + switch (parser.next()) { + case XMLStreamReader.START_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("project")) { + if (parser.getAttributeValue(null, "name").equals(projectName)) { + Set groups = new HashSet<>(); + projectGroups.put(projectName, groups); + INSIDE_GROUP: + while (parser.hasNext()) { + switch (parser.next()) { + case XMLStreamReader.START_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("group")) { + groups.add(parser.getAttributeValue(null, "name")); + } + break; + case XMLStreamReader.END_ELEMENT: + if (parser.getLocalName().equalsIgnoreCase("project")) { + break INSIDE_GROUP; + } + break; + } + } + } + } + if (parser.getLocalName().equalsIgnoreCase("user")) { + String userGroupsAsString = parser.getAttributeValue(null, "userGroup"); + String userEmail = parser.getAttributeValue(null, "email"); + INSIDE_USER: + while (parser.hasNext()) { + switch (parser.next()) { + case XMLStreamReader.START_ELEMENT: + String userName = parser.getElementText(); + if (userGroupsAsString != null && !userGroupsAsString.isEmpty()) { + Set groupsOfUser = Arrays.stream(userGroupsAsString.split(" ")).collect(Collectors.toSet()); + User user = new User(); + user.setFullName(userName); + user.setEmail(userEmail); + user.setUserGroup(new ArrayList<>(groupsOfUser)); + userGroupsMap.put(user, groupsOfUser); + } + break; + case XMLStreamReader.END_ELEMENT: + break INSIDE_USER; + } + } + } + break; + case XMLStreamReader.END_DOCUMENT: + default: + break; + } + } + + return userGroupsMap.keySet(); + } + + //5: Из списка участников сделать html таблицу (имя/email). Реализация- любая. + private static HtmlTag toHtml(Set users, String projectName) { + final ContainerTag table = table().with( + tr().with(th("FullName"), th("email"))) + .attr("border", "2") + .attr("cellpadding", "18") + .attr("cellspacing", "1"); + users.forEach(u -> table.with(tr().with(td(u.getFullName()), td(u.getEmail())))); + return html().with( + head().with(title(projectName + " users")), + body().with(h1(projectName + " users"), table)); +// .render(); + } + + public static String xsltTransform(String project) throws IOException, TransformerException { + try (InputStream xslInputStream = Resources.getResource("payload.xsl").openStream(); + InputStream xmlInputStream = Resources.getResource("payload.xml").openStream()) { + + XsltProcessor processor = new XsltProcessor(xslInputStream); + processor.setParameter("project", project); + String transform = processor.transform(xmlInputStream); + return transform; + } + } + + } diff --git a/src/main/java/ru/javaops/masterjava/xml/schema/User.java b/src/main/java/ru/javaops/masterjava/xml/schema/User.java index 604a115..82b6cff 100644 --- a/src/main/java/ru/javaops/masterjava/xml/schema/User.java +++ b/src/main/java/ru/javaops/masterjava/xml/schema/User.java @@ -193,4 +193,16 @@ public List getUserGroup() { return this.userGroup; } + public void setUserGroup(List userGroup) { + this.userGroup = userGroup; + } + + @Override + public String toString() { + return "User{" + + "fullName='" + fullName + '\'' + + ", email='" + email + '\'' + + ", userGroup=" + userGroup + + '}'; + } } diff --git a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java index 019eeed..3ee1c21 100644 --- a/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java +++ b/src/main/java/ru/javaops/masterjava/xml/util/XsltProcessor.java @@ -40,4 +40,8 @@ public void transform(Reader sourceReader, Writer result) throws TransformerExce public static String getXsltHeader(String xslt) { return "\n"; } + + public void setParameter(String name, String vladim) { + xformer.setParameter(name, vladim); + } } diff --git a/src/main/resources/cities.xsl b/src/main/resources/cities.xsl index 1c50912..c1c40df 100644 --- a/src/main/resources/cities.xsl +++ b/src/main/resources/cities.xsl @@ -1,9 +1,11 @@ - - + + + - + - \ No newline at end of file + \ No newline at end of file diff --git a/src/main/resources/projects.xsl b/src/main/resources/projects.xsl new file mode 100644 index 0000000..97ed98f --- /dev/null +++ b/src/main/resources/projects.xsl @@ -0,0 +1,10 @@ + + + + + + + + + + \ 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 index 199f676..676cb1e 100644 --- a/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java +++ b/src/test/java/ru/javaops/masterjava/xml/util/XPathProcessorTest.java @@ -23,4 +23,17 @@ public void getCities() throws Exception { ); } } + @Test + public void getProjects() throws Exception { + try (InputStream is = + Resources.getResource("payload.xml").openStream()) { + XPathProcessor processor = new XPathProcessor(is); + XPathExpression expression = + XPathProcessor.getExpression("/*[name()='Payload']/*[name()='Projects']/*[name()='Project']/*[name()='Group']/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 index d7f42a6..c616adc 100644 --- a/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java +++ b/src/test/java/ru/javaops/masterjava/xml/util/XsltProcessorTest.java @@ -3,16 +3,25 @@ import com.google.common.io.Resources; import org.junit.Test; +import java.io.BufferedWriter; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; public class XsltProcessorTest { @Test public void transform() throws Exception { - try (InputStream xslInputStream = Resources.getResource("cities.xsl").openStream(); - InputStream xmlInputStream = Resources.getResource("payload.xml").openStream()) { + try (InputStream xslInputStream = Resources.getResource("payload.xsl").openStream(); + InputStream xmlInputStream = Resources.getResource("payload.xml").openStream(); + BufferedWriter bw = Files.newBufferedWriter(Paths.get("payload.html"));) { XsltProcessor processor = new XsltProcessor(xslInputStream); - System.out.println(processor.transform(xmlInputStream)); + processor.setParameter("project", "topjava"); + String transform = processor.transform(xmlInputStream); + System.out.println(transform); + + bw.write(transform); } } }