{"id":13753854,"url":"https://github.com/kawasima/enkan","last_synced_at":"2025-04-05T19:14:41.459Z","repository":{"id":3549058,"uuid":"50105719","full_name":"kawasima/enkan","owner":"kawasima","description":"An explicit and simple Java framework","archived":false,"fork":false,"pushed_at":"2025-03-22T01:18:39.000Z","size":1527,"stargazers_count":71,"open_issues_count":12,"forks_count":13,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-03-29T18:09:25.596Z","etag":null,"topics":["framework","lightweight","microservice"],"latest_commit_sha":null,"homepage":"https://enkan.github.io","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kawasima.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-21T12:20:21.000Z","updated_at":"2024-03-31T14:17:18.000Z","dependencies_parsed_at":"2022-09-07T07:02:06.587Z","dependency_job_id":null,"html_url":"https://github.com/kawasima/enkan","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawasima%2Fenkan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawasima%2Fenkan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawasima%2Fenkan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kawasima%2Fenkan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kawasima","download_url":"https://codeload.github.com/kawasima/enkan/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247386266,"owners_count":20930619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["framework","lightweight","microservice"],"created_at":"2024-08-03T09:01:31.523Z","updated_at":"2025-04-05T19:14:41.434Z","avatar_url":"https://github.com/kawasima.png","language":"Java","funding_links":[],"categories":["lightweight","开发框架"],"sub_categories":["Web框架"],"readme":"# enkan\n\nEnkan(円環) is a microframework implementing a middleware pattern like ring or connect.\n\n[![CircleCI](https://circleci.com/gh/kawasima/enkan.svg?style=svg\u0026circle-token=e3d88ba4abde99dabc9fe527d0681d236ff49548)](https://circleci.com/gh/kawasima/enkan)\n\n## Concept\n\n- Minimal (Simple made easy)\n- Ease of development\n- Ease of operation\n\n### Minimal\n\n- Middleware pattern\n- No configuration files\n- Avoid blackbox\n- Less annotations\n- Less library dependencies\n- Single instance (Middlewares and compoments, controller)\n\n### Ease of development\n\n- Faster startup (Preventing to scan classes)\n- Reloading classes without restarting JVM\n- Trace execution of middlewares\n- Alert misconfiguration\n\n### Ease of operation\n\n- Starting server is fast. (~3 seconds)\n- Resetting application is very fast. (~1 seconds)\n- Run-time change predicates of middleware on the REPL\n\n## Requirements\n\n- Java8 or higher\n- Java EE 7 Specification\n\n## Middleware\n\n`Middleware` is an implementation of filters and chains.\n\n- Service Unavailable\n- Session\n- Flash\n- Cookie\n- Parsing parameters\n- Trace log\n- Populating form (kotowari)\n- JSR-303 Validation (kotowari)\n- Routing like Rails (kotowari)\n- Injecting components to a controller (kotowari)\n\n## Components\n\nIn Enkan, `component` is an object manages lifecycle of stateful objects.\n\n- HikariCP\n- Flyway\n- Freemarker\n- Thyemeleaf\n- Jetty\n- Undertow\n- Doma2\n- JPA(EclipseLink)\n- Jackson\n- S2Util-beans\n- Metrics\n\nUsing enkan and kotowari, the following will be your code\n\n```java\npublic class ExampleController {\n    @Inject\n    private TemplateEngineComponent templateEngine;\n\n    @Inject\n    private DomaDaoProvider daoProvider;\n\n    public HttpResponse index(ExampleForm form) {\n        CustomerDao customerDao = daoProvider.get(CustomerDao.class);\n        Customer customer = customerDao.selectById(form.getId());\n        return templateEngine.render(\"example\",\n                \"customer\", customer);\n    }\n}\n```\n\n## Get started\n\nAdd sonatype snapshots repository to your pom.xml\n\n```xml\n  \u003crepositories\u003e\n    \u003crepository\u003e\n      \u003cid\u003esonatype-snapshot\u003c/id\u003e\n      \u003curl\u003ehttp://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n      \u003creleases\u003e\n        \u003cenabled\u003efalse\u003c/enabled\u003e\n      \u003c/releases\u003e\n      \u003csnapshots\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n      \u003c/snapshots\u003e\n    \u003c/repository\u003e\n  \u003c/repositories\u003e\n```\n\n## Manual\n\n### EnkanSystem\n\nThe Enkan system consist of components. A component is a singleton instance that shares data between requests.\n\n```java\nEnkanSystem.of(\n    \"doma\", new DomaProvider(),\n    \"flyway\", new FlywayMigration(),\n    \"template\", new FreemarkerComponent(),\n    \"datasource\", new HikariCPComponent(OptionMap.of(\"uri\", \"jdbc:h2:mem:test\")),\n    \"app\", new ApplicationComponent(\"kotowari.example.MyApplicationFactory\"),\n    \"http\", builder(new JettyComponent())\n        .set(JettyComponent::setPort, Env.getInt(\"PORT\", 3000))\n        .build()\n).relationships(\n    component(\"http\").using(\"app\"),\n    component(\"app\").using(\"template\", \"doma\", \"datasource\"),\n    component(\"doma\").using(\"datasource\"),\n    component(\"flyway\").using(\"datasource\")\n);\n```\n\n### Application\n\nAn application has a stack of middlewares.\nA middleware is a single instance. By `use` method, the middleware is used by application.\n\n```java\napp.use(ANY(\"/secret\"), new AuthenticateMiddleware());\n```\n\n### REPL\n\nEnkan system is operated by a REPL interface.\n\n- Start a server\n```\nREPL\u003e /start\n[pool-1-thread-1] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-0 - is starting.\n[pool-1-thread-1] INFO org.flywaydb.core.internal.util.VersionPrinter - Flyway 3.2.1 by Boxfuse\n[pool-1-thread-1] INFO org.flywaydb.core.internal.dbsupport.DbSupportFactory - Database: jdbc:h2:mem:test (H2 1.4)\n[pool-1-thread-1] INFO org.flywaydb.core.internal.command.DbValidate - Validated 1 migration (execution time 00:00.019s)\n[pool-1-thread-1] INFO org.flywaydb.core.internal.metadatatable.MetaDataTableImpl - Creating Metadata table: \"PUBLIC\".\"schema_version\"\n[pool-1-thread-1] INFO org.flywaydb.core.internal.command.DbMigrate - Current version of schema \"PUBLIC\": \u003c\u003c Empty Schema \u003e\u003e\n[pool-1-thread-1] INFO org.flywaydb.core.internal.command.DbMigrate - Migrating schema \"PUBLIC\" to version 1 - CreateCustomer\n[pool-1-thread-1] INFO org.flywaydb.core.internal.command.DbMigrate - Successfully applied 1 migration to schema \"PUBLIC\" (execution time 00:00.059s).\n2 02, 2016 7:58:35 午後 org.hibernate.validator.internal.util.Version \u003cclinit\u003e\nINFO: HV000001: Hibernate Validator 5.2.2.Final\n[pool-1-thread-1] INFO org.eclipse.jetty.util.log - Logging initialized @2688228ms\n[pool-1-thread-1] INFO org.eclipse.jetty.server.Server - jetty-9.3.5.v20151012\nREPL\u003e [pool-1-thread-1] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@5325abc3{HTTP/1.1,[http/1.1]}{0.0.0.0:3000}\n[pool-1-thread-1] INFO org.eclipse.jetty.server.Server - Started @2688295ms\n```\n- Stop a server\n- Reload an application\n- Show routing information\n```\nREPL\u003e /routes app\nGET    /                                        {controller=class kotowari.example.controller.ExampleController, action=index}\nGET    /m1                                      {controller=class kotowari.example.controller.ExampleController, action=method1}\nGET    /m2                                      {controller=class kotowari.example.controller.ExampleController, action=method2}\nGET    /m3                                      {controller=class kotowari.example.controller.ExampleController, action=method3}\nGET    /m4                                      {controller=class kotowari.example.controller.ExampleController, action=method4}\nPOST   /login                                   {controller=class kotowari.example.controller.LoginController, action=login}\n```\n- Show middleware stack\n```\nREPL\u003e /middleware app list\nANY   defaultCharset (enkan.middleware.DefaultCharsetMiddleware@4929dbc3)\nNONE   serviceUnavailable (enkan.middleware.ServiceUnavailableMiddleware@2ee4fa3b)\nANY   stacktrace (enkan.middleware.StacktraceMiddleware@545872dd)\nANY   trace (enkan.middleware.TraceMiddleware@1c985ffd)\nANY   contentType (enkan.middleware.ContentTypeMiddleware@1b68686e)\nANY   httpStatusCat (enkan.middleware.HttpStatusCatMiddleware@12d47c1a)\nANY   params (enkan.middleware.ParamsMiddleware@58d3a07)\nANY   normalization (enkan.middleware.NormalizationMiddleware@5b34eafc)\nANY   cookies (enkan.middleware.CookiesMiddleware@347c2ec)\nANY   session (enkan.middleware.SessionMiddleware@32424a32)\nANY   resource (enkan.middleware.ResourceMiddleware@5e73037f)\nANY   routing (kotowari.middleware.RoutingMiddleware@226c7147)\nANY   domaTransaction (enkan.middleware.DomaTransactionMiddleware@1f819744)\nANY   form (kotowari.middleware.FormMiddleware@3f325d5c)\nANY   validateForm (kotowari.middleware.ValidateFormMiddleware@791cd93e)\nANY   htmlRenderer (enkan.middleware.HtmlRenderer@383b6913)\nANY   controllerInvoker (kotowari.middleware.ControllerInvokerMiddleware@2b13e2e7)\n```\n- Rewrite a predicate of middleware\n```\nREPL\u003e /middleware app predicate serviceUnavailable ANY\nREPL\u003e /middleware app list\nANY   defaultCharset (enkan.middleware.DefaultCharsetMiddleware@4929dbc3)\nANY   serviceUnavailable (enkan.middleware.ServiceUnavailableMiddleware@2ee4fa3b)\nANY   stacktrace (enkan.middleware.StacktraceMiddleware@545872dd)\n```\n\n\nEnkan REPL can attach to a running process.\n\n```\nenkan\u003e /connect 35677\nConnected to server (port = 35677)\n```\n\nIf you use Java9 or higher, you can use JShellRepl. It's so great experience!!\n\n```\nenkan\u003e /connect 64815\nConnected to server (port = 64815)\nenkan\u003e system\nEnkanSystem {\n  \"datasource\":   #HikariCPComponent {\n    \"jdbcUrl\": \"jdbc:h2:mem:test\",\n    \"username\": \"null\",\n    \"dependencies\": []\n  },\n  \"flyway\":   enkan.component.flyway.FlywayMigration@345f69f3,\n  \"doma\":   #DomaProvider {\n    \"dependencies\": [\"flyway\", \"datasource\"]\n  },\n  \"jwt\":   net.unit8.bouncr.sign.JsonWebToken@3f57bcad,\n  \"jackson\":   #JacksonBeansConverter {\n    \"dependencies\": []\n  },\n  \"template\":   enkan.component.freemarker.FreemarkerTemplateEngine@1e8b7643,\n  \"app\":   #ApplicationComponent {\n    \"application\": \"null\",\n    \"factoryClassName\": \"net.unit8.rascaloid.RascaloidApplicationFactory\",\n    \"dependencies\": [\"template\", \"doma\", \"jackson\", \"datasource\", \"jwt\"]\n  },\n  \"http\":   enkan.component.jetty.JettyComponent@7d286fb6\n}\n\nenkan\u003e system.getComponent(\"doma\")\n#DomaProvider {\n  \"dependencies\": [\"flyway\", \"datasource\"]\n}\n```\n\n\n### Kotowari\n\nKotowari is a web routing framework on Enkan.\n\nIt provides a rails-like syntax for routing definition.\n\n```java\nRoutes routes = Routes.define(r -\u003e {\n    r.get(\"/\").to(ExampleController.class, \"index\");\n    r.get(\"/m1\").to(ExampleController.class, \"method1\");\n    r.get(\"/m2\").to(ExampleController.class, \"method2\");\n    r.get(\"/m3\").to(ExampleController.class, \"method3\");\n    r.get(\"/m4\").to(ExampleController.class, \"method4\");\n    r.post(\"/login\").to(LoginController.class, \"login\");\n    r.resource(CustomerController.class);\n}).compile();\n```\n\n## Get started\n\nkotowari-archetype is very useful at starting point.\n\n```sh\n% bash \u003c(curl -L https://raw.githubusercontent.com/kawasima/kotowari-archetype/master/kotowari.sh)\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100  2051  100  2051    0     0   5962      0 --:--:-- --:--:-- --:--:--  5944\n\n╔═╗┌┐┌┬┌─┌─┐┌┐┌ ┬ ╦╔═┌─┐┌┬┐┌─┐┬ ┬┌─┐┬─┐┬\n║╣ │││├┴┐├─┤│││┌┼─╠╩╗│ │ │ │ ││││├─┤├┬┘│\n╚═╝┘└┘┴ ┴┴ ┴┘└┘└┘ ╩ ╩└─┘ ┴ └─┘└┴┘┴ ┴┴└─┴\n\nWhich web server component do you use?:\n1) undertow\n2) jetty\n3) No thank you\n#?\n```\n\n\n## License\n\nCopyright © 2016-2018 kawasima\n\nDistributed under the Eclipse Public License either version 1.0 or (at your option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkawasima%2Fenkan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkawasima%2Fenkan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkawasima%2Fenkan/lists"}