[
  {
    "path": ".gitignore",
    "content": "### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\ntarget/"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n    id 'org.springframework.boot' version '2.2.2.RELEASE'\n    id 'io.spring.dependency-management' version '1.0.8.RELEASE'\n    id 'java'\n}\n\ngroup = 'tech.allegro'\nversion = '0.0.1-SNAPSHOT'\nsourceCompatibility = '11'\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation 'org.springframework.boot:spring-boot-starter-web'\n    testImplementation('org.springframework.boot:spring-boot-starter-test') {\n        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'\n    }\n}\n\ntest {\n    useJUnitPlatform()\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.0.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'hexagonal-architecture-by-example'\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/HexagonalArchitectureExampleApplication.java",
    "content": "package tech.allegro.hexagon;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class HexagonalArchitectureExampleApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(HexagonalArchitectureExampleApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/api/ArticleEndpoint.java",
    "content": "package tech.allegro.hexagon.articles.adapters.api;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"articles\")\nclass ArticleEndpoint {\n\n    private final ArticleFacade articles;\n\n    ArticleEndpoint(ArticleFacade articles) {\n        this.articles = articles;\n    }\n\n    @GetMapping(\"{articleId}\")\n    ArticleResponse get(@PathVariable(\"articleId\") final String articleId) {\n        return articles.get(articleId);\n    }\n\n    @PostMapping\n    ArticleIdResponse create(@RequestBody final ArticleRequest articleRequest) {\n        return articles.create(articleRequest);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/api/ArticleFacade.java",
    "content": "package tech.allegro.hexagon.articles.adapters.api;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleService;\n\n@Component\nclass ArticleFacade {\n\n    private final ArticleService articleService;\n\n    ArticleFacade(final ArticleService articleService) {\n        this.articleService = articleService;\n    }\n\n    ArticleResponse get(final String articleId) {\n        final Article article = articleService.get(ArticleId.of(articleId));\n        return ArticleResponse.of(article);\n    }\n\n    ArticleIdResponse create(final ArticleRequest articleRequest) {\n        final ArticleId articleId = articleService.create(articleRequest.authorId(), articleRequest.title(), articleRequest.content());\n        return ArticleIdResponse.of(articleId);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/api/ArticleIdResponse.java",
    "content": "package tech.allegro.hexagon.articles.adapters.api;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\n\nclass ArticleIdResponse {\n\n    private final String id;\n\n    private ArticleIdResponse(final String id) {\n        this.id = id;\n    }\n\n    static ArticleIdResponse of(final ArticleId articleId) {\n        return new ArticleIdResponse(articleId.value());\n    }\n\n    @JsonProperty(\"id\")\n    String id() {\n        return id;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/api/ArticleRequest.java",
    "content": "package tech.allegro.hexagon.articles.adapters.api;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\nimport tech.allegro.hexagon.articles.domain.model.Content;\nimport tech.allegro.hexagon.articles.domain.model.Title;\n\nclass ArticleRequest {\n    private final String title;\n    private final String content;\n    private final String authorId;\n\n    ArticleRequest(@JsonProperty(\"title\") final String title, @JsonProperty(\"content\") final String content, @JsonProperty(\"authorId\") final String authorId) {\n        this.title = title;\n        this.content = content;\n        this.authorId = authorId;\n    }\n\n\n    Title title() {\n        return Title.of(title);\n    }\n\n    Content content() {\n        return Content.of(content);\n    }\n\n    AuthorId authorId() {\n        return AuthorId.of(authorId);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/api/ArticleResponse.java",
    "content": "package tech.allegro.hexagon.articles.adapters.api;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nclass ArticleResponse {\n    private final String id;\n    private final String title;\n    private final String content;\n    private final String authorName;\n\n    private ArticleResponse(final String id, final String title, final String content, final String authorName) {\n        this.id = id;\n        this.title = title;\n        this.content = content;\n        this.authorName = authorName;\n    }\n\n    static ArticleResponse of(final Article article) {\n        return new ArticleResponse(article.id().value(),\n                article.title().value(),\n                article.content().value(),\n                article.author().name().value());\n    }\n\n    @JsonProperty(\"id\")\n    String id() {\n        return id;\n    }\n\n    @JsonProperty(\"title\")\n    String title() {\n        return title;\n    }\n\n    @JsonProperty(\"content\")\n    String content() {\n        return content;\n    }\n\n    @JsonProperty(\"authorName\")\n    String authorName() {\n        return authorName;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/articledb/ArticleDatabaseModel.java",
    "content": "package tech.allegro.hexagon.articles.adapters.articledb;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\nimport tech.allegro.hexagon.articles.domain.model.Content;\nimport tech.allegro.hexagon.articles.domain.model.PersonName;\nimport tech.allegro.hexagon.articles.domain.model.Title;\n\nimport java.time.ZonedDateTime;\nimport java.util.UUID;\n\nclass ArticleDatabaseModel {\n\n    private final UUID id;\n    private final String title;\n    private final String content;\n    private final long version;\n    private final ZonedDateTime createdAt;\n    private final String authorId;\n    private final String authorName;\n\n    private ArticleDatabaseModel(final UUID id,\n                                 final String title,\n                                 final String content,\n                                 final String authorId,\n                                 final long version,\n                                 final ZonedDateTime createdAt,\n                                 final String authorName) {\n        this.id = id;\n        this.title = title;\n        this.content = content;\n        this.authorId = authorId;\n        this.version = version;\n        this.createdAt = createdAt;\n        this.authorName = authorName;\n    }\n\n    @Override\n    public String toString() {\n        return title;\n    }\n\n    Article toDomain() {\n        return Article.article()\n                .withId(ArticleId.of(id.toString()))\n                .withAuthor(Author\n                        .author()\n                        .withId(AuthorId.of(authorId))\n                        .withName(PersonName.of(authorName))\n                        .build())\n                .withTitle(Title.of(title))\n                .withContent(Content.of(content))\n                .build();\n    }\n\n    static ArticleDatabaseModel of(final Author author, final Title title, final Content content) {\n        return articleDatabaseModel()\n                .withId(UUID.randomUUID())\n                .withVersion(0)\n                .withCreatedAt(ZonedDateTime.now())\n                .withAuthorId(author.id().value())\n                .withAuthorName(author.name().value())\n                .withTitle(title.value())\n                .withContent(content.value())\n                .build();\n    }\n\n    static ArticleDatabaseModelBuilder articleDatabaseModel() {\n        return new ArticleDatabaseModelBuilder();\n    }\n\n    static final class ArticleDatabaseModelBuilder {\n        private UUID id;\n        private String title;\n        private String content;\n        private long version;\n        private ZonedDateTime createdAt;\n        private String authorId;\n        private String authorName;\n\n        private ArticleDatabaseModelBuilder() {\n        }\n\n        ArticleDatabaseModelBuilder withId(UUID id) {\n            this.id = id;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withTitle(String title) {\n            this.title = title;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withContent(String content) {\n            this.content = content;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withVersion(long version) {\n            this.version = version;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withCreatedAt(ZonedDateTime createdAt) {\n            this.createdAt = createdAt;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withAuthorId(String authorId) {\n            this.authorId = authorId;\n            return this;\n        }\n\n        ArticleDatabaseModelBuilder withAuthorName(String authorName) {\n            this.authorName = authorName;\n            return this;\n        }\n\n        ArticleDatabaseModel build() {\n            return new ArticleDatabaseModel(id, title, content, authorId, version, createdAt, authorName);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/articledb/DbArticleRepository.java",
    "content": "package tech.allegro.hexagon.articles.adapters.articledb;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.Content;\nimport tech.allegro.hexagon.articles.domain.model.Title;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleRepository;\n\nimport java.util.UUID;\n\nimport static tech.allegro.hexagon.articles.adapters.articledb.ArticleDatabaseModel.articleDatabaseModel;\nimport static tech.allegro.hexagon.articles.adapters.articledb.ArticleDatabaseModel.of;\n\n@Component\nclass DbArticleRepository implements ArticleRepository {\n\n    @Override\n    public Article save(final Author author, final Title title, final Content content) {\n        /**\n         * Database integration implementation comes here\n         */\n        final ArticleDatabaseModel entity = of(author, title, content);\n        return entity.toDomain();\n    }\n\n    @Override\n    public Article get(final ArticleId id) {\n        /**\n         * Database integration implementation comes here\n         */\n        final ArticleDatabaseModel entity = articleDatabaseModel()\n                .withId(UUID.fromString(id.value()))\n                .withAuthorName(\"William Shakespeare\")\n                .withAuthorId(\"928467\")\n                .withTitle(\"Hexagonal Architecture\")\n                .withContent(\"Lorem ipsum\")\n                .build();\n        return entity.toDomain();\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/authorservice/AuthorExternalModel.java",
    "content": "package tech.allegro.hexagon.articles.adapters.authorservice;\n\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\nimport tech.allegro.hexagon.articles.domain.model.PersonName;\n\nclass AuthorExternalModel {\n    private final long id;\n    private final String firstName;\n    private final String lastName;\n\n    private AuthorExternalModel(final long id, final String firstName, final String lastName) {\n        this.id = id;\n        this.firstName = firstName;\n        this.lastName = lastName;\n    }\n\n    Author toDomain() {\n        return Author.author()\n                .withId(AuthorId.of(String.valueOf(id)))\n                .withName(PersonName.of(fullName()))\n                .build();\n    }\n\n    private String fullName() {\n        return String.format(\"%s %s\", firstName, lastName);\n    }\n\n    @Override\n    public String toString() {\n        return fullName();\n    }\n\n    static AuthorExternalModelBuilder authorExternalModel() {\n        return new AuthorExternalModelBuilder();\n    }\n\n    static final class AuthorExternalModelBuilder {\n        private long id;\n        private String firstName;\n        private String lastName;\n\n        private AuthorExternalModelBuilder() {\n        }\n\n        AuthorExternalModelBuilder withId(long id) {\n            this.id = id;\n            return this;\n        }\n\n        AuthorExternalModelBuilder withFirstName(String firstName) {\n            this.firstName = firstName;\n            return this;\n        }\n\n        AuthorExternalModelBuilder withLastName(String lastName) {\n            this.lastName = lastName;\n            return this;\n        }\n\n        AuthorExternalModel build() {\n            return new AuthorExternalModel(id, firstName, lastName);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/authorservice/ExternalServiceClientAuthorRepository.java",
    "content": "package tech.allegro.hexagon.articles.adapters.authorservice;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorRepository;\n\nimport static tech.allegro.hexagon.articles.adapters.authorservice.AuthorExternalModel.authorExternalModel;\n\n@Component\nclass ExternalServiceClientAuthorRepository implements AuthorRepository {\n\n\n    @Override\n    public Author get(final AuthorId authorId) {\n        /**\n         * external author service integration implementation comes here\n         */\n        final AuthorExternalModel author = authorExternalModel()\n                .withId(928467)\n                .withFirstName(\"William\")\n                .withLastName(\"Shakespeare\")\n                .build();\n        return author.toDomain();\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/messagebroker/ArticleCreatedMessage.java",
    "content": "package tech.allegro.hexagon.articles.adapters.messagebroker;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nimport java.time.ZonedDateTime;\n\nclass ArticleCreatedMessage {\n\n    private final Article article;\n    private final ZonedDateTime sentAt;\n\n    private ArticleCreatedMessage(final Article article, final ZonedDateTime sentAt) {\n        this.article = article;\n        this.sentAt = sentAt;\n    }\n\n    static ArticleCreatedMessage of(Article article) {\n        return new ArticleCreatedMessage(article, ZonedDateTime.now());\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"\\\"Article >>%s<< created\\\"\", article.title().value());\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/messagebroker/ArticleRetrievedMessage.java",
    "content": "package tech.allegro.hexagon.articles.adapters.messagebroker;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nimport java.time.ZonedDateTime;\n\nclass ArticleRetrievedMessage {\n\n    private final Article article;\n\n    private final ZonedDateTime sentAt;\n\n    private ArticleRetrievedMessage(final Article article, final ZonedDateTime sentAt) {\n        this.article = article;\n        this.sentAt = sentAt;\n    }\n\n    static ArticleRetrievedMessage of(Article article) {\n        return new ArticleRetrievedMessage(article, ZonedDateTime.now());\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"\\\"Article >>%s<< retrieved\\\"\", article.title().value());\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/messagebroker/MessageBrokerArticleMessageSender.java",
    "content": "package tech.allegro.hexagon.articles.adapters.messagebroker;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleMessageSender;\n\n@Component\nclass MessageBrokerArticleMessageSender implements ArticleMessageSender {\n\n    @Override\n    public void sendMessageForCreated(final Article article) {\n        /**\n         * message broker integration implementation comes here\n         */\n        ArticleCreatedMessage.of(article);\n    }\n\n    @Override\n    public void sendMessageForRetrieved(final Article article) {\n        /**\n         * message broker integration implementation comes here\n         */\n        ArticleRetrievedMessage.of(article);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/notifications/ArticleMailModel.java",
    "content": "package tech.allegro.hexagon.articles.adapters.notifications;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nclass ArticleMailModel {\n\n    private static final String SUBJECT = \"You have successfully published: >>%s<<\";\n    private static final String CONTENT = \"Check if everything is correct: >>%s<<\";\n\n    private final String recipientId;\n    private final String subject;\n    private final String content;\n\n    private ArticleMailModel(final String recipientId,\n                             final String subject,\n                             final String content) {\n        this.recipientId = recipientId;\n        this.subject = subject;\n        this.content = content;\n    }\n\n    static ArticleMailModel of(final Article article) {\n        return new ArticleMailModel(article.author().name().value(),\n                String.format(SUBJECT, article.title().value()),\n                String.format(CONTENT, article.content().value()));\n    }\n\n    @Override\n    public String toString() {\n        return subject;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/notifications/ArticleSmsModel.java",
    "content": "package tech.allegro.hexagon.articles.adapters.notifications;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nclass ArticleSmsModel {\n\n    public static final String CONTENT = \"Please check your email. We have sent you publication details of the article: >>%s<<\";\n    private final String recipientId;\n    private final String text;\n\n    private ArticleSmsModel(final String recipientId, final String text) {\n        this.recipientId = recipientId;\n        this.text = text;\n    }\n\n    public static ArticleSmsModel of(Article article) {\n        return new ArticleSmsModel(\n                article.author().name().value(),\n                String.format(CONTENT, article.title().value()));\n\n    }\n\n    @Override\n    public String toString() {\n        return text;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/notifications/AuthorMailNotifier.java",
    "content": "package tech.allegro.hexagon.articles.adapters.notifications;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorNotifier;\n\n@Component\nclass AuthorMailNotifier implements AuthorNotifier {\n\n    @Override\n    public void notifyAboutCreationOf(final Article article) {\n        /**\n         * Mail system integration implementation comes here\n         */\n        ArticleMailModel.of(article);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/notifications/AuthorSmsNotifier.java",
    "content": "package tech.allegro.hexagon.articles.adapters.notifications;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorNotifier;\n\n@Component\nclass AuthorSmsNotifier implements AuthorNotifier {\n\n    @Override\n    public void notifyAboutCreationOf(final Article article) {\n        /**\n         * SMS system integration implementation comes here\n         */\n        ArticleSmsModel.of(article);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/socialmedia/ArticleTwitterModel.java",
    "content": "package tech.allegro.hexagon.articles.adapters.socialmedia;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\nclass ArticleTwitterModel {\n\n    public static final String TWEET = \"Check out the new article >>%s<< by %s\";\n    private final String twitterAccountId;\n    private final String tweet;\n\n    private ArticleTwitterModel(final String twitterAccountId, final String tweet) {\n        this.twitterAccountId = twitterAccountId;\n        this.tweet = tweet;\n    }\n\n    static ArticleTwitterModel of(Article article) {\n        final String title = article\n                .title()\n                .value();\n        final String twitterId = article.author().name().value();\n        return new ArticleTwitterModel(twitterId, String.format(TWEET, title, twitterId));\n    }\n\n    @Override\n    public String toString() {\n        return tweet;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/socialmedia/TwitterArticlePublisher.java",
    "content": "package tech.allegro.hexagon.articles.adapters.socialmedia;\n\nimport org.springframework.stereotype.Component;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.ports.SocialMediaPublisher;\n\n@Component\nclass TwitterArticlePublisher implements SocialMediaPublisher {\n\n    private final TwitterClient twitterClient;\n\n    TwitterArticlePublisher(final TwitterClient twitterClient) {\n        this.twitterClient = twitterClient;\n    }\n\n    @Override\n    public void publish(final Article article) {\n        final ArticleTwitterModel articleTweet = ArticleTwitterModel.of(article);\n        twitterClient.tweet(articleTweet);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/adapters/socialmedia/TwitterClient.java",
    "content": "package tech.allegro.hexagon.articles.adapters.socialmedia;\n\nimport org.springframework.stereotype.Component;\n\n@Component\nclass TwitterClient {\n    void tweet(final ArticleTwitterModel articleTweet) {\n        /**\n         * social media integration implementation comes here\n         */\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/config/ArticleConfig.java",
    "content": "package tech.allegro.hexagon.articles.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport tech.allegro.hexagon.articles.domain.ArticlePublisher;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleMessageSender;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleRepository;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleService;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorNotifier;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorRepository;\nimport tech.allegro.hexagon.articles.domain.ports.SocialMediaPublisher;\n\nimport java.util.List;\n\n@Configuration\nclass ArticleConfig {\n\n    @Bean\n    ArticlePublisher articleEventPublisher(final ArticleMessageSender eventPublisher,\n                                           final List<SocialMediaPublisher> socialMediaPublishers,\n                                           final List<AuthorNotifier> articleAuthorNotifiers) {\n        return new ArticlePublisher(eventPublisher,\n                socialMediaPublishers,\n                articleAuthorNotifiers);\n    }\n\n    @Bean\n    ArticleService articleService(final ArticleRepository articleRepository,\n                                  final AuthorRepository authorRepository,\n                                  final ArticlePublisher articleEventPublisher\n    ) {\n        return new ArticleService(\n                articleRepository,\n                authorRepository,\n                articleEventPublisher);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ArticlePublisher.java",
    "content": "package tech.allegro.hexagon.articles.domain;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.ports.ArticleMessageSender;\nimport tech.allegro.hexagon.articles.domain.ports.AuthorNotifier;\nimport tech.allegro.hexagon.articles.domain.ports.SocialMediaPublisher;\n\nimport java.util.List;\n\npublic class ArticlePublisher {\n    private final ArticleMessageSender messageSender;\n    private final List<SocialMediaPublisher> socialMediaPublishers;\n    private final List<AuthorNotifier> articleAuthorNotifiers;\n\n    public ArticlePublisher(final ArticleMessageSender messageSender,\n                            final List<SocialMediaPublisher> socialMediaPublishers,\n                            final List<AuthorNotifier> articleAuthorNotifiers) {\n        this.messageSender = messageSender;\n        this.socialMediaPublishers = socialMediaPublishers;\n        this.articleAuthorNotifiers = articleAuthorNotifiers;\n    }\n\n    public void publishCreationOf(final Article article) {\n        messageSender.sendMessageForCreated(article);\n        socialMediaPublishers.forEach(socialMediaPublisher -> socialMediaPublisher.publish(article));\n        articleAuthorNotifiers.forEach(articleAuthorNotifier -> articleAuthorNotifier.notifyAboutCreationOf(article));\n    }\n\n    public void publishRetrievalOf(final Article article) {\n        messageSender.sendMessageForRetrieved(article);\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/Article.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class Article {\n\n    private final ArticleId id;\n    private final Title title;\n    private final Content content;\n    private final Author author;\n\n    private Article(final ArticleId id, final Title title, final Content content, final Author author) {\n        this.id = id;\n        this.title = title;\n        this.content = content;\n        this.author = author;\n    }\n\n    public void validateEligibilityForPublication() {\n        verifyForPlagiarism();\n        validateTitleLength();\n        validateContentLength();\n        checkPunctuation();\n        checkGrammar();\n        checkStyle();\n        //TODO: these methods are just placeholders with empty implementation\n    }\n\n    public ArticleId id() {\n        return id;\n    }\n\n    public Title title() {\n        return title;\n    }\n\n    public Content content() {\n        return content;\n    }\n\n    public Author author() {\n        return author;\n    }\n\n    private void checkGrammar() {\n    }\n\n    private void checkStyle() {\n    }\n\n    private void checkPunctuation() {\n    }\n\n    private void verifyForPlagiarism() {\n    }\n\n    private void validateContentLength() {\n    }\n\n    private void validateTitleLength() {\n    }\n\n    public static ArticleBuilder article() {\n        return new ArticleBuilder();\n    }\n\n\n    public static final class ArticleBuilder {\n        private ArticleId id;\n        private Title title;\n        private Content content;\n        private Author author;\n\n        private ArticleBuilder() {\n        }\n\n        public ArticleBuilder withId(ArticleId id) {\n            this.id = id;\n            return this;\n        }\n\n        public ArticleBuilder withTitle(Title title) {\n            this.title = title;\n            return this;\n        }\n\n        public ArticleBuilder withContent(Content content) {\n            this.content = content;\n            return this;\n        }\n\n        public ArticleBuilder withAuthor(Author author) {\n            this.author = author;\n            return this;\n        }\n\n        public Article build() {\n            return new Article(id, title, content, author);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/ArticleId.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class ArticleId {\n    private final String value;\n\n    private ArticleId(final String value) {\n        this.value = value;\n    }\n\n    public static ArticleId of(final String articleId) {\n        return new ArticleId(articleId);\n    }\n\n    public String value() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/Author.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class Author {\n    private final AuthorId id;\n    private final PersonName name;\n\n\n    private Author(final AuthorId id, final PersonName name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    public static AuthorBuilder author() {\n        return new AuthorBuilder();\n    }\n\n    public PersonName name() {\n        return name;\n    }\n\n    public AuthorId id() {\n        return id;\n    }\n\n    public static final class AuthorBuilder {\n        private AuthorId id;\n        private PersonName name;\n\n        private AuthorBuilder() {\n        }\n\n        public AuthorBuilder withId(AuthorId id) {\n            this.id = id;\n            return this;\n        }\n\n        public AuthorBuilder withName(PersonName name) {\n            this.name = name;\n            return this;\n        }\n\n        public Author build() {\n            return new Author(id, name);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/AuthorId.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class AuthorId {\n    private final String value;\n\n    private AuthorId(final String value) {\n        this.value = value;\n    }\n\n    public static AuthorId of(final String authorId) {\n        return new AuthorId(authorId);\n    }\n\n    public String value() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/Content.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class Content {\n    private final String value;\n\n    private Content(final String value) {\n        this.value = value;\n    }\n\n    public static Content of(final String content) {\n        return new Content(content);\n    }\n\n    public String value() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/PersonName.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class PersonName {\n    private final String value;\n\n    private PersonName(final String value) {\n        this.value = value;\n    }\n\n    public static PersonName of(final String content) {\n        return new PersonName(content);\n    }\n\n    public String value() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/model/Title.java",
    "content": "package tech.allegro.hexagon.articles.domain.model;\n\npublic class Title {\n    private final String value;\n\n    private Title(final String value) {\n        this.value = value;\n    }\n\n    public static Title of(final String title) {\n        return new Title(title);\n    }\n\n    public String value() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/ArticleMessageSender.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\npublic interface ArticleMessageSender {\n\n    void sendMessageForCreated(Article article);\n\n    void sendMessageForRetrieved(Article article);\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/ArticleRepository.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.Content;\nimport tech.allegro.hexagon.articles.domain.model.Title;\n\npublic interface ArticleRepository {\n\n    Article save(Author author, Title title, Content content);\n\n    Article get(ArticleId id);\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/ArticleService.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.ArticlePublisher;\nimport tech.allegro.hexagon.articles.domain.model.Article;\nimport tech.allegro.hexagon.articles.domain.model.ArticleId;\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\nimport tech.allegro.hexagon.articles.domain.model.Content;\nimport tech.allegro.hexagon.articles.domain.model.Title;\n\npublic final class ArticleService {\n\n    private final ArticleRepository articleRepository;\n    private final AuthorRepository authorRepository;\n    private final ArticlePublisher eventPublisher;\n\n\n    public ArticleService(final ArticleRepository articleRepository,\n                          final AuthorRepository authorRepository,\n                          final ArticlePublisher eventPublisher) {\n        this.articleRepository = articleRepository;\n        this.authorRepository = authorRepository;\n        this.eventPublisher = eventPublisher;\n    }\n\n    public ArticleId create(final AuthorId authorId, final Title title, final Content content) {\n        final Author author = authorRepository.get(authorId);\n        final Article article = articleRepository.save(author, title, content);\n\n        article.validateEligibilityForPublication();\n\n        eventPublisher.publishCreationOf(article);\n        return article.id();\n    }\n\n    public Article get(final ArticleId id) {\n        final Article article = articleRepository.get(id);\n        eventPublisher.publishRetrievalOf(article);\n        return article;\n    }\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/AuthorNotifier.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\npublic interface AuthorNotifier {\n\n    void notifyAboutCreationOf(Article article);\n\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/AuthorRepository.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.model.Author;\nimport tech.allegro.hexagon.articles.domain.model.AuthorId;\n\npublic interface AuthorRepository {\n\n    Author get(AuthorId authorId);\n}\n"
  },
  {
    "path": "src/main/java/tech/allegro/hexagon/articles/domain/ports/SocialMediaPublisher.java",
    "content": "package tech.allegro.hexagon.articles.domain.ports;\n\nimport tech.allegro.hexagon.articles.domain.model.Article;\n\npublic interface SocialMediaPublisher {\n\n    void publish(Article article);\n\n}\n"
  },
  {
    "path": "src/main/resources/application.properties",
    "content": "\n"
  }
]