diff --git a/.gitignore b/.gitignore
index b6065fb..b8174c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ hs_err_pid*
*.iml
.idea
-target
\ No newline at end of file
+target
+logs
diff --git a/hw03-gc/Conclusions.md b/hw03-gc/Conclusions.md
new file mode 100644
index 0000000..6bfba4c
--- /dev/null
+++ b/hw03-gc/Conclusions.md
@@ -0,0 +1,52 @@
+#
+**Статистика работы сборщиков мусора (java-11-openjdk)**
+
+Имя | Событие | Длительность,мс
+--- | :---: | :---:
+|**Serial**|
+Copy | 4 | 474 |
+MarkSweepCompact | 1 | 675
+|**Parallel**|
+PS Scavenge | 3 | 195
+PS MarkSweep | 5 | 4496
+|**CMS**|
+ParNew | 4 | 547
+ConcurrentMarkSweep | 40 | 155899
+|**G1**|
+G1 Young Generation | 16 | 223
+G1 Old Generation | 1 | 296
+
+**Статистика работы сборщиков мусора (java-14-oracle)**
+
+Имя | Событие | Длительность,мс
+--- | :---: | :---:
+|**Serial**|
+Copy | 4 | 429 |
+MarkSweepCompact | 1 | 461
+|**Parallel**|
+PS Scavenge | 3 | 203
+PS MarkSweep | 3 | 2100
+|**G1**|
+G1 Young Generation | 16 | 264
+G1 Old Generation | 1 | 314
+
+**Время работы приложения при использовании разных сборщиков мусора и jdk**
+
+Сборщик мусора|Время работы приложения (java-11-openjdk), с |Время работы приложения (java-14-oracle), с
+---| :---:| :---:
+Serial | 281 | 370
+Parallel | 314 | 337
+CMS | 342 | -
+G1 | 397 | 383
+
+ **Выводы:**
+
+ - Для написанного приложения лучше всего показал себя G1 сборщик мусора. С G1 приложение работало
+ дольше, общая длительность пауз была меньше, чем с Serial, Parallel, CMS сборщиками;
+ - Минорные сборки G1 начинались раньше (при размере heap 20Mb, тогда как для других GC первые
+ сборки стартовали при размере heap больше 100Mb), выполнялись чаще (G1 имеет максимальное число
+ минорных сборок из рассмотренных сборщиков мусора) и были короткими (время на одну минорную сборку
+ минимально у G1, общая длительность минорных сборок меньше, чем у Serial и CMS сборщиков);
+ - Эффективность Parallel и CMS сборщиков мусора оказалась наименьшей: полных сборок мусора было больше,
+ приложение останавливалось чаще, время, затраченное на сборку мусора, значительно превышало аналогичное
+ значение для Serial и G1 сборщиков.
diff --git a/hw03-gc/README.md b/hw03-gc/README.md
new file mode 100644
index 0000000..5f638fd
--- /dev/null
+++ b/hw03-gc/README.md
@@ -0,0 +1,19 @@
+# Сравнение разных сборщиков мусора
+ Написать приложение, которое следит за сборками мусора и пишет в лог количество сборок каждого типа
+ (young, old) и время которое ушло на сборки в минуту.
+
+ Добиться OutOfMemory в этом приложении через медленное подтекание по памяти
+ (например добавлять элементы в List и удалять только половину).
+
+ Настроить приложение (можно добавлять Thread.sleep(...)) так чтобы оно падало
+ с OOM примерно через 5 минут после начала работы.
+
+ Собрать статистику (количество сборок, время на сборки) по разным GC.
+
+ !!! Сделать выводы !!!
+ ЭТО САМАЯ ВАЖНАЯ ЧАСТЬ РАБОТЫ:
+ Какой gc лучше и почему?
+
+ Выводы оформить в файле Сonclusions.md в корне папки проекта.
+ Результаты измерений сведите в таблицу.
+
\ No newline at end of file
diff --git a/hw03-gc/pom.xml b/hw03-gc/pom.xml
new file mode 100644
index 0000000..9ee3b5e
--- /dev/null
+++ b/hw03-gc/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ ru.otus
+ otus-java
+ 2019-09-SNAPSHOT
+
+
+ hw03-gc
+ jar
+ hw03-gc
+
+
+ 11
+ 11
+
+
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+ ${project.name}
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
diff --git a/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java b/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java
new file mode 100644
index 0000000..1ddcdab
--- /dev/null
+++ b/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java
@@ -0,0 +1,72 @@
+package ru.otus.homework;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * -Xms512m
+ * -Xmx512m
+ * -Xlog:gc=debug:file=./logs/gc.log:tags,uptime,time,level:filecount=10,filesize=10m
+ * -XX:+HeapDumpOnOutOfMemoryError
+ * -XX:HeapDumpPath=./logs/dump
+ * -XX:+UseG1GC
+ *
+ * -XX:+UseSerialGC
+ * -XX:+UseParallelGC
+ * -XX:+UseConcMarkSweepGC
+ * -XX:+UseG1GC
+ */
+public class GcDemo {
+ private static final Logger LOG = LoggerFactory.getLogger(GcDemo.class);
+
+ public static void main(String[] args) {
+ new GcDemo().startDemo();
+ }
+
+ private void startDemo() {
+ Map> map = new HashMap<>();
+ GcStatistic gcStatistic = new GcStatistic(map);
+ gcStatistic.switchOnMonitoring();
+
+ long beginTime = System.currentTimeMillis();
+ List list = readFile();
+
+ MemoryLeakApp appDemo = new MemoryLeakApp(list);
+ try {
+ appDemo.run();
+ } catch (OutOfMemoryError e) {
+ LOG.info("time: {}", (System.currentTimeMillis() - beginTime) / 1000);
+ LOG.info("GC statistic: {}", map);
+ LOG.info("Out of memory error", e);
+ }
+ }
+
+ private List readFile() {
+ List list = new ArrayList<>();
+ try {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ InputStream in = classLoader.getResourceAsStream("example.txt");
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String[] ar = line.split(" ");
+ list.addAll(Arrays.asList(ar));
+ }
+ }
+ } catch (IOException e) {
+ LOG.error("Can not read file ", e);
+ }
+ return list;
+ }
+}
diff --git a/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java b/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java
new file mode 100644
index 0000000..d780d2d
--- /dev/null
+++ b/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java
@@ -0,0 +1,62 @@
+package ru.otus.homework;
+
+import com.sun.management.GarbageCollectionNotificationInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationListener;
+import javax.management.openmbean.CompositeData;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class GcStatistic {
+ private static final Logger LOG = LoggerFactory.getLogger(GcStatistic.class);
+ private final Map> map;
+
+ public GcStatistic(Map> map) {
+ this.map = map;
+ }
+
+ public void switchOnMonitoring() {
+ List gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
+ final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+ for (GarbageCollectorMXBean gcbean : gcBeans) {
+ LOG.info("GC name: {}", gcbean.getName());
+ NotificationEmitter emitter = (NotificationEmitter) gcbean;
+ NotificationListener listener = (Notification notification, Object handback) -> {
+ if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
+ handleNotification(notification,
+ memoryMXBean.getHeapMemoryUsage().getUsed());
+ }
+ };
+ emitter.addNotificationListener(listener, null, null);
+ }
+ }
+
+ private void handleNotification(Notification notification, long memoryUsed) {
+ GarbageCollectionNotificationInfo info =
+ GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
+ String gcName = info.getGcName();
+ long duration = info.getGcInfo().getDuration();
+
+ String heapMemory = String.format("%.2f Mb", (double)memoryUsed / 1_048_576);
+ LOG.info("Name: {}, action: {}, cause: {} ({} ms). Used heap memory {}",
+ info.getGcName(), info.getGcAction(), info.getGcCause(), duration,
+ heapMemory);
+
+ if (map.containsKey(gcName)) {
+ Map actionStatistic = map.get(gcName);
+ long eventCount = actionStatistic.entrySet().iterator().next().getKey();
+ long sumDuration = actionStatistic.get(eventCount) + duration;
+ map.put(gcName, Collections.singletonMap(eventCount + 1, sumDuration));
+ } else {
+ map.put(gcName, Collections.singletonMap(1L, duration));
+ }
+ }
+}
diff --git a/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java b/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java
new file mode 100644
index 0000000..7f1a62b
--- /dev/null
+++ b/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java
@@ -0,0 +1,24 @@
+package ru.otus.homework;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MemoryLeakApp {
+ private static final List TEMP = new ArrayList<>();
+ private static final int ITERATION = 100_000;
+ private final List init = new ArrayList<>();
+
+ public MemoryLeakApp(List in) {
+ init.addAll(in);
+ }
+
+ public void run() {
+ for (int i = 0; i < ITERATION; i++) {
+ TEMP.addAll(init);
+ for (int j = 0; j < ITERATION / 2; j++) {
+ TEMP.add("empty" + i);
+ }
+ TEMP.removeAll(init);
+ }
+ }
+}
diff --git a/hw03-gc/src/main/resources/example.txt b/hw03-gc/src/main/resources/example.txt
new file mode 100644
index 0000000..bd0602d
--- /dev/null
+++ b/hw03-gc/src/main/resources/example.txt
@@ -0,0 +1,7 @@
+start:618 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(88 ms) start:779 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(114 ms)
+start:939 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(85 ms) start:1076 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(53 ms)
+start:1159 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(52 ms) start:1350 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(44 ms)
+start:1414 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(37 ms) start:1476 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(69 ms)
+start:1579 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(98 ms) start:1803 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Humongous Allocation(72 ms)
+start:1935 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(154 ms) start:2141 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(108 ms)
+start:2411 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(105 ms) start:2614 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(130 ms)
diff --git a/hw03-gc/src/main/resources/logback.xml b/hw03-gc/src/main/resources/logback.xml
new file mode 100644
index 0000000..08fc1ec
--- /dev/null
+++ b/hw03-gc/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ %d{HH:mm:ss.SSS} - %msg%n
+
+
+
+
+
+
+
diff --git a/hw04-logging/README.md b/hw04-logging/README.md
new file mode 100644
index 0000000..d9dc649
--- /dev/null
+++ b/hw04-logging/README.md
@@ -0,0 +1,22 @@
+# Автомагическое логирование.
+ Разработайте такой функционал:
+ метод класса можно пометить самодельной аннотацией @Log, например, так:
+
+ class TestLogging {
+ @Log
+ public void calculation(int param) {};
+ }
+
+ При вызове этого метода "автомагически" в консоль должны логироваться
+ значения параметров. Например так.
+
+ class Demo {
+ public void action() {
+ new TestLogging().calculation(6);
+ }
+ }
+
+ В консоли дожно быть:
+ executed method: calculation, param: 6
+
+ Обратите внимание: явного вызова логирования быть не должно.
\ No newline at end of file
diff --git a/hw04-logging/pom.xml b/hw04-logging/pom.xml
new file mode 100644
index 0000000..8657a35
--- /dev/null
+++ b/hw04-logging/pom.xml
@@ -0,0 +1,64 @@
+
+
+ 4.0.0
+
+
+ ru.otus
+ otus-java
+ 2019-09-SNAPSHOT
+
+
+ hw04-logging
+ hw04-logging
+
+
+ 7.2
+ 3.2.1
+
+
+
+
+ org.ow2.asm
+ asm
+ ${asm.version}
+
+
+ org.ow2.asm
+ asm-commons
+ ${asm.version}
+
+
+
+
+
+
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ asmDemo
+ package
+
+ shade
+
+
+ target/asmDemo.jar
+
+
+
+ ru.otus.homework.demo.AsmDemo
+ ru.otus.homework.asm.Agent
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java b/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java
new file mode 100644
index 0000000..2b490d0
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java
@@ -0,0 +1,11 @@
+package ru.otus.homework.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Log {
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java b/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java
new file mode 100644
index 0000000..c0c96f8
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java
@@ -0,0 +1,49 @@
+package ru.otus.homework.asm;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+
+public class Agent {
+ private static final String OUTPUT_FILE = "proxyASM.class";
+
+ public static void premain(String agentArgs, Instrumentation inst) {
+
+ inst.addTransformer(new ClassFileTransformer() {
+ @Override
+ public byte[] transform(ClassLoader loader, String className,
+ Class> classBeingRedefined,
+ ProtectionDomain protectionDomain,
+ byte[] classfileBuffer) {
+ if (className.equals(agentArgs)) {
+ return scanLogAnnotation(classfileBuffer);
+ }
+ return classfileBuffer;
+ }
+ });
+ }
+
+ private static byte[] scanLogAnnotation(byte[] classfileBuffer) {
+ ClassReader reader = new ClassReader(classfileBuffer);
+ ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
+ ClassVisitor visitor = new LogClassVisitor(writer);
+ reader.accept(visitor, Opcodes.ASM5);
+
+ byte[] finalClass = writer.toByteArray();
+
+ try (OutputStream fos = new FileOutputStream(OUTPUT_FILE)) {
+ fos.write(finalClass);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return finalClass;
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java b/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java
new file mode 100755
index 0000000..12fb5ec
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java
@@ -0,0 +1,21 @@
+package ru.otus.homework.asm;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class LogClassVisitor extends ClassVisitor implements Opcodes {
+
+ public LogClassVisitor(ClassVisitor writer) {
+ super(ASM5, writer);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String methodName, String desc,
+ String signature, String[] exceptions) {
+
+ MethodVisitor methodVisitor = cv.visitMethod(access, methodName, desc, signature,
+ exceptions);
+ return new LogMethodVisitor(methodVisitor, methodName, desc, access);
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java b/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java
new file mode 100755
index 0000000..8a3398f
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java
@@ -0,0 +1,93 @@
+package ru.otus.homework.asm;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Add logging if method has @Log annotation
+ */
+public class LogMethodVisitor extends MethodVisitor implements Opcodes {
+ private static final String LOG_ANNOTATION = "Lru/otus/homework/annotation/Log;";
+
+ private final String methodName;
+ private final String descriptor;
+ private final int access;
+ private boolean isAnnotationPresent;
+
+ public LogMethodVisitor(MethodVisitor methodVisitor, String methodName, String descriptor, int access) {
+ super(ASM5, methodVisitor);
+ this.methodName = methodName;
+ this.descriptor = descriptor;
+ this.access = access;
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (LOG_ANNOTATION.equals(desc)) {
+ isAnnotationPresent = true;
+ }
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public void visitCode() {
+ if (isAnnotationPresent) {
+ Type[] argTypes = Type.getArgumentTypes(descriptor);
+ int i = (access | ACC_STATIC) == 0 ? 0 : 1;
+ int index = argTypes.length + i;
+
+ mv.visitIntInsn(BIPUSH, argTypes.length);
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+ int x = 0;
+ for (Type t : argTypes) {
+ mv.visitInsn(DUP);
+ mv.visitIntInsn(BIPUSH, x);
+ if (t.equals(Type.BOOLEAN_TYPE)) {
+ mv.visitVarInsn(ILOAD, i);
+ invokeStatic("java/lang/Boolean", "(Z)Ljava/lang/Boolean;");
+ } else if (t.equals(Type.BYTE_TYPE)) {
+ mv.visitVarInsn(ILOAD, i);
+ invokeStatic("java/lang/Byte", "(B)Ljava/lang/Byte;");
+ } else if (t.equals(Type.CHAR_TYPE)) {
+ mv.visitVarInsn(ILOAD, i);
+ invokeStatic("java/lang/Character", "(C)Ljava/lang/Character;");
+ } else if (t.equals(Type.SHORT_TYPE)) {
+ mv.visitVarInsn(ILOAD, i);
+ invokeStatic("java/lang/Short", "(S)Ljava/lang/Short;");
+ } else if (t.equals(Type.INT_TYPE)) {
+ mv.visitVarInsn(ILOAD, i);
+ invokeStatic("java/lang/Integer", "(I)Ljava/lang/Integer;");
+ } else if (t.equals(Type.LONG_TYPE)) {
+ mv.visitVarInsn(LLOAD, i);
+ invokeStatic("java/lang/Long", "(J)Ljava/lang/Long;");
+ i++;
+ } else if (t.equals(Type.FLOAT_TYPE)) {
+ mv.visitVarInsn(FLOAD, i);
+ invokeStatic("java/lang/Float", "(F)Ljava/lang/Float;");
+ } else if (t.equals(Type.DOUBLE_TYPE)) {
+ mv.visitVarInsn(DLOAD, i);
+ invokeStatic("java/lang/Double", "(D)Ljava/lang/Double;");
+ i++;
+ } else {
+ mv.visitVarInsn(ALOAD, i);
+ }
+ mv.visitInsn(AASTORE);
+ i++;
+ x++;
+ }
+ mv.visitVarInsn(ASTORE, index);
+ this.visitLdcInsn(methodName);
+ this.visitVarInsn(ALOAD, index);
+ mv.visitMethodInsn(INVOKESTATIC, "ru/otus/homework/asm/Logger", "logMethod",
+ "(Ljava/lang/String;[Ljava/lang/Object;)V", false);
+ }
+ super.visitCode();
+ }
+
+ private void invokeStatic(String owner, String descriptor) {
+ mv.visitMethodInsn(INVOKESTATIC, owner, "valueOf", descriptor, false);
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java b/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java
new file mode 100755
index 0000000..5cfc943
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java
@@ -0,0 +1,22 @@
+package ru.otus.homework.asm;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * This class is called by LogMethodVisitor to log method`s name and arguments
+ */
+public class Logger {
+
+ public static void logMethod(String methodName, Object[] args) {
+ String log = String.format("executed method %s", methodName);
+ if (args.length > 0) {
+ String params = Arrays.stream(args).
+ filter(Objects::nonNull).
+ map(Object::toString).collect(Collectors.joining(", "));
+ log = log.concat(", params: ").concat(params);
+ }
+ System.out.println(log);
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java b/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java
new file mode 100755
index 0000000..eff8dc9
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java
@@ -0,0 +1,21 @@
+package ru.otus.homework.demo;
+
+/*
+ * Class with methods which has @Log annotation should be passed as argument for javaagent:
+ *
+ * java -javaagent:target/asmDemo.jar=ru/otus/homework/demo/TestLogging -jar target/asmDemo.jar
+ */
+public class AsmDemo {
+
+ public static void main(String[] args) {
+ TestLogging testLogging = new TestLogging();
+ testLogging.testNoArgs();
+ testLogging.testNoLog();
+ testLogging.testObject(new TestObject("string", 357));
+ testLogging.testInt(3, 2, 1);
+ testLogging.testIntegerFloatDouble(1, 2.1f, 3.111111);
+ testLogging.testBooleanShortByte(true, (short) 1, (byte) 1);
+ testLogging.testLongDouble(5L, 7.8);
+ testLogging.testStringChar("asdfg", 't');
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java b/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java
new file mode 100755
index 0000000..d4bb803
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java
@@ -0,0 +1,49 @@
+package ru.otus.homework.demo;
+
+import ru.otus.homework.annotation.Log;
+
+/**
+ * Test class
+ */
+public class TestLogging {
+
+ @Log
+ public void testInt(int param1, int param2, int param3) {
+ System.out.println("Multiple int");
+ }
+
+ @Log
+ public void testIntegerFloatDouble(Integer i, Float f, Double d) {
+ System.out.println("Test integer, float");
+ }
+
+ @Log
+ public void testBooleanShortByte(boolean bool, short s, byte b) {
+ System.out.println("Test boolean, short, byte");
+ }
+
+ @Log
+ public void testLongDouble(long l, double d){
+ System.out.println("Test long, double");
+ }
+
+ public void testNoLog() {
+ System.out.println("Log annotation is absent");
+ }
+
+ @Log
+ public void testNoArgs() {
+ System.out.println("No arguments");
+ }
+
+ @Log
+ public void testObject(TestObject o) {
+ System.out.println("Test object");
+ }
+
+ @Log
+ public String testStringChar(String s, char a) {
+ System.out.println("Test string and char");
+ return s;
+ }
+}
diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java b/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java
new file mode 100644
index 0000000..83a1afd
--- /dev/null
+++ b/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java
@@ -0,0 +1,19 @@
+package ru.otus.homework.demo;
+
+public class TestObject {
+ private String s;
+ private int i;
+
+ public TestObject(String s, int i) {
+ this.s = s;
+ this.i = i;
+ }
+
+ @Override
+ public String toString() {
+ return "TestObject{" +
+ "s='" + s + '\'' +
+ ", i=" + i +
+ '}';
+ }
+}
diff --git a/pom.xml b/pom.xml
index 97e4408..5242e0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,6 +16,7 @@
hw01-maven
hw02-arrayList
+ hw04-logging
hw05-testFramework
hw06-atm
hw07-atm-department