diff --git a/aop/build.gradle b/aop/build.gradle new file mode 100644 index 00000000..2bf2e09c --- /dev/null +++ b/aop/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'java-library' +} + +group = 'com.callv2' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + + implementation 'org.aspectj:aspectjrt:1.9.24' + + testImplementation 'org.junit.jupiter:junit-jupiter:5.11.4' + testImplementation 'org.mockito:mockito-junit-jupiter:5.15.2' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/aop/src/main/java/com/callv2/aop/context/AbstractInvocationContext.java b/aop/src/main/java/com/callv2/aop/context/AbstractInvocationContext.java new file mode 100644 index 00000000..5f16443c --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/AbstractInvocationContext.java @@ -0,0 +1,89 @@ +package com.callv2.aop.context; + +import java.time.Instant; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.reflect.SourceLocation; +import org.aspectj.runtime.internal.AroundClosure; + +public abstract class AbstractInvocationContext implements InvocationContext { + + protected final ProceedingJoinPoint joinPoint; + protected final AtomicBoolean proceeded; + private final Instant contextedAt; + + protected AbstractInvocationContext(final ProceedingJoinPoint joinPoint) { + this.joinPoint = joinPoint; + this.proceeded = new AtomicBoolean(false); + this.contextedAt = Instant.now(); + } + + protected AbstractInvocationContext(final PreInvocationContext preInvocationContext) { + this.joinPoint = preInvocationContext; + this.proceeded = new AtomicBoolean(preInvocationContext.proceeded()); + this.contextedAt = preInvocationContext.getContextedAt(); + } + + @Override + public void set$AroundClosure(AroundClosure arc) { + this.joinPoint.set$AroundClosure(arc); + } + + @Override + public String toShortString() { + return this.joinPoint.toShortString(); + } + + @Override + public String toLongString() { + return this.joinPoint.toLongString(); + } + + @Override + public Object getThis() { + return this.joinPoint.getThis(); + } + + @Override + public Object getTarget() { + return this.joinPoint.getTarget(); + } + + @Override + public Object[] getArgs() { + return this.joinPoint.getArgs(); + } + + @Override + public Signature getSignature() { + return this.joinPoint.getSignature(); + } + + @Override + public SourceLocation getSourceLocation() { + return this.joinPoint.getSourceLocation(); + } + + @Override + public String getKind() { + return this.joinPoint.getKind(); + } + + @Override + public StaticPart getStaticPart() { + return this.joinPoint.getStaticPart(); + } + + @Override + public Instant getContextedAt() { + return this.contextedAt; + } + + @Override + public boolean proceeded() { + return this.proceeded.get(); + } + +} diff --git a/aop/src/main/java/com/callv2/aop/context/InvocationContext.java b/aop/src/main/java/com/callv2/aop/context/InvocationContext.java new file mode 100644 index 00000000..84e485fd --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/InvocationContext.java @@ -0,0 +1,13 @@ +package com.callv2.aop.context; + +import java.time.Instant; + +import org.aspectj.lang.ProceedingJoinPoint; + +public interface InvocationContext extends ProceedingJoinPoint { + + Instant getContextedAt(); + + boolean proceeded(); + +} diff --git a/aop/src/main/java/com/callv2/aop/context/PostInvocationContext.java b/aop/src/main/java/com/callv2/aop/context/PostInvocationContext.java new file mode 100644 index 00000000..f2a9f5b2 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/PostInvocationContext.java @@ -0,0 +1,15 @@ +package com.callv2.aop.context; + +import java.time.Instant; + +public interface PostInvocationContext extends InvocationContext { + + Instant getProceededAt(); + + Object getResult(); + + Throwable getThrowable(); + + boolean wasSuccessful(); + +} \ No newline at end of file diff --git a/aop/src/main/java/com/callv2/aop/context/PreInvocationContext.java b/aop/src/main/java/com/callv2/aop/context/PreInvocationContext.java new file mode 100644 index 00000000..b2989833 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/PreInvocationContext.java @@ -0,0 +1,7 @@ +package com.callv2.aop.context; + +public interface PreInvocationContext extends InvocationContext { + + PostInvocationContext proceedWithContext(); + +} diff --git a/aop/src/main/java/com/callv2/aop/context/SimplePostInvocationContext.java b/aop/src/main/java/com/callv2/aop/context/SimplePostInvocationContext.java new file mode 100644 index 00000000..d150913b --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/SimplePostInvocationContext.java @@ -0,0 +1,98 @@ +package com.callv2.aop.context; + +import java.time.Instant; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class SimplePostInvocationContext extends AbstractInvocationContext implements PostInvocationContext { + + private final Object result; + private final Throwable throwable; + private final Instant proceededAt; + private final AtomicBoolean successful; + + private SimplePostInvocationContext( + final PreInvocationContext preInvocationContext, + final Object result, + final Throwable throwable, + final Instant proceededAt, + final boolean successful) { + super(preInvocationContext); + this.result = result; + this.throwable = throwable; + this.proceededAt = proceededAt; + this.successful = new AtomicBoolean(successful); + } + + protected static SimplePostInvocationContext from(final PreInvocationContext preInvocationContext) { + + Object result; + Throwable throwable; + boolean successful; + final Instant proceededAt; + + try { + result = preInvocationContext.proceed(); + throwable = null; + successful = true; + } catch (Throwable e) { + result = null; + throwable = e; + successful = false; + } finally { + proceededAt = Instant.now(); + } + + return new SimplePostInvocationContext( + preInvocationContext, + result, + throwable, + proceededAt, + successful); + + } + + @Override + public Object proceed() throws Throwable { + if (this.proceeded.get()) { + if (successful.get()) + return result; + else + throw throwable; + } + + return this.joinPoint.proceed(); + } + + @Override + public Object proceed(Object[] args) throws Throwable { + if (this.proceeded.get()) { + if (successful.get()) + return result; + else + throw throwable; + } + + return this.joinPoint.proceed(args); + } + + @Override + public Instant getProceededAt() { + return this.proceededAt; + } + + @Override + public Object getResult() { + return this.result; + } + + @Override + public Throwable getThrowable() { + return this.throwable; + } + + @Override + public boolean wasSuccessful() { + return this.successful.get(); + } + +} diff --git a/aop/src/main/java/com/callv2/aop/context/SimplePreInvocationContext.java b/aop/src/main/java/com/callv2/aop/context/SimplePreInvocationContext.java new file mode 100644 index 00000000..bbda8f5a --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/context/SimplePreInvocationContext.java @@ -0,0 +1,34 @@ +package com.callv2.aop.context; + +import org.aspectj.lang.ProceedingJoinPoint; + +public final class SimplePreInvocationContext extends AbstractInvocationContext implements PreInvocationContext { + + private SimplePreInvocationContext(final ProceedingJoinPoint joinPoint) { + super(joinPoint); + } + + public static SimplePreInvocationContext of(final ProceedingJoinPoint joinPoint) { + return new SimplePreInvocationContext(joinPoint); + } + + @Override + public Object proceed() throws Throwable { + if (proceeded.getAndSet(true)) + throw new IllegalStateException("Method already proceeded"); + return joinPoint.proceed(); + } + + @Override + public Object proceed(Object[] args) throws Throwable { + if (proceeded.getAndSet(true)) + throw new IllegalStateException("Method already proceeded"); + return joinPoint.proceed(args); + } + + @Override + public PostInvocationContext proceedWithContext() { + return SimplePostInvocationContext.from(this); + } + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/Executor.java b/aop/src/main/java/com/callv2/aop/executor/Executor.java new file mode 100644 index 00000000..f735e76e --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/Executor.java @@ -0,0 +1,10 @@ +package com.callv2.aop.executor; + +import org.aspectj.lang.ProceedingJoinPoint; + +@FunctionalInterface +public interface Executor { + + void execute(J joinPoint); + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/PostExecutor.java b/aop/src/main/java/com/callv2/aop/executor/PostExecutor.java new file mode 100644 index 00000000..37642b05 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/PostExecutor.java @@ -0,0 +1,7 @@ +package com.callv2.aop.executor; + +import com.callv2.aop.context.PostInvocationContext; + +public interface PostExecutor extends Executor { + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/PreExecutor.java b/aop/src/main/java/com/callv2/aop/executor/PreExecutor.java new file mode 100644 index 00000000..1fcf32b0 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/PreExecutor.java @@ -0,0 +1,7 @@ +package com.callv2.aop.executor; + +import com.callv2.aop.context.PreInvocationContext; + +public interface PreExecutor extends Executor { + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/ExecutorChain.java b/aop/src/main/java/com/callv2/aop/executor/chain/ExecutorChain.java new file mode 100644 index 00000000..44397761 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/ExecutorChain.java @@ -0,0 +1,32 @@ +package com.callv2.aop.executor.chain; + +import org.aspectj.lang.ProceedingJoinPoint; + +import com.callv2.aop.executor.Executor; + +public abstract class ExecutorChain> { + + private ExecutorChain next; + private final E executor; + + protected ExecutorChain(final E executor) { + this.executor = executor; + } + + public ExecutorChain setNext(final ExecutorChain executorChain) { + return this.next = executorChain; + } + + public final O execute(final J joinpoint) throws Throwable { + + this.executor.execute(joinpoint); + + if (next != null) + return next.execute(joinpoint); + + return resolve(joinpoint); + } + + protected abstract O resolve(J joinPoint) throws Throwable; + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/PostInvocationExecutorChain.java b/aop/src/main/java/com/callv2/aop/executor/chain/PostInvocationExecutorChain.java new file mode 100644 index 00000000..0dedd463 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/PostInvocationExecutorChain.java @@ -0,0 +1,21 @@ +package com.callv2.aop.executor.chain; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.executor.PostExecutor; + +public final class PostInvocationExecutorChain + extends ExecutorChain { + + public PostInvocationExecutorChain(final PostExecutor executor) { + super(executor); + } + + @Override + protected Object resolve(final PostInvocationContext joinPoint) throws Throwable { + if (joinPoint.wasSuccessful()) + return joinPoint.getResult(); + else + throw joinPoint.getThrowable(); + } + +} \ No newline at end of file diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/PreInvocationExecutorChain.java b/aop/src/main/java/com/callv2/aop/executor/chain/PreInvocationExecutorChain.java new file mode 100644 index 00000000..1f6e0b8f --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/PreInvocationExecutorChain.java @@ -0,0 +1,19 @@ +package com.callv2.aop.executor.chain; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.context.PreInvocationContext; +import com.callv2.aop.executor.PreExecutor; + +public final class PreInvocationExecutorChain + extends ExecutorChain { + + public PreInvocationExecutorChain(final PreExecutor executor) { + super(executor); + } + + @Override + protected PostInvocationContext resolve(final PreInvocationContext joinPoint) throws Throwable { + return joinPoint.proceedWithContext(); + } + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/handler/ExecutorChainHandler.java b/aop/src/main/java/com/callv2/aop/executor/chain/handler/ExecutorChainHandler.java new file mode 100644 index 00000000..3d214c6b --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/handler/ExecutorChainHandler.java @@ -0,0 +1,10 @@ +package com.callv2.aop.executor.chain.handler; + +import org.aspectj.lang.ProceedingJoinPoint; + +@FunctionalInterface +public interface ExecutorChainHandler { + + Object handle(final ProceedingJoinPoint joinPoint) throws Throwable; + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandler.java b/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandler.java new file mode 100644 index 00000000..1d7033d8 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandler.java @@ -0,0 +1,53 @@ +package com.callv2.aop.executor.chain.handler; + +import org.aspectj.lang.ProceedingJoinPoint; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.context.SimplePreInvocationContext; +import com.callv2.aop.executor.chain.PostInvocationExecutorChain; +import com.callv2.aop.executor.chain.PreInvocationExecutorChain; + +public final class SimpleExecutorChainHandler implements ExecutorChainHandler { + + private final PreInvocationExecutorChain preInvocationExecutorChain; + private final PostInvocationExecutorChain postInvocationExecutorChain; + private final PostInvocationExecutorChain errorInvocationExecutorChain; + + private final PreInvocationExecutorChain noOpPreInvocationExecutorChain = new PreInvocationExecutorChain(j -> { + }); + + private final PostInvocationExecutorChain noOpPostInvocationExecutorChain = new PostInvocationExecutorChain(j -> { + }); + + public SimpleExecutorChainHandler( + final PreInvocationExecutorChain preInvocationExecutorChain, + final PostInvocationExecutorChain postInvocationExecutorChain, + final PostInvocationExecutorChain errorInvocationExecutorChain) { + this.preInvocationExecutorChain = preInvocationExecutorChain == null ? noOpPreInvocationExecutorChain + : preInvocationExecutorChain; + this.postInvocationExecutorChain = postInvocationExecutorChain == null ? noOpPostInvocationExecutorChain + : postInvocationExecutorChain; + this.errorInvocationExecutorChain = errorInvocationExecutorChain == null ? noOpPostInvocationExecutorChain + : errorInvocationExecutorChain; + } + + @Override + public Object handle(final ProceedingJoinPoint joinPoint) throws Throwable { + + final SimplePreInvocationContext preContext = SimplePreInvocationContext.of(joinPoint); + final PostInvocationContext postContext = preInvocationExecutorChain.execute(preContext); + + if (postContext.wasSuccessful()) + return postInvocationExecutorChain.execute(postContext); + else + errorInvocationExecutorChain.execute(postContext); + + final Throwable throwable = postContext.getThrowable(); + if (throwable != null) + throw throwable; + + throw new IllegalStateException("Invocation failed but no throwable was provided."); + + } + +} diff --git a/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandlerBuilder.java b/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandlerBuilder.java new file mode 100644 index 00000000..6204e8c2 --- /dev/null +++ b/aop/src/main/java/com/callv2/aop/executor/chain/handler/SimpleExecutorChainHandlerBuilder.java @@ -0,0 +1,83 @@ +package com.callv2.aop.executor.chain.handler; + +import java.util.Queue; + +import org.aspectj.lang.ProceedingJoinPoint; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.context.PreInvocationContext; +import com.callv2.aop.executor.Executor; +import com.callv2.aop.executor.PostExecutor; +import com.callv2.aop.executor.PreExecutor; +import com.callv2.aop.executor.chain.ExecutorChain; +import com.callv2.aop.executor.chain.PostInvocationExecutorChain; +import com.callv2.aop.executor.chain.PreInvocationExecutorChain; + +public final class SimpleExecutorChainHandlerBuilder { + + private final Queue> preInvocationExecutorChainQueue; + private final Queue> postInvocationExecutorChainQueue; + private final Queue> errorInvocationExecutorChainQueue; + + public SimpleExecutorChainHandlerBuilder() { + this.preInvocationExecutorChainQueue = new java.util.LinkedList<>(); + this.postInvocationExecutorChainQueue = new java.util.LinkedList<>(); + this.errorInvocationExecutorChainQueue = new java.util.LinkedList<>(); + } + + public static SimpleExecutorChainHandlerBuilder create() { + return new SimpleExecutorChainHandlerBuilder(); + } + + public SimpleExecutorChainHandlerBuilder preExecutor(final PreExecutor executor) { + this.preInvocationExecutorChainQueue.add(new PreInvocationExecutorChain(executor)); + return this; + } + + public SimpleExecutorChainHandlerBuilder postExecutor(final PostExecutor executor) { + this.postInvocationExecutorChainQueue.add(new PostInvocationExecutorChain(executor)); + return this; + } + + public SimpleExecutorChainHandlerBuilder errorExecutor(final PostExecutor executor) { + this.errorInvocationExecutorChainQueue.add(new PostInvocationExecutorChain(executor)); + return this; + } + + private static PreInvocationExecutorChain buildPreInvocationChain( + final Queue> chains) { + + return (PreInvocationExecutorChain) buildInvocationChain(chains); + } + + private PostInvocationExecutorChain buildPostInvocationChain( + Queue> chains) { + + return (PostInvocationExecutorChain) buildInvocationChain(chains); + } + + private static > ExecutorChain buildInvocationChain( + final Queue> chains) { + if (chains.isEmpty()) + return null; + + final var firstChain = chains.poll(); + var chain = firstChain; + + do { + final var next = chains.poll(); + chain = chain.setNext(next); + } while (!chains.isEmpty()); + + return firstChain; + } + + public SimpleExecutorChainHandler build() { + + return new SimpleExecutorChainHandler( + buildPreInvocationChain(preInvocationExecutorChainQueue), + buildPostInvocationChain(postInvocationExecutorChainQueue), + buildPostInvocationChain(errorInvocationExecutorChainQueue)); + } + +} diff --git a/domain/src/main/java/com/callv2/drive/domain/file/File.java b/domain/src/main/java/com/callv2/drive/domain/file/File.java index 99f8679d..cdfdd044 100644 --- a/domain/src/main/java/com/callv2/drive/domain/file/File.java +++ b/domain/src/main/java/com/callv2/drive/domain/file/File.java @@ -136,4 +136,10 @@ private void selfValidate() { throw ValidationException.with("Validation fail has occoured", notification); } + @Override + public String toString() { + return "File [id=" + id + ", owner=" + owner + ", folder=" + folder + ", name=" + name + ", content=" + content + + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + "]"; + } + } \ No newline at end of file diff --git a/domain/src/main/java/com/callv2/drive/domain/file/FileID.java b/domain/src/main/java/com/callv2/drive/domain/file/FileID.java index 9bd05546..3d8de895 100644 --- a/domain/src/main/java/com/callv2/drive/domain/file/FileID.java +++ b/domain/src/main/java/com/callv2/drive/domain/file/FileID.java @@ -18,4 +18,9 @@ public static FileID unique() { return FileID.of(UUID.randomUUID()); } + @Override + public String toString() { + return "FileID [value=" + getValue() + "]"; + } + } diff --git a/domain/src/main/java/com/callv2/drive/domain/folder/Folder.java b/domain/src/main/java/com/callv2/drive/domain/folder/Folder.java index 35beb80d..9e1bc8fa 100644 --- a/domain/src/main/java/com/callv2/drive/domain/folder/Folder.java +++ b/domain/src/main/java/com/callv2/drive/domain/folder/Folder.java @@ -159,4 +159,11 @@ private void selfValidate() { throw ValidationException.with("Validation fail has occoured", notification); } + @Override + public String toString() { + return "Folder [id=" + id + ", rootFolder=" + rootFolder + ", owner=" + owner + ", name=" + name + + ", parentFolder=" + parentFolder + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + + ", deletedAt=" + deletedAt + "]"; + } + } diff --git a/domain/src/main/java/com/callv2/drive/domain/folder/FolderID.java b/domain/src/main/java/com/callv2/drive/domain/folder/FolderID.java index e5c4d642..eab47e85 100644 --- a/domain/src/main/java/com/callv2/drive/domain/folder/FolderID.java +++ b/domain/src/main/java/com/callv2/drive/domain/folder/FolderID.java @@ -18,4 +18,9 @@ public static FolderID unique() { return FolderID.of(UUID.randomUUID()); } + @Override + public String toString() { + return "FolderID [value=" + getValue() + "]"; + } + } diff --git a/domain/src/main/java/com/callv2/drive/domain/member/Member.java b/domain/src/main/java/com/callv2/drive/domain/member/Member.java index ff437a44..fd8529cd 100644 --- a/domain/src/main/java/com/callv2/drive/domain/member/Member.java +++ b/domain/src/main/java/com/callv2/drive/domain/member/Member.java @@ -172,4 +172,11 @@ public Long getSynchronizedVersion() { return synchronizedVersion; } + @Override + public String toString() { + return "Member [id=" + id + ", username=" + username + ", nickname=" + nickname + ", quota=" + quota + + ", quotaRequest=" + quotaRequest + ", hasSystemAccess=" + hasSystemAccess + ", createdAt=" + createdAt + + ", updatedAt=" + updatedAt + ", synchronizedVersion=" + synchronizedVersion + "]"; + } + } diff --git a/domain/src/main/java/com/callv2/drive/domain/member/MemberID.java b/domain/src/main/java/com/callv2/drive/domain/member/MemberID.java index 9310602a..2be9ec43 100644 --- a/domain/src/main/java/com/callv2/drive/domain/member/MemberID.java +++ b/domain/src/main/java/com/callv2/drive/domain/member/MemberID.java @@ -12,4 +12,9 @@ public static MemberID of(final String id) { return new MemberID(id); } + @Override + public String toString() { + return "MemberID [value=" + getValue() + "]"; + } + } diff --git a/infrastructure/build.gradle b/infrastructure/build.gradle index 5fadb191..c5ab35fc 100644 --- a/infrastructure/build.gradle +++ b/infrastructure/build.gradle @@ -20,6 +20,7 @@ dependencies { implementation(project(":domain")) implementation(project(":application")) + implementation(project(":aop")) implementation 'org.springframework.boot:spring-boot-starter-web' diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/ApplicationLayerAspect.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/ApplicationLayerAspect.java new file mode 100644 index 00000000..4952cc9a --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/ApplicationLayerAspect.java @@ -0,0 +1,35 @@ +package com.callv2.drive.infrastructure.aop.aspect; + +import org.apache.logging.log4j.Level; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import com.callv2.aop.executor.chain.handler.ExecutorChainHandler; +import com.callv2.aop.executor.chain.handler.SimpleExecutorChainHandlerBuilder; +import com.callv2.drive.infrastructure.aop.executor.LogErrorPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodArgsPreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodResultPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodSignaturePreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogTelemetryPostExecutor; + +@Aspect +@Component +public class ApplicationLayerAspect { + + private final ExecutorChainHandler chainHandler = SimpleExecutorChainHandlerBuilder + .create() + .preExecutor(LogMethodSignaturePreExecutor.create(Level.INFO)) + .preExecutor(LogMethodArgsPreExecutor.create(Level.DEBUG)) + .postExecutor(LogMethodResultPostExecutor.create(Level.DEBUG)) + .postExecutor(LogTelemetryPostExecutor.create(Level.INFO)) + .errorExecutor(LogErrorPostExecutor.create(Level.ERROR)) + .build(); + + @Around("execution(* com.callv2.drive.application..*.*(..))") + public Object aspect(final ProceedingJoinPoint joinPoint) throws Throwable { + return chainHandler.handle(joinPoint); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/DomainLayerAspect.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/DomainLayerAspect.java new file mode 100644 index 00000000..9a53f1b5 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/DomainLayerAspect.java @@ -0,0 +1,35 @@ +package com.callv2.drive.infrastructure.aop.aspect; + +import org.apache.logging.log4j.Level; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import com.callv2.aop.executor.chain.handler.ExecutorChainHandler; +import com.callv2.aop.executor.chain.handler.SimpleExecutorChainHandlerBuilder; +import com.callv2.drive.infrastructure.aop.executor.LogErrorPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodArgsPreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodResultPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodSignaturePreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogTelemetryPostExecutor; + +@Aspect +@Component +public class DomainLayerAspect { + + private final ExecutorChainHandler chainHandler = SimpleExecutorChainHandlerBuilder + .create() + .preExecutor(LogMethodSignaturePreExecutor.create(Level.INFO)) + .preExecutor(LogMethodArgsPreExecutor.create(Level.DEBUG)) + .postExecutor(LogMethodResultPostExecutor.create(Level.DEBUG)) + .postExecutor(LogTelemetryPostExecutor.create(Level.INFO)) + .errorExecutor(LogErrorPostExecutor.create(Level.ERROR)) + .build(); + + @Around("execution(* com.callv2.drive.domain..*.*(..))") + public Object aspect(final ProceedingJoinPoint joinPoint) throws Throwable { + return chainHandler.handle(joinPoint); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/InfrastructureLayerAspect.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/InfrastructureLayerAspect.java new file mode 100644 index 00000000..8cfce871 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspect/InfrastructureLayerAspect.java @@ -0,0 +1,40 @@ +package com.callv2.drive.infrastructure.aop.aspect; + +import org.apache.logging.log4j.Level; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import com.callv2.aop.executor.chain.handler.ExecutorChainHandler; +import com.callv2.aop.executor.chain.handler.SimpleExecutorChainHandlerBuilder; +import com.callv2.drive.infrastructure.aop.executor.LogErrorPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodArgsPreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodResultPostExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogMethodSignaturePreExecutor; +import com.callv2.drive.infrastructure.aop.executor.LogTelemetryPostExecutor; + +@Aspect +@Component +public class InfrastructureLayerAspect { + + private final ExecutorChainHandler chainHandler = SimpleExecutorChainHandlerBuilder + .create() + .preExecutor(LogMethodSignaturePreExecutor.create(Level.INFO)) + .preExecutor(LogMethodArgsPreExecutor.create(Level.DEBUG)) + .postExecutor(LogMethodResultPostExecutor.create(Level.DEBUG)) + .postExecutor(LogTelemetryPostExecutor.create(Level.INFO)) + .errorExecutor(LogErrorPostExecutor.create(Level.ERROR)) + .build(); + + @Around("execution(* com.callv2.drive.infrastructure.api.controller..*.*(..))") + public Object controllerAspect(final ProceedingJoinPoint joinPoint) throws Throwable { + return chainHandler.handle(joinPoint); + } + + @Around("execution(* com.callv2.drive.infrastructure.messaging..*.*(..))") + public Object messagingAspect(final ProceedingJoinPoint joinPoint) throws Throwable { + return chainHandler.handle(joinPoint); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/AspectExecutorChain.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/AspectExecutorChain.java deleted file mode 100644 index b7aa2c67..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/AspectExecutorChain.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.chain; - -import java.util.ArrayDeque; -import java.util.Queue; - -import org.aopalliance.intercept.Joinpoint; - -import com.callv2.drive.infrastructure.aop.aspects.executor.AspectExecutor; - -public abstract class AspectExecutorChain> { - - private AspectExecutorChain next; - private final E executor; - - protected AspectExecutorChain(final E executor) { - this.executor = executor; - } - - public final O execute(final J joinpoint) throws Throwable { - - executor.execute(joinpoint); - - if (next != null) - return next.execute(joinpoint); - - return callsProceed(joinpoint); - } - - protected abstract O callsProceed(J joinpoint) throws Throwable; - - @SuppressWarnings("unchecked") - protected AspectExecutorChain setNext(final AspectExecutorChain next) { - return this.next = (AspectExecutorChain) next; - } - - public static final class Builder> { - - private final Class clazz; - private final Queue chains; - - private Builder(final Class clazz) { - this.clazz = clazz; - this.chains = new ArrayDeque<>(); - } - - public static > Builder create(final Class clazz) { - return new Builder(clazz); - } - - public Builder add(final C chain) { - - if (chain.getClass() != clazz) - throw new IllegalArgumentException("Chain must be exactly of type " + clazz.getName()); - - this.chains.add(chain); - return this; - } - - @SuppressWarnings("unchecked") - public C build() { - if (chains.isEmpty()) - return null; - - final var firstChain = chains.poll(); - var chain = firstChain; - - do { - chain = (C) chain.setNext(chains.poll()); - } while (!chains.isEmpty()); - - return firstChain; - } - - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/MethodInvocationAspectExecutorChain.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/MethodInvocationAspectExecutorChain.java deleted file mode 100644 index 2f0e954d..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/MethodInvocationAspectExecutorChain.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.chain; - -import com.callv2.drive.infrastructure.aop.aspects.context.MethodInvocationContext; -import com.callv2.drive.infrastructure.aop.aspects.context.PostInvocationContext; -import com.callv2.drive.infrastructure.aop.aspects.executor.AspectExecutor; - -public final class MethodInvocationAspectExecutorChain extends - AspectExecutorChain> { - - private MethodInvocationAspectExecutorChain(final AspectExecutor executor) { - super(executor); - } - - public static MethodInvocationAspectExecutorChain with(final AspectExecutor executor) { - return new MethodInvocationAspectExecutorChain(executor); - } - - @Override - protected PostInvocationContext callsProceed(final MethodInvocationContext joinpoint) throws Throwable { - return joinpoint.proceedWithContext(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/PostInvocationAspectExecutorChain.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/PostInvocationAspectExecutorChain.java deleted file mode 100644 index 8f4a953b..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/PostInvocationAspectExecutorChain.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.chain; - -import com.callv2.drive.infrastructure.aop.aspects.context.PostInvocationContext; -import com.callv2.drive.infrastructure.aop.aspects.executor.AspectExecutor; - -public final class PostInvocationAspectExecutorChain extends - AspectExecutorChain> { - - private PostInvocationAspectExecutorChain(final AspectExecutor executor) { - super(executor); - } - - public static PostInvocationAspectExecutorChain with(final AspectExecutor executor) { - return new PostInvocationAspectExecutorChain(executor); - } - - @Override - protected Object callsProceed(final PostInvocationContext joinpoint) throws Throwable { - if (joinpoint.wasSuccessful()) - return joinpoint.getResult(); - else - throw joinpoint.getThrowable(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/Proceeder.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/Proceeder.java deleted file mode 100644 index 1dad486c..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/chain/Proceeder.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.chain; - -import org.aopalliance.intercept.Joinpoint; - -@FunctionalInterface -public interface Proceeder { - - O proceed(J joinpoint) throws Throwable; - -} \ No newline at end of file diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractMethodInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractMethodInvocationContext.java deleted file mode 100644 index 325ab18f..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractMethodInvocationContext.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.time.Instant; - -import jakarta.annotation.Nonnull; - -public abstract class AbstractMethodInvocationContext implements MethodInvocationContext { - - private final Instant contextedAt; - - protected AbstractMethodInvocationContext() { - this.contextedAt = Instant.now(); - } - - @Override - @Nonnull - public Instant getContextedAt() { - return contextedAt; - } - - @Override - @Nonnull - public PostInvocationContext proceedWithContext() { - return SimplePostInvocationContext.captureFromExecution(this); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractPostInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractPostInvocationContext.java deleted file mode 100644 index bdeae37f..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/AbstractPostInvocationContext.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.time.Instant; -import java.util.concurrent.atomic.AtomicBoolean; - -public abstract class AbstractPostInvocationContext implements PostInvocationContext { - - private final Object result; - private final Throwable throwable; - private final Instant proceededAt; - private final AtomicBoolean successful; - - protected AbstractPostInvocationContext( - final Object result, - final Throwable throwable, - final Instant proceededAt, - final boolean successful) { - this.result = result; - this.throwable = throwable; - this.proceededAt = proceededAt; - this.successful = new AtomicBoolean(successful); - } - - @Override - public Instant getProceededAt() { - return proceededAt; - } - - @Override - public Object getResult() { - return result; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - @Override - public boolean wasSuccessful() { - return successful.get(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/MethodInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/MethodInvocationContext.java deleted file mode 100644 index 0a5b46a6..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/MethodInvocationContext.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.time.Instant; - -import org.aopalliance.intercept.MethodInvocation; - -import jakarta.annotation.Nonnull; - -public interface MethodInvocationContext extends MethodInvocation { - - @Nonnull - Instant getContextedAt(); - - boolean proceeded(); - - @Nonnull - PostInvocationContext proceedWithContext(); - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/PostInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/PostInvocationContext.java deleted file mode 100644 index 125b22de..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/PostInvocationContext.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.time.Instant; - -import jakarta.annotation.Nullable; - -public interface PostInvocationContext extends MethodInvocationContext { - - @Nullable - Instant getProceededAt(); - - @Nullable - Object getResult(); - - @Nullable - Throwable getThrowable(); - - boolean wasSuccessful(); - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimpleMethodInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimpleMethodInvocationContext.java deleted file mode 100644 index b5e5d4ea..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimpleMethodInvocationContext.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.aopalliance.intercept.MethodInvocation; - -public final class SimpleMethodInvocationContext extends AbstractMethodInvocationContext { - - private final AtomicBoolean proceeded; - private final MethodInvocation methodInvocation; - - private SimpleMethodInvocationContext(final MethodInvocation methodInvocation) { - super(); - this.proceeded = new AtomicBoolean(false); - this.methodInvocation = methodInvocation; - } - - public static SimpleMethodInvocationContext of(final MethodInvocation methodInvocation) { - return new SimpleMethodInvocationContext(methodInvocation); - } - - @Override - public boolean proceeded() { - return proceeded.get(); - } - - @Override - @Nonnull - public Method getMethod() { - return methodInvocation.getMethod(); - } - - @Override - @Nonnull - public Object[] getArguments() { - return methodInvocation.getArguments(); - } - - @Override - @Nullable - public Object proceed() throws Throwable { - if (proceeded.getAndSet(true)) - throw new IllegalStateException("Method already proceeded"); - return methodInvocation.proceed(); - } - - @Override - @Nullable - public Object getThis() { - return methodInvocation.getThis(); - } - - @Override - @Nonnull - public AccessibleObject getStaticPart() { - return methodInvocation.getStaticPart(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimplePostInvocationContext.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimplePostInvocationContext.java deleted file mode 100644 index 30b55dfc..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/context/SimplePostInvocationContext.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.context; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Method; -import java.time.Instant; -import java.util.Objects; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public final class SimplePostInvocationContext extends AbstractPostInvocationContext { - - private final MethodInvocationContext methodInvocationContext; - - private SimplePostInvocationContext( - final Object result, - final Throwable throwable, - final Instant proceededAt, - final boolean successful, - final MethodInvocationContext methodInvocationContext) { - super(result, throwable, proceededAt, successful); - this.methodInvocationContext = Objects.requireNonNull(methodInvocationContext, - "'methodInvocationContext' must not be null"); - } - - public static final PostInvocationContext captureFromExecution( - final MethodInvocationContext methodInvocationContext) { - - Objects.requireNonNull(methodInvocationContext, "'methodInvocationContext' must not be null"); - - Object result; - Throwable throwable; - boolean successful; - final Instant proceededAt; - - try { - result = methodInvocationContext.proceed(); - throwable = null; - successful = true; - } catch (Throwable e) { - result = null; - throwable = e; - successful = false; - } finally { - proceededAt = Instant.now(); - } - - return new SimplePostInvocationContext( - result, - throwable, - proceededAt, - successful, - methodInvocationContext); - - } - - @Override - @Nonnull - public Instant getContextedAt() { - return methodInvocationContext.getContextedAt(); - } - - @Override - public boolean proceeded() { - return methodInvocationContext.proceeded(); - } - - @Override - @Nonnull - public PostInvocationContext proceedWithContext() { - return this; - } - - @Override - @Nonnull - public Method getMethod() { - return methodInvocationContext.getMethod(); - } - - @Override - @Nonnull - public Object[] getArguments() { - return methodInvocationContext.getArguments(); - } - - @Override - @Nullable - public Object proceed() throws Throwable { - return methodInvocationContext.proceed(); - } - - @Override - @Nullable - public Object getThis() { - return methodInvocationContext.getThis(); - } - - @Override - @Nonnull - public AccessibleObject getStaticPart() { - return methodInvocationContext.getStaticPart(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ArgsLogExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ArgsLogExecutor.java deleted file mode 100644 index 8519ed3e..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ArgsLogExecutor.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import java.util.Arrays; - -import org.apache.logging.log4j.Level; - -import com.callv2.drive.infrastructure.aop.aspects.context.MethodInvocationContext; - -public class ArgsLogExecutor extends Log4jExecutor { - - public ArgsLogExecutor(final Level level, final Class clazz) { - super(level, clazz); - } - - @Override - public void execute(final MethodInvocationContext context) { - final var args = context.getArguments(); - log("<> [{}] <> count:[{}] args: [{}]", - context.getMethod(), - args.length, - Arrays.toString(args)); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/AspectExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/AspectExecutor.java deleted file mode 100644 index 9b7cf5da..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/AspectExecutor.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import org.aopalliance.intercept.Joinpoint; - -@FunctionalInterface -public interface AspectExecutor { - - void execute(J joinPoint); - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/IdentifiableAspectExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/IdentifiableAspectExecutor.java deleted file mode 100644 index 8a96e709..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/IdentifiableAspectExecutor.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import org.aopalliance.intercept.Joinpoint; - -public interface IdentifiableAspectExecutor extends AspectExecutor { - - default String getId() { - return getClass().getSimpleName(); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/MethodSignatureLogExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/MethodSignatureLogExecutor.java deleted file mode 100644 index 4c8ec16b..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/MethodSignatureLogExecutor.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import org.apache.logging.log4j.Level; - -import com.callv2.drive.infrastructure.aop.aspects.context.MethodInvocationContext; - -public class MethodSignatureLogExecutor extends Log4jExecutor { - - public MethodSignatureLogExecutor(final Level level, final Class clazz) { - super(level, clazz); - } - - @Override - public void execute(final MethodInvocationContext context) { - log("<>: [{}]", context.getMethod().toString()); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/PostTelemetryLogExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/PostTelemetryLogExecutor.java deleted file mode 100644 index 48675064..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/PostTelemetryLogExecutor.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import java.time.Duration; - -import org.apache.logging.log4j.Level; - -import com.callv2.drive.infrastructure.aop.aspects.context.PostInvocationContext; - -public class PostTelemetryLogExecutor extends Log4jExecutor { - - public PostTelemetryLogExecutor(final Level logLevel, final Class clazz) { - super(logLevel, clazz); - } - - @Override - public void execute(final PostInvocationContext context) { - log("<> [{}] ms <> [{}]", - Duration.between(context.getContextedAt(), context.getProceededAt()).toMillis(), - context.getMethod().toString()); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ThrowableLogExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ThrowableLogExecutor.java deleted file mode 100644 index 72cebda8..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/ThrowableLogExecutor.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; - -import com.callv2.drive.infrastructure.aop.aspects.context.PostInvocationContext; -import org.apache.logging.log4j.Level; - -public class ThrowableLogExecutor extends Log4jExecutor { - - private ThrowableLogExecutor(final Level level, final Class clazz) { - super(level, clazz); - } - - public static ThrowableLogExecutor defaultCreate(final Class clazz) { - return new ThrowableLogExecutor(Level.ERROR, clazz); - } - - public static ThrowableLogExecutor create(final Level level, final Class clazz) { - return new ThrowableLogExecutor(level, clazz); - } - - @Override - public void execute(final PostInvocationContext context) { - if (context.getThrowable() != null) - log("<> [{}] <> [{}] <> [{}]", - context.getThrowable().getClass().getName(), - context.getThrowable().getMessage(), - context.getMethod().toString(), - context.getThrowable()); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/handler/SimpleMethodInterceptorWithContextHandler.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/handler/SimpleMethodInterceptorWithContextHandler.java deleted file mode 100644 index 9c000fc3..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/handler/SimpleMethodInterceptorWithContextHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.callv2.drive.infrastructure.aop.aspects.handler; - -import javax.annotation.Nonnull; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -import com.callv2.drive.infrastructure.aop.aspects.chain.MethodInvocationAspectExecutorChain; -import com.callv2.drive.infrastructure.aop.aspects.chain.PostInvocationAspectExecutorChain; -import com.callv2.drive.infrastructure.aop.aspects.context.MethodInvocationContext; -import com.callv2.drive.infrastructure.aop.aspects.context.PostInvocationContext; -import com.callv2.drive.infrastructure.aop.aspects.context.SimpleMethodInvocationContext; - -import jakarta.annotation.Nullable; - -public final class SimpleMethodInterceptorWithContextHandler implements MethodInterceptor { - - private final MethodInvocationAspectExecutorChain beforeChain; - private final PostInvocationAspectExecutorChain afterChain; - private final PostInvocationAspectExecutorChain errorChain; - - public SimpleMethodInterceptorWithContextHandler( - final MethodInvocationAspectExecutorChain beforeChain, - final PostInvocationAspectExecutorChain afterChain, - final PostInvocationAspectExecutorChain errorChain) { - this.beforeChain = beforeChain; - this.afterChain = afterChain; - this.errorChain = errorChain; - } - - @Override - @Nullable - public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable { - - final MethodInvocationContext context = SimpleMethodInvocationContext.of(invocation); - - final PostInvocationContext postInvocationResult = beforeChain.execute(context); - - if (postInvocationResult.wasSuccessful()) - return afterChain.execute(postInvocationResult); - else - errorChain.execute(postInvocationResult); - - final Throwable throwable = postInvocationResult.getThrowable(); - if (throwable != null) - throw throwable; - - throw new IllegalStateException("Invocation failed but no throwable was provided."); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/Log4jExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/Log4jLogger.java similarity index 79% rename from infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/Log4jExecutor.java rename to infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/Log4jLogger.java index 16195a1f..b4303d38 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/aspects/executor/Log4jExecutor.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/Log4jLogger.java @@ -1,18 +1,16 @@ -package com.callv2.drive.infrastructure.aop.aspects.executor; +package com.callv2.drive.infrastructure.aop.executor; -import org.aopalliance.intercept.Joinpoint; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.Message; -public abstract class Log4jExecutor implements IdentifiableAspectExecutor { +public abstract class Log4jLogger { private final Logger logger; private final Level logLevel; - public Log4jExecutor(final Level logLevel, Class clazz) { - super(); + protected Log4jLogger(final Level logLevel, final Class clazz) { this.logLevel = logLevel; this.logger = LogManager.getLogger(clazz); } diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogErrorPostExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogErrorPostExecutor.java new file mode 100644 index 00000000..943d3258 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogErrorPostExecutor.java @@ -0,0 +1,30 @@ +package com.callv2.drive.infrastructure.aop.executor; + +import org.apache.logging.log4j.Level; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.executor.PostExecutor; + +public class LogErrorPostExecutor extends Log4jLogger implements PostExecutor { + + private LogErrorPostExecutor(final Level logLevel, final Class clazz) { + super(logLevel, clazz); + } + + public static LogErrorPostExecutor create(final Level logLevel) { + return new LogErrorPostExecutor(logLevel, LogErrorPostExecutor.class); + } + + @Override + public void execute(final PostInvocationContext joinPoint) { + if (joinPoint.getThrowable() != null) + log("<> [{}] <> [{}] <> [{}]", + joinPoint.getSignature().toShortString(), + joinPoint.getThrowable().getClass().getName(), + joinPoint.getThrowable().getMessage(), + joinPoint.getThrowable()); + else + log("<> [{}] <>", joinPoint.getSignature().toShortString()); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodArgsPreExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodArgsPreExecutor.java new file mode 100644 index 00000000..705dbf1b --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodArgsPreExecutor.java @@ -0,0 +1,28 @@ +package com.callv2.drive.infrastructure.aop.executor; + +import java.util.Arrays; + +import org.apache.logging.log4j.Level; + +import com.callv2.aop.context.PreInvocationContext; +import com.callv2.aop.executor.PreExecutor; + +public class LogMethodArgsPreExecutor extends Log4jLogger implements PreExecutor { + + private LogMethodArgsPreExecutor(final Level logLevel, final Class clazz) { + super(logLevel, clazz); + } + + public static LogMethodArgsPreExecutor create(final Level logLevel) { + return new LogMethodArgsPreExecutor(logLevel, LogMethodArgsPreExecutor.class); + } + + @Override + public void execute(final PreInvocationContext joinPoint) { + + log("<> [{}] <> [{}]", + joinPoint.getSignature().toShortString(), + Arrays.toString(joinPoint.getArgs())); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodResultPostExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodResultPostExecutor.java new file mode 100644 index 00000000..99ba0811 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodResultPostExecutor.java @@ -0,0 +1,29 @@ +package com.callv2.drive.infrastructure.aop.executor; + +import java.util.Arrays; + +import org.apache.logging.log4j.Level; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.executor.PostExecutor; + +public class LogMethodResultPostExecutor extends Log4jLogger implements PostExecutor { + + private LogMethodResultPostExecutor(final Level logLevel, final Class clazz) { + super(logLevel, clazz); + } + + public static LogMethodResultPostExecutor create(final Level logLevel) { + return new LogMethodResultPostExecutor(logLevel, LogMethodResultPostExecutor.class); + } + + @Override + public void execute(final PostInvocationContext joinPoint) { + + log("<> [{}] <> [{}] <> [{}]", + joinPoint.getSignature().toShortString(), + Arrays.toString(joinPoint.getArgs()), + joinPoint.getResult()); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodSignaturePreExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodSignaturePreExecutor.java new file mode 100644 index 00000000..90fef616 --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogMethodSignaturePreExecutor.java @@ -0,0 +1,23 @@ +package com.callv2.drive.infrastructure.aop.executor; + +import org.apache.logging.log4j.Level; + +import com.callv2.aop.context.PreInvocationContext; +import com.callv2.aop.executor.PreExecutor; + +public class LogMethodSignaturePreExecutor extends Log4jLogger implements PreExecutor { + + private LogMethodSignaturePreExecutor(final Level logLevel, final Class clazz) { + super(logLevel, clazz); + } + + public static LogMethodSignaturePreExecutor create(final Level logLevel) { + return new LogMethodSignaturePreExecutor(logLevel, LogMethodSignaturePreExecutor.class); + } + + @Override + public void execute(final PreInvocationContext joinPoint) { + log("<>: [{}]", joinPoint.getSignature().toShortString()); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogTelemetryPostExecutor.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogTelemetryPostExecutor.java new file mode 100644 index 00000000..1bc4769b --- /dev/null +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/aop/executor/LogTelemetryPostExecutor.java @@ -0,0 +1,27 @@ +package com.callv2.drive.infrastructure.aop.executor; + +import java.time.Duration; + +import org.apache.logging.log4j.Level; + +import com.callv2.aop.context.PostInvocationContext; +import com.callv2.aop.executor.PostExecutor; + +public class LogTelemetryPostExecutor extends Log4jLogger implements PostExecutor { + + private LogTelemetryPostExecutor(final Level logLevel, final Class clazz) { + super(logLevel, clazz); + } + + public static LogTelemetryPostExecutor create(final Level logLevel) { + return new LogTelemetryPostExecutor(logLevel, LogTelemetryPostExecutor.class); + } + + @Override + public void execute(final PostInvocationContext joinPoint) { + log("<>: [{}] <> [{}] ms", + joinPoint.getSignature().toShortString(), + Duration.between(joinPoint.getContextedAt(), joinPoint.getProceededAt()).toMillis()); + } + +} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/aop/aspect/AspectConfig.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/aop/aspect/AspectConfig.java deleted file mode 100644 index e76fca6c..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/aop/aspect/AspectConfig.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.callv2.drive.infrastructure.configuration.aop.aspect; - -import org.aopalliance.intercept.MethodInterceptor; -import org.apache.logging.log4j.Level; -import org.springframework.aop.Advisor; -import org.springframework.aop.aspectj.AspectJExpressionPointcut; -import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import com.callv2.drive.infrastructure.aop.aspects.chain.AspectExecutorChain; -import com.callv2.drive.infrastructure.aop.aspects.chain.MethodInvocationAspectExecutorChain; -import com.callv2.drive.infrastructure.aop.aspects.chain.PostInvocationAspectExecutorChain; -import com.callv2.drive.infrastructure.aop.aspects.executor.ArgsLogExecutor; -import com.callv2.drive.infrastructure.aop.aspects.executor.MethodSignatureLogExecutor; -import com.callv2.drive.infrastructure.aop.aspects.executor.PostTelemetryLogExecutor; -import com.callv2.drive.infrastructure.aop.aspects.executor.ThrowableLogExecutor; -import com.callv2.drive.infrastructure.aop.aspects.handler.SimpleMethodInterceptorWithContextHandler; - -@Configuration -public class AspectConfig { - - @Bean - Advisor applicationAdvisor() { - - final var beforeChain = AspectExecutorChain.Builder - .create(MethodInvocationAspectExecutorChain.class) - .add(MethodInvocationAspectExecutorChain - .with(new MethodSignatureLogExecutor(Level.DEBUG, MethodSignatureLogExecutor.class))) - .add(MethodInvocationAspectExecutorChain - .with(new ArgsLogExecutor(Level.DEBUG, ArgsLogExecutor.class))) - .build(); - - final var afterChain = AspectExecutorChain.Builder - .create(PostInvocationAspectExecutorChain.class) - .add(PostInvocationAspectExecutorChain - .with(new PostTelemetryLogExecutor(Level.DEBUG, PostTelemetryLogExecutor.class))) - .build(); - - final var errorChain = AspectExecutorChain.Builder - .create(PostInvocationAspectExecutorChain.class) - .add(PostInvocationAspectExecutorChain - .with(new PostTelemetryLogExecutor(Level.ERROR, PostTelemetryLogExecutor.class))) - .add(PostInvocationAspectExecutorChain - .with(ThrowableLogExecutor.defaultCreate(ThrowableLogExecutor.class))) - .build(); - - return applicationAdvisor( - "execution(* com.callv2.drive.application..*.*(..))", - new SimpleMethodInterceptorWithContextHandler(beforeChain, afterChain, errorChain)); - } - - private static Advisor applicationAdvisor( - final String expression, - final MethodInterceptor interceptor) { - - final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(expression); - - return new DefaultPointcutAdvisor( - pointcut, - interceptor); - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/properties/aspect/PointcutAdvisorProperties.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/properties/aspect/PointcutAdvisorProperties.java deleted file mode 100644 index c930113e..00000000 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/configuration/properties/aspect/PointcutAdvisorProperties.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.callv2.drive.infrastructure.configuration.properties.aspect; - -import java.util.List; - -public class PointcutAdvisorProperties { - - private String expression; - - private List before; - private List after; - private List error; - - public PointcutAdvisorProperties() { - } - - public String getExpression() { - return expression; - } - - public void setExpression(String expression) { - this.expression = expression; - } - - public List getBefore() { - return before; - } - - public void setBefore(List before) { - this.before = before; - } - - public List getAfter() { - return after; - } - - public void setAfter(List after) { - this.after = after; - } - - public List getError() { - return error; - } - - public void setError(List error) { - this.error = error; - } - -} diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/converter/JacksonCaster.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/converter/JacksonCaster.java index d420a4f5..f7d0b9f7 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/converter/JacksonCaster.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/converter/JacksonCaster.java @@ -6,13 +6,10 @@ import com.callv2.drive.infrastructure.configuration.mapper.Mapper; @Component -public final class JacksonCaster implements Caster { +public class JacksonCaster implements Caster { private static final ObjectMapper mapper = Mapper.mapper(); - private JacksonCaster() { - } - @Override public T cast(Object value, Class targetType) { return mapper.convertValue(value, targetType); diff --git a/infrastructure/src/main/java/com/callv2/drive/infrastructure/file/persistence/FileJpaEntity.java b/infrastructure/src/main/java/com/callv2/drive/infrastructure/file/persistence/FileJpaEntity.java index 2785ce24..bdb06259 100644 --- a/infrastructure/src/main/java/com/callv2/drive/infrastructure/file/persistence/FileJpaEntity.java +++ b/infrastructure/src/main/java/com/callv2/drive/infrastructure/file/persistence/FileJpaEntity.java @@ -166,4 +166,11 @@ public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } + @Override + public String toString() { + return "FileJpaEntity [id=" + id + ", ownerId=" + ownerId + ", folderId=" + folderId + ", name=" + name + + ", contentType=" + contentType + ", contentLocation=" + contentLocation + ", contentSize=" + + contentSize + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + "]"; + } + } diff --git a/settings.gradle b/settings.gradle index 6ea23965..60ec077c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'drive-api' -include('domain', 'application', 'infrastructure') \ No newline at end of file +include('domain', 'application', 'infrastructure', 'aop') \ No newline at end of file