{"id":15043544,"url":"https://github.com/yegor256/takes","last_synced_at":"2025-05-13T23:09:22.717Z","repository":{"id":25493032,"uuid":"28924109","full_name":"yegor256/takes","owner":"yegor256","description":"True Object-Oriented Java Web Framework without NULLs, Static Methods, Annotations, and Mutable Objects","archived":false,"fork":false,"pushed_at":"2025-05-07T17:47:48.000Z","size":32883,"stargazers_count":826,"open_issues_count":99,"forks_count":201,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-05-07T18:46:45.611Z","etag":null,"topics":["http","http-server","java","java-framework","oop","web-framework","xml-xslt"],"latest_commit_sha":null,"homepage":"https://www.takes.org/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yegor256.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-01-07T16:57:47.000Z","updated_at":"2025-05-07T17:47:52.000Z","dependencies_parsed_at":"2023-02-18T12:46:10.697Z","dependency_job_id":"36f825df-bb8e-4799-846d-17b457fb2623","html_url":"https://github.com/yegor256/takes","commit_stats":{"total_commits":2729,"total_committers":106,"mean_commits":"25.745283018867923","dds":0.7903994137046537,"last_synced_commit":"07be911144a0106ee4978c65836e7470620e3b14"},"previous_names":[],"tags_count":155,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Ftakes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Ftakes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Ftakes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Ftakes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yegor256","download_url":"https://codeload.github.com/yegor256/takes/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254042068,"owners_count":22004837,"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":["http","http-server","java","java-framework","oop","web-framework","xml-xslt"],"created_at":"2024-09-24T20:49:14.828Z","updated_at":"2025-05-13T23:09:17.702Z","avatar_url":"https://github.com/yegor256.png","language":"Java","funding_links":[],"categories":["开发框架","Projects","项目"],"sub_categories":["Web Frameworks","Web框架"],"readme":"# Pure Object-Oriented Java Web Framework\n\n[![EO principles respected here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org)\n[![DevOps By Rultor.com](https://www.rultor.com/b/yegor256/takes)](https://www.rultor.com/p/yegor256/takes)\n[![We recommend IntelliJ IDEA](https://www.elegantobjects.org/intellij-idea.svg)](https://www.jetbrains.com/idea/)\n\n[![mvn](https://github.com/yegor256/takes/actions/workflows/mvn.yml/badge.svg)](https://github.com/yegor256/takes/actions/workflows/mvn.yml)\n[![Javadoc](https://www.javadoc.io/badge/org.takes/takes.svg)](https://www.javadoc.io/doc/org.takes/takes)\n[![codebeat badge](https://codebeat.co/badges/5721bba4-59cd-44ea-a60f-6043734187f7)](https://codebeat.co/projects/github-com-yegor256-takes)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/takes/blob/master/LICENSE.txt)\n[![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/takes.svg)](https://codecov.io/github/yegor256/takes?branch=master)\n[![Hits-of-Code](https://hitsofcode.com/github/yegor256/takes)](https://hitsofcode.com/view/github/yegor256/takes)\n[![SonarQube](https://img.shields.io/badge/sonar-ok-green.svg)](https://sonarcloud.io/dashboard?id=org.takes%3Atakes)\n[![Maintainability](https://api.codeclimate.com/v1/badges/dca23c1154539343737a/maintainability)](https://codeclimate.com/github/yegor256/takes/maintainability)\n[![Maven Central](https://img.shields.io/maven-central/v/org.takes/takes.svg)](https://maven-badges.herokuapp.com/maven-central/org.takes/takes)\n[![PDD status](https://www.0pdd.com/svg?name=yegor256/takes)](https://www.0pdd.com/p?name=yegor256/takes)\n\n**Takes** is a [true object-oriented][oop]\nand [immutable][immutable]\nJava8 web development framework. Its key benefits, comparing to all others,\ninclude these\nfour fundamental principles:\n\n1. Not a single `null`\n([why NULL is bad?][null])\n2. Not a single `public` `static` method\n([why they are bad?][utility])\n3. Not a single mutable class\n([why they are bad?][immutable])\n4. Not a single `instanceof` keyword, type casting, or reflection\n([why?][casting])\n\nOf course, there are no configuration files.\nBesides that, these are more traditional features, out of the box:\n\n* Hit-refresh debugging\n* [XML+XSLT](http://www.yegor256.com/2014/06/25/xml-and-xslt-in-browser.html)\n* [JSON](http://en.wikipedia.org/wiki/JSON)\n* [RESTful](http://en.wikipedia.org/wiki/Representational_state_transfer)\n* Templates, incl. [Apache Velocity](http://velocity.apache.org/)\n\nThis is what is not supported and won't be supported:\n\n* [WebSockets](http://en.wikipedia.org/wiki/WebSocket)\n\nThese two web systems use Takes, and they are open source:\n[wring.io](http://www.wring.io) ([sources](https://github.com/yegor256/wring)),\n[jare.io](http://www.jare.io) ([sources](https://github.com/yegor256/jare)).\n\nWatch these videos to learn more:\n[An Immutable Object-Oriented Web Framework][webcast] and\n[Takes, Java Web Framework, Intro](https://www.youtube.com/watch?v=nheD2LNYrpk).\nThis\n[blog post](http://www.yegor256.com/2015/03/22/takes-1.24.6-web-framework.html)\nmay help you too.\n\n## Contents\n\n* [Quick Start](#quick-start)\n* [Build and Run With Maven](#build-and-run-with-maven)\n* [Build and Run With Gradle](#build-and-run-with-gradle)\n* [Unit Testing](#unit-testing)\n* [Integration Testing](#integration-testing)\n* [A Bigger Example](#a-bigger-example)\n  * [Front Interface](#front-interface)\n  * [Back Interface](#back-interface)\n* [Templates](#templates)\n  * [Velocity Templates](#velocity-templates)\n* [Static Resources](#static-resources)\n* [Hit Refresh Debugging](#hit-refresh-debugging)\n* [Request Methods (POST, PUT, HEAD, etc.)](#request-methods-post-put-head-etc)\n* [Request Parsing](#request-parsing)\n* [Form Processing](#form-processing)\n* [Exception Handling](#exception-handling)\n* [Redirects](#redirects)\n* [RsJSON](#rsjson)\n* [RsXembly](#rsxembly)\n* [GZIP Compression](#gzip-compression)\n* [SSL Configuration](#ssl-configuration)\n* [Authentication](#authentication)\n* [Command Line Arguments](#command-line-arguments)\n* [Logging](#logging)\n* [Directory Layout](#directory-layout)\n* [Optional dependencies](#optional-dependencies)\n* [Backward compatibility](#backward-compatibility)\n* [Version pattern for RESTful API](#version-pattern-for-restful-api)\n* [How to contribute](#how-to-contribute)\n\n## Quick Start\n\nCreate this `App.java` file:\n\n```java\nimport org.takes.http.Exit;\nimport org.takes.http.FtBasic;\nimport org.takes.facets.fork.FkRegex;\nimport org.takes.facets.fork.TkFork;\npublic final class App {\n  public static void main(final String... args) throws Exception {\n    new FtBasic(\n      new TkFork(new FkRegex(\"/\", \"hello, world!\")), 8080\n    ).start(Exit.NEVER);\n  }\n}\n```\n\nThen, download [`takes-1.24.6-jar-with-dependencies.jar`][jar]\nand compile your Java code:\n\n```bash\njavac -cp takes-1.24.6-jar-with-dependencies.jar App.java\n```\n\nNow, run it like this:\n\n```bash\njava -Dfile.encoding=UTF-8 -cp takes-1.24.6-jar-with-dependencies.jar:. App\n```\n\nShould work :)\n\nThis code starts a new HTTP server on port 8080 and renders a plain-text page on\nall requests at the root URI.\n\n**Important**: Pay attention that UTF-8 encoding is set on the command line.\nThe entire framework relies on your default Java encoding, which is not\nnecessarily UTF-8 by default. To be sure, always set it on the command line\nwith `file.encoding` Java argument. We decided not to hard-code \"UTF-8\" in\nour code mostly because this would be against the entire idea of\nJava localization,\naccording to which a user always should have a choice of encoding and language\nselection. We're using `Charset.defaultCharset()` everywhere in the code.\n\n## Build and Run With Maven\n\nIf you're using Maven, this is how your `pom.xml` should look like:\n\n```xml\n\u003cproject\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003eorg.takes\u003c/groupId\u003e\n      \u003cartifactId\u003etakes\u003c/artifactId\u003e\n      \u003cversion\u003e1.24.6\u003c/version\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n  \u003cprofiles\u003e\n    \u003cprofile\u003e\n      \u003cid\u003ehit-refresh\u003c/id\u003e\n      \u003cbuild\u003e\n        \u003cplugins\u003e\n          \u003cplugin\u003e\n            \u003cgroupId\u003eorg.codehaus.mojo\u003c/groupId\u003e\n            \u003cartifactId\u003eexec-maven-plugin\u003c/artifactId\u003e\n            \u003cexecutions\u003e\n              \u003cexecution\u003e\n                \u003cid\u003estart-server\u003c/id\u003e\n                \u003cphase\u003epre-integration-test\u003c/phase\u003e\n                \u003cgoals\u003e\n                  \u003cgoal\u003ejava\u003c/goal\u003e\n                \u003c/goals\u003e\n              \u003c/execution\u003e\n            \u003c/executions\u003e\n            \u003cconfiguration\u003e\n              \u003cmainClass\u003efoo.App\u003c/mainClass\u003e \u003c!-- your main class --\u003e\n              \u003ccleanupDaemonThreads\u003efalse\u003c/cleanupDaemonThreads\u003e\n              \u003carguments\u003e\n                \u003cargument\u003e--port=${port}\u003c/argument\u003e\n              \u003c/arguments\u003e\n            \u003c/configuration\u003e\n          \u003c/plugin\u003e\n        \u003c/plugins\u003e\n      \u003c/build\u003e\n    \u003c/profile\u003e\n  \u003c/profiles\u003e\n\u003c/project\u003e\n```\n\nWith this configuration you can run it from command line:\n\n```bash\nmvn clean integration-test -Phit-refresh -Dport=8080\n```\n\nMaven will start the server and you can see it at `http://localhost:8080`.\n\n## Using in servlet app\n\nCreate a take with constructor accepting `ServletContext`:\n\n```java\npackage com.myapp;\npublic final class TkApp implements Take {\n  private final ServletContext ctx;\n  public TkApp(final ServletContext context) {\n    this.ctx = context;\n  }\n  @Override\n  public Response act(final Request req) throws Exception {\n    return new RsText(\"Hello servlet!\");\n  }\n}\n```\n\nAdd `org.takes.servlet.SrvTake` to your `web.xml`, don't forget to specify\ntake class as servlet `init-param`:\n\n```xml\n\u003cservlet\u003e\n  \u003cservlet-name\u003etakes\u003c/servlet-name\u003e\n  \u003cservlet-class\u003eorg.takes.servlet.SrvTake\u003c/servlet-class\u003e\n  \u003cinit-param\u003e\n    \u003cparam-name\u003etake\u003c/param-name\u003e\n    \u003cparam-value\u003ecom.myapp.TkApp\u003c/param-value\u003e\n  \u003c/init-param\u003e\n\u003c/servlet\u003e\n\u003cservlet-mapping\u003e\n  \u003cservlet-name\u003etakes\u003c/servlet-name\u003e\n  \u003curl-pattern\u003e/*\u003c/url-pattern\u003e\n\u003c/servlet-mapping\u003e\n```\n\n## Build and Run With Gradle\n\nIf you're using Gradle, this is how your `build.gradle` should look like:\n\n```groovy\nplugins {\n  id 'java'\n  id 'application'\n}\nrepositories {\n  mavenCentral()\n}\ndependencies {\n  compile group: 'org.takes', name: 'takes', version: '1.11.3'\n}\nmainClassName='foo.App' //your main class\n```\n\nWith this configuration you can run it from command line:\n\n```bash\ngradle run -Phit-refresh -Dport=8080\n```\n\n## Unit Testing\n\nThis is how you can unit test the app, using JUnit 4.x and\n[Hamcrest](http://hamcrest.org):\n\n```java\npublic final class AppTest {\n  @Test\n  public void returnsHttpResponse() throws Exception {\n    MatcherAssert.assertThat(\n      new RsPrint(\n        new App().act(new RqFake(\"GET\", \"/\"))\n      ).printBody(),\n      Matchers.equalsTo(\"hello, world!\")\n    );\n  }\n}\n```\n\nYou can create a fake request with form parameters like this:\n\n```java\nnew RqForm.Fake(\n  new RqFake(),\n  \"foo\", \"value-1\",\n  \"bar\", \"value-2\"\n)\n```\n\n## Integration Testing\n\nHere is how you can test the entire server via HTTP, using JUnit and\n[jcabi-http](http://http.jcabi.com) for making HTTP requests:\n\n```java\npublic final class AppITCase {\n  @Test\n  public void returnsTextPageOnHttpRequest() throws Exception {\n    new FtRemote(new App()).exec(\n      new FtRemote.Script() {\n        @Override\n        public void exec(final URI home) throws IOException {\n          new JdkRequest(home)\n            .fetch()\n            .as(RestResponse.class)\n            .assertStatus(HttpURLConnection.HTTP_OK)\n            .assertBody(Matchers.equalTo(\"hello, world!\"));\n        }\n      }\n    );\n  }\n}\n```\n\nMore complex integration testing examples you can find in one\nof the open source projects that are using Take, for example:\n[rultor.com][rultor-code].\n\n## A Bigger Example\n\nLet's make it a bit more sophisticated:\n\n```java\npublic final class App {\n  public static void main(final String... args) {\n    new FtBasic(\n      new TkFork(\n        new FkRegex(\"/robots\\\\.txt\", \"\"),\n        new FkRegex(\"/\", new TkIndex())\n      ),\n      8080\n    ).start(Exit.NEVER);\n  }\n}\n```\n\nThe `FtBasic` is accepting new incoming sockets on port 8080,\nparses them according to HTTP 1.1 specification and creates instances\nof class `Request`. Then, it gives requests to the instance of `TkFork`\n(`tk` stands for \"take\") and expects it to return an instance of `Take` back.\nAs you probably understood already, the first regular expression that matches\nreturns a take. `TkIndex` is our custom class,\nlet's see how it looks:\n\n```java\npublic final class TkIndex implements Take {\n  @Override\n  public Response act(final Request req) {\n    return new RsHtml(\"\u003chtml\u003eHello, world!\u003c/html\u003e\");\n  }\n}\n```\n\nIt is immutable and must implement a single method `act()`, which is returning\nan instance of `Response`. So far so good, but this class doesn't have an access\nto an HTTP request. Here is how we solve this:\n\n```java\nnew TkFork(\n  new FkRegex(\n    \"/file/(?\u003cpath\u003e[^/]+)\",\n    new TkRegex() {\n      @Override\n      public Response act(final RqRegex request) throws Exception {\n        final File file = new File(\n          request.matcher().group(\"path\")\n        );\n        return new RsHTML(\n          FileUtils.readFileToString(file, Charsets.UTF_8)\n        );\n      }\n    }\n  )\n)\n```\n\nWe're using `TkRegex` instead of `Take`, in order to deal with\n`RqRegex` instead of a more generic `Request`. `RqRegex` gives an instance\nof `Matcher` used by `FkRegex` for pattern matching.\n\nHere is a more complex and verbose example:\n\n```java\npublic final class App {\n  public static void main(final String... args) {\n    new FtBasic(\n      new TkFork(\n        new FkRegex(\"/robots.txt\", \"\"),\n        new FkRegex(\"/\", new TkIndex()),\n        new FkRegex(\n          \"/xsl/.*\",\n          new TkWithType(new TkClasspath(), \"text/xsl\")\n        ),\n        new FkRegex(\"/account\", new TkAccount(users)),\n        new FkRegex(\"/balance/(?\u003cuser\u003e[a-z]+)\", new TkBalance())\n      )\n    ).start(Exit.NEVER);\n  }\n}\n```\n\n## Front interface\n\nEssential part of [Bigger Example](#a-bigger-example) is\n[Front](src/main/java/org/takes/http/Front.java) interface.\nIt's encapsulates server's [back-end](src/main/java/org/takes/http/Back.java)\nand used to start an instance, which will accept requests and return results.\n`FtBasic`, which is a basic front, implements that interface - you've\nseen it's usage in above mentioned example.\n\nThere are other useful implementations of this interface:\n\n* The [FtRemote](src/main/java/org/takes/http/FtRemote.java)\nclass allows you to provide script, that will be executed against\ngiven front. You can see how it's used in\n[integration tests](#integration-testing).\n* The [FtCli](src/main/java/org/takes/http/FtCli.java) class\nallows you to start your application with command line arguments. More details\nin [Command Line Arguments](#command-line-arguments).\n* The [FtSecure](src/main/java/org/takes/http/FtSecure.java) class allows\nyou to start your application with SSL. More details in\n[SSL Configuration](#ssl-configuration).\n\n## Back interface\n\n[Back](src/main/java/org/takes/http/Back.java) interface is the back-end that\nis responsible for IO operations on TCP network level. There are various useful\nimplementations of that interface:\n\n* The [BkBasic](src/main/java/org/takes/http/BkBasic.java) class is a basic\nimplementation of the `Back` interface. It is responsible for accepting the\nrequest from `Socket`, converting the socket's input to the\n[Request](src/main/java/org/takes/Request.java), dispatching it to the\nprovided [Take](src/main/java/org/takes/Take.java) instance, getting\nthe result and printing it to the socket's output until all the request is\nfulfilled.\n* The [BkParallel](src/main/java/org/takes/http/BkParallel.java) class is\na decorator of the `Back` interface, that is responsible for running the\nback-end in parallel threads. You can specify the number of threads or try\nto use the default number, which depends on available processors number in JVM.\n* The [BkSafe](src/main/java/org/takes/http/BkSafe.java) class is a decorator\nof the `Back` interface, that is responsible for running the back-end in a\nsafe mode. That means that it will ignore exception thrown from original `Back`.\n* The [BkTimeable](src/main/java/org/takes/http/BkTimeable.java) class is a\ndecorator of the `Back` interface, that is responsible for running the back-end\nfor specified maximum lifetime in milliseconds. It is constantly checking if\nthe thread with original `back` exceeds provided limit and if so - it's\ninterrupts the thread of that `back`.\n* The [BkWrap](src/main/java/org/takes/http/BkWrap.java) class is a convenient\nwrap over the original `Back` instance. It's just delegates the `accept`\nto that `Back` and might be useful if you want to add your own decorators of the\n`Back` interface. This class is used in `BkParallel` and `BkSafe` as\na parent class.\n\n## Templates\n\nNow let's see how we can render something more complex than a plain text.\nFirst, XML+XSLT is a recommended mechanism of HTML rendering.\nEven though it may be\ntoo complex, give it a try, you won't regret. Here is how we render a simple XML\npage that is transformed to HTML5 on-fly (more about `RsXembly` read below):\n\n```java\npublic final class TkAccount implements Take {\n  private final Users users;\n  public TkAccount(final Users users) {\n    this.users = users;\n  }\n  @Override\n  public Response act(final Request req) {\n    final User user = this.users.find(new RqCookies(req).get(\"user\"));\n    return new RsLogin(\n      new RsXslt(\n        new RsXembly(\n          new XeStylesheet(\"/xsl/account.xsl\"),\n          new XeAppend(\"page\", user)\n        )\n      ),\n      user\n    );\n  }\n}\n```\n\nThis is how that `User` class may look like:\n\n```java\npublic final class User implements XeSource {\n  private final String name;\n  private final int balance;\n  @Override\n  public Iterable\u003cDirective\u003e toXembly() {\n    return new Directives().add(\"user\")\n      .add(\"name\").set(this.name).up()\n      .add(\"balance\").set(Integer.toString(this.balance));\n  }\n}\n```\n\nHere is how `RsLogin` may look like:\n\n```java\npublic final class RsLogin extends RsWrap {\n  public RsLogin(final Response response, final User user) {\n    super(\n      new RsWithCookie(\n        response, \"user\", user.toString()\n      )\n    );\n  }\n}\n```\n\n## Velocity Templates\n\nLet's say, you want to use [Velocity](http://velocity.apache.org/):\n\n```java\npublic final class TkHelloWorld implements Take {\n  @Override\n  public Response act(final Request req) {\n    return new RsVelocity(\n      \"hi, ${user.name}! You've got ${user.balance}\",\n      new RsVelocity.Pair(\"user\", new User())\n    );\n  }\n}\n```\n\nYou will need this extra dependency in classpath:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.apache.velocity\u003c/groupId\u003e\n  \u003cartifactId\u003evelocity-engine-core\u003c/artifactId\u003e\n  \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nFor Gradle users:\n\n```groovy\ndependencies {\n  ...\n  runtime group: 'org.apache.velocity',\n  name: 'velocity-engine-core',\n  version: 'x.xx' // put the version here\n  ...\n}\n```\n\n## Static Resources\n\nVery often you need to serve static resources to your web users, like CSS\nstylesheets, images, JavaScript files, etc. There are a few supplementary\nclasses for that:\n\n```java\nnew TkFork(\n  new FkRegex(\"/css/.+\", new TkWithType(new TkClasspath(), \"text/css\")),\n  new FkRegex(\"/data/.+\", new TkFiles(new File(\"/usr/local/data\"))\n)\n```\n\nClass `TkClasspath` take static part of the request URI and finds\na resource with this name in classpath.\n\n`TkFiles` just looks by file name in the directory configured.\n\n`TkWithType` sets content type of all responses coming out of\nthe decorated take.\n\n## Hit Refresh Debugging\n\nIt is a very convenient feature. Once you start the app you want to be able to\nmodify its static resources (CSS, JS, XSL, etc), refresh the page in a browser\nand immediately see the result. You don't want to re-compile the entire project\nand restart it. Here is what you need to do to your sources in order to enable\nthat feature:\n\n```java\nnew TkFork(\n  new FkRegex(\n    \"/css/.+\",\n    new TkWithType(\n      new TkFork(\n        new FkHitRefresh(\n          \"./src/main/resources/foo/scss/**\", // what sources to watch\n          \"mvn sass:compile\", // what to run when sources are modified\n          new TkFiles(\"./target/css\")\n        )\n        new FkFixed(new TkClasspath())\n      ),\n      \"text/css\"\n    )\n  )\n)\n```\n\nThis `FkHitRefresh` fork is a decorator of take. Once it sees\n`X-Take-Refresh` header in the request, it realizes that the server\nis running in\n\"hit-refresh\" mode and passes the request to the encapsulated take. Before it\npasses the request it tries to understand whether any of the resources\nare older than compiled files. If they are older, it tries\nto run compilation tool to build them again.\n\n## Request Methods (POST, PUT, HEAD, etc.)\n\nHere is an example:\n\n```java\nnew TkFork(\n  new FkRegex(\n    \"/user\",\n    new TkFork(\n      new FkMethods(\"GET\", new TkGetUser()),\n      new FkMethods(\"POST,PUT\", new TkPostUser()),\n      new FkMethods(\"DELETE\", new TkDeleteUser())\n    )\n  )\n)\n```\n\n## Request Parsing\n\nHere is how you can parse an instance of `Request`:\n\n```java\nHref href = new RqHref.Base(request).href();\nURI uri = href.uri();\nIterable\u003cString\u003e values = href.param(\"key\");\n```\n\nFor a more complex parsing try to use Apache Http Client or something\nsimilar.\n\n## Form Processing\n\nHere is an example:\n\n```java\npublic final class TkSavePhoto implements Take {\n  @Override\n  public Response act(final Request req) {\n    final String name = new RqForm(req).param(\"name\");\n    return new RsWithStatus(HttpURLConnection.HTTP_NO_CONTENT);\n  }\n}\n```\n\n## Exception Handling\n\nBy default, `TkFork` lets all exceptions bubble up. If one of your take\ncrashes, a user will see a default error page. Here is how you can configure\nthis behavior:\n\n```java\npublic final class App {\n  public static void main(final String... args) {\n    new FtBasic(\n      new TkFallback(\n        new TkFork(\n          new FkRegex(\"/robots\\\\.txt\", \"\"),\n          new FkRegex(\"/\", new TkIndex())\n        ),\n        new FbChain(\n          new FbStatus(404, new RsText(\"sorry, page is absent\")),\n          new FbStatus(405, new RsText(\"this method is not allowed here\")),\n          new Fallback() {\n            @Override\n            public Iterator\u003cResponse\u003e route(final RqFallback req) {\n              return Collections.\u003cResponse\u003esingleton(\n                new RsHTML(\"oops, something went terribly wrong!\")\n              ).iterator();\n            }\n          }\n        )\n      ),\n      8080\n    ).start(Exit.NEVER);\n  }\n}\n```\n\n`TkFallback` decorates an instance of Take and catches all exceptions any of\nits take may throw. Once it's thrown, an instance of `FbChain` will\nfind the most suitable fallback and will fetch a response from there.\n\n## Redirects\n\nSometimes it's very useful to return a redirect response (`30x` status code),\neither by a normal `return` or by throwing an exception. This example\nillustrates both methods:\n\n```java\npublic final class TkPostMessage implements Take {\n  @Override\n  public Response act(final Request req) {\n    final String body = new RqPrint(req).printBody();\n    if (body.isEmpty()) {\n      throw new RsForward(\n        new RsFlash(\"message can't be empty\")\n      );\n    }\n    // save the message to the database\n    return new RsForward(\n      new RsFlash(\n        \"thanks, the message was posted\"\n      ),\n      \"/\"\n    );\n  }\n}\n```\n\nThen, you should decorate the entire `TkFork` with this\n`TkForward` and `TkFlash`:\n\n```java\npublic final class App {\n  public static void main(final String... args) {\n    new FtBasic(\n      new TkFlash(\n        new TkForward(\n          new TkFork(new FkRegex(\"/\", new TkPostMessage())\n        )\n      ),\n      8080\n    ).start(Exit.NEVER);\n  }\n}\n```\n\n## RsJSON\n\nHere is how we can deal with JSON:\n\n```java\npublic final class TkBalance extends TkFixed {\n  @Override\n  public Response act(final RqRegex request) {\n    return new RsJSON(\n      new User(request.matcher().group(\"user\"))\n    );\n  }\n}\n```\n\nThis is the method to add to `User`:\n\n```java\npublic final class User implements XeSource, RsJSON.Source {\n  @Override\n  public JsonObject toJSON() {\n    return Json.createObjectBuilder()\n      .add(\"balance\", this.balance)\n      .build();\n  }\n}\n```\n\n## RsXembly\n\nHere is how you generate an XML page using [Xembly](http://www.xembly.org):\n\n```java\nResponse response = new RsXembly(\n  new XeAppend(\"page\"),\n  new XeDirectives(\"XPATH '/page'\", this.user)\n)\n```\n\nThis is a complete example, with all possible options:\n\n```java\nResponse response = new RsXembly(\n  new XeStylesheet(\"/xsl/account.xsl\"), // add processing instruction\n  new XeAppend(\n    \"page\", // create a DOM document with \"page\" root element\n    new XeMillis(false), // add \"millis\" attribute to the root, with current time\n    user, // add user to the root element\n    new XeSource() {\n      @Override\n      public Iterable\u003cDirective\u003e toXembly() {\n        return new Directives().add(\"status\").set(\"alive\");\n      }\n    },\n    new XeMillis(true), // replace \"millis\" attribute with take building time\n  ),\n)\n```\n\nThis is the output that will be produced:\n\n```xml\n\u003c?xml version='1.0'?\u003e\n\u003c?xsl-stylesheet href='/xsl/account.xsl'?\u003e\n\u003cpage\u003e\n  \u003cmillis\u003e5648\u003c/millis\u003e\n  \u003cuser\u003e\n    \u003cname\u003eJeff Lebowski\u003c/name\u003e\n    \u003cbalance\u003e123\u003c/balance\u003e\n  \u003c/user\u003e\n  \u003cstatus\u003ealive\u003c/status\u003e\n\u003c/page\u003e\n```\n\nTo avoid duplication of all this scaffolding in every page, you can create your\nown class, which will be used in every page, for example:\n\n```java\nResponse response = new RsXembly(\n  new XeFoo(user)\n)\n```\n\nThis is how this `XeFoo` class would look like:\n\n```java\npublic final class XeFoo extends XeWrap {\n  public XeFoo(final String stylesheet, final XeSource... sources) {\n    super(\n      new XeAppend(\n        \"page\",\n        new XeMillis(false),\n        new XeStylesheet(stylesheet),\n        new XeChain(sources),\n        new XeSource() {\n          @Override\n          public Iterable\u003cDirective\u003e toXembly() {\n            return new Directives().add(\"status\").set(\"alive\");\n          }\n        },\n        new XeMillis(true)\n      )\n    );\n  }\n}\n```\n\nYou will need this extra dependency in classpath:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.jcabi.incubator\u003c/groupId\u003e\n  \u003cartifactId\u003exembly\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\nMore about this mechanism in this blog post:\n[XML Data and XSL Views in Takes Framework][xsl].\n\n## Cookies\n\nHere is how we drop a cookie to the user:\n\n```java\npublic final class TkIndex implements Take {\n  @Override\n  public Response act(final Request req) {\n    return new RsWithCookie(\"auth\", \"John Doe\");\n  }\n}\n```\n\nAn HTTP response will contain this header, which will place\na `auth` cookie into the user's browser:\n\n```text\nHTTP/1.1 200 OK\nSet-Cookie: auth=\"John Doe\"\n```\n\nThis is how you read cookies from a request:\n\n```java\npublic final class TkIndex implements Take {\n  @Override\n  public Response act(final Request req) {\n    // the list may be empty\n    final Iterable\u003cString\u003e cookies = new RqCookies(req).cookie(\"my-cookie\");\n  }\n}\n```\n\n## GZIP Compression\n\nIf you want to compress all your responses with GZIP, wrap your take in\n`TkGzip`:\n\n```java\nnew TkGzip(take)\n```\n\nNow, each request that contains `Accept-Encoding` request header with `gzip`\ncompression method inside will receive a GZIP-compressed response. Also,\nyou can compress an individual response, using `RsGzip` decorator.\n\n## Content Negotiation\n\nSay, you want to return different content based on `Accept` header\nof the request (a.k.a.\n[content negotiation](http://en.wikipedia.org/wiki/Content_negotiation)):\n\n```java\npublic final class TkIndex implements Take {\n  @Override\n  public Response act(final Request req) {\n    return new RsFork(\n      req,\n      new FkTypes(\"text/*\", new RsText(\"it's a text\"))\n      new FkTypes(\"application/json\", new RsJSON(\"{\\\"a\\\":1}\"))\n      new FkTypes(\"image/png\", /* something else */)\n    );\n  }\n}\n```\n\n## SSL Configuration\n\nFirst of all, setup your keystore settings, for example\n\n```java\nfinal String file = this.getClass().getResource(\"/org/takes/http/keystore\").getFile();\nfinal String password = \"abc123\";\nSystem.setProperty(\"javax.net.ssl.keyStore\", file);\nSystem.setProperty(\"javax.net.ssl.keyStorePassword\", password);\nSystem.setProperty(\"javax.net.ssl.trustStore\", file);\nSystem.setProperty(\"javax.net.ssl.trustStorePassword\", password);\n```\n\nThen simple create exemplar of class\n[`FtSecure`](src/main/java/org/takes/http/FtSecure.java) with socket factory\n\n```java\nfinal ServerSocket skt = SSLServerSocketFactory.getDefault().createServerSocket(0);\nnew FtRemote(\n  new FtSecure(new BkBasic(new TkFixed(\"hello, world\")), skt),\n  skt,\n  true\n);\n```\n\n## Authentication\n\nHere is an example of login via\n[Facebook](https://developers.facebook.com/docs/reference/dialogs/oauth/):\n\n```java\nnew TkAuth(\n  new TkFork(\n    new FkRegex(\"/\", new TkHTML(\"hello, check \u003ca href='/acc'\u003eaccount\u003c/a\u003e\")),\n    new FkRegex(\"/acc\", new TkSecure(new TkAccount()))\n  ),\n  new PsChain(\n    new PsCookie(\n      new CcSafe(new CcHex(new CcXOR(new CcCompact(), \"secret-code\")))\n    ),\n    new PsByFlag(\n      new PsByFlag.Pair(\n        PsFacebook.class.getSimpleName(),\n        new PsFacebook(\"facebook-app-id\", \"facebook-secret\")\n      ),\n      new PsByFlag.Pair(\n        PsLogout.class.getSimpleName(),\n        new PsLogout()\n      )\n    )\n  )\n)\n```\n\nThen, you need to show a login link to the user, which he or she\ncan click and get to the Facebook OAuth authentication page. Here is how\nyou do this with XeResponse:\n\n```java\nnew RsXembly(\n  new XeStylesheet(\"/xsl/index.xsl\"),\n  new XeAppend(\n    \"page\",\n    new XeFacebookLink(req, \"facebook-app-id\"),\n    // ... other xembly sources\n  )\n)\n```\n\nThe link will be add to the XML page like this:\n\n```xml\n\u003cpage\u003e\n  \u003clinks\u003e\n    \u003clink rel=\"take:facebook\" href=\"https://www.facebook.com/dialog/oauth...\"/\u003e\n  \u003c/links\u003e\n\u003c/page\u003e\n```\n\nSimilar mechanism can be used for `PsGithub`,\n`PsGoogle`, `PsLinkedin`, `PsTwitter`, etc.\n\nThis is how you get currently logged in user:\n\n```java\npublic final class TkAccount implements Take {\n  @Override\n  public Response act(final Request req) {\n    final Identity identity = new RqAuth(req).identity();\n    if (this.identity.equals(Identity.ANONYMOUS)) {\n      // returns \"urn:facebook:1234567\" for a user logged in via Facebook\n      this.identity().urn();\n    }\n  }\n}\n```\n\nMore about it in this blog post:\n[How Cookie-Based Authentication Works in the Takes Framework][cookies].\n\n## Command Line Arguments\n\nThere is a convenient class `FtCLI` that parses command line arguments and\nstarts the necessary `Front` accordingly.\n\nThere are a few command line arguments that should be passed to\n`FtCLI` constructor:\n\n```text\n--port=1234         Tells the server to listen to TCP port 1234\n--lifetime=5000     The server will die in five seconds (useful for integration testing)\n--hit-refresh       Run the server in hit-refresh mode\n--daemon            Runs the server in Java daemon thread (for integration testing)\n--threads=30        Processes incoming HTTP requests in 30 parallel threads\n--max-latency=5000  Maximum latency in milliseconds per each request\n                    (longer requests will be interrupted)\n```\n\nFor example:\n\n```java\npublic final class App {\n  public static void main(final String... args) {\n    new FtCLI(\n      new TkFork(new FkRegex(\"/\", \"hello, world!\")),\n      args\n    ).start(Exit.NEVER);\n  }\n}\n```\n\nThen, run it like this:\n\n```bash\njava -cp take.jar App.class --port=8080 --hit-refresh\n```\n\nYou should see \"hello, world!\" at `http://localhost:8080`.\n\nParameter `--port` also accepts file name, instead of a number. If the file\nexists, `FtCLI` will try to read its content and use it as\nport number. If the file is absent, `FtCLI` will allocate a new random\nport number, use it to start a server, and save it to the file.\n\n## Logging\n\nThe framework sends all logs to SLF4J logging facility. If you want to see them,\nconfigure one of [SLF4J bindings](http://www.slf4j.org/manual.html).\n\nTo make a `Take` log, wrap it in the `TkSlf4j`, for example:\n\n```java\nnew TkSlf4j(\n  new TkFork(/* your code here */)\n)\n```\n\n## Directory Layout\n\nYou are free to use any build tool, but we recommend Maven.\nThis is how your project directory layout may/should look like:\n\n```text\nsrc/\n  main/\n    java/\n      foo/\n        App.java\n    scss/\n    coffeescript/\n    resources/\n      vtl/\n      xsl/\n      js/\n      css/\n      robot.txt\n      log4j.properties\n  test/\n    java/\n      foo/\n        AppTest.java\n    resources/\n      log4j.properties\npom.xml\nLICENSE.txt\n```\n\n## Optional dependencies\n\nIf you're using Maven and include Takes as a dependency in your own project,\nyou can choose which of the optional dependencies to include in your project.\nThe list of all of the optional dependencies can be seen in the\nTakes project `pom.xml`.\n\nFor example, to use the Facebook API shown above, simply add a dependency to\nthe `restfb` API in your project:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.restfb\u003c/groupId\u003e\n  \u003cartifactId\u003erestfb\u003c/artifactId\u003e\n  \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nFor Gradle, you should add the dependencies as usual:\n\n```groovy\ndependencies {\n  ...\n  runtime group: 'com.restfb', name: 'restfb', version: '1.15.0'\n}\n```\n\n## Backward compatibility\n\nVersion 2.0 is not backward compatible with previous versions.\n\n## Version pattern for RESTful API\n\nThe URL should NOT contain the versions, but the type requested.\n\nFor example:\n\n```text\n===\u003e\nGET /architect/256 HTTP/1.1\nAccept: application/org.takes.architect-v1+xml\n\u003c===\nHTTP/1.1 200 OK\nContent-Type: application/org.takes.architect-v1+xml\n\u003carchitect\u003e\n  \u003cname\u003eYegor Bugayenko\u003c/name\u003e\n\u003c/architect\u003e\n```\n\nThen clients aware of newer version of this service can call:\n\n```text\n===\u003e\nGET /architect/256 HTTP/1.1\nAccept: application/org.takes.architect-v2+xml\n\u003c===\nHTTP/1.1 200 OK\nContent-Type: application/org.takes.architect-v2+xml\n\n\u003carchitect\u003e\n  \u003cfirstName\u003eYegor\u003c/firstName\u003e\n  \u003clastName\u003eBugayenko\u003c/lastName\u003e\n  \u003csalutation\u003eMr.\u003c/salutation\u003e\n\u003c/architect\u003e\n```\n\n[This article][rest-types]\nexplains why it's done this way.\n\n## How to contribute\n\nFork repository, make changes, send us a pull request. We will review\nyour changes and apply them to the `master` branch shortly, provided\nthey don't violate our quality standards. To avoid frustration, before\nsending us your pull request please run full Maven build:\n\n```bash\nmvn clean install -Pqulice\n```\n\nTo avoid build errors use maven 3.2+.\n\nPay attention that our `pom.xml` inherits a lot of configuration\nfrom [jcabi-parent](http://parent.jcabi.com).\n[This article](http://www.yegor256.com/2015/02/05/jcabi-parent-maven-pom.html)\nexplains why it's done this way.\n\n[jar]: https://repo1.maven.org/maven2/org/takes/takes/1.24.6/takes-1.24.6-jar-with-dependencies.jar\n[oop]: http://www.yegor256.com/2014/11/20/seven-virtues-of-good-object.html\n[immutable]: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html\n[null]: http://www.yegor256.com/2014/05/13/why-null-is-bad.html\n[utility]: http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes.html\n[casting]: http://www.yegor256.com/2015/04/02/class-casting-is-anti-pattern.html\n[webcast]: https://www.youtube.com/watch?v=-Y4XS7ZtQ2g\n[rultor-code]: https://github.com/yegor256/rultor/tree/master/src/test/java/com/rultor/web\n[xsl]:https://www.yegor256.com/2015/06/25/xml-data-xsl-views-takes-framework.html\n[cookies]: http://www.yegor256.com/2015/05/18/cookie-based-authentication.html\n[rest-types]: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Ftakes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyegor256%2Ftakes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Ftakes/lists"}