Skip to content

Commit

Permalink
[톰캣 구현하기 - 4단계] 깃짱(조은기) 미션 제출합니다. (#468)
Browse files Browse the repository at this point in the history
* feat: Thread Pool 적용

* feat: 동시성 컬렉션 사용

* refactor: 동시성 컬렉션 적용

* refactor: Controller 메서드 시그니처 변경

* feat: 쓰레드 풀 사용 후 shutdown 설정

* fix: NPE 해결

* refactor: 반환 타입 Optional로 변경

* refactor: RequestMapping 객체 static 제거

* feat: Thread stage2 테스트 통과

* fix: Cookie에 jsession id string을 그대로 넣도록 수정

* fix: 쿠키 파싱 문제 해결
  • Loading branch information
gitchannn authored Sep 11, 2023
1 parent e93b1b7 commit 6ed3307
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 55 deletions.
10 changes: 5 additions & 5 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ handlebars:
suffix: .html

server:
# tomcat:
# accept-count: 1
# max-connections: 1
# threads:
# max: 2
tomcat:
accept-count: 10
max-connections: 2
threads:
max: 2
compression:
enabled: true
min-response-size: 10 # 기본 설정은 2KB
Expand Down
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage2/AppTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class AppTest {
@Test
void test() throws Exception {
final var NUMBER_OF_THREAD = 10;
var threads = new Thread[NUMBER_OF_THREAD];
Thread[] threads = new Thread[NUMBER_OF_THREAD];

for (int i = 0; i < NUMBER_OF_THREAD; i++) {
threads[i] = new Thread(() -> incrementIfOk(TestHttpUtils.send("/test")));
Expand Down
23 changes: 21 additions & 2 deletions tomcat/src/main/java/org/apache/catalina/connector/Connector.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,44 @@
import java.io.UncheckedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Connector implements Runnable {

private static final Logger log = LoggerFactory.getLogger(Connector.class);

private static final int DEFAULT_PORT = 8080;
private static final int DEFAULT_ACCEPT_COUNT = 100;
private static final int DEFAULT_MAX_THREAD = 250;

private final ServerSocket serverSocket;
private boolean stopped;
private ExecutorService executorService;

public Connector() {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT);
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_MAX_THREAD);
}

public Connector(final int port, final int acceptCount) {
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
}

public Connector(final int port, final int acceptCount, final int maxThreads) {
this.serverSocket = createServerSocket(port, acceptCount);
this.executorService = new ThreadPoolExecutor(
maxThreads, // 쓰레드풀의 최대 크기
maxThreads, // 쓰레드풀의 핵심 크기
0L, // 쓰레드의 비활성화 시간
TimeUnit.MILLISECONDS, // 비활성화 시간의 단위
new ArrayBlockingQueue<>(acceptCount) // 작업 큐의 크기
);
this.stopped = false;
}

private ServerSocket createServerSocket(final int port, final int acceptCount) {
try {
final int checkedPort = checkPort(port);
Expand Down Expand Up @@ -67,13 +85,14 @@ private void process(final Socket connection) {
return;
}
var processor = new Http11Processor(connection);
new Thread(processor).start();
executorService.execute(processor);
}

public void stop() {
stopped = true;
try {
serverSocket.close();
executorService.shutdown();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.apache.coyote.http11.controller.RequestMapping;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.ResponseEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -37,10 +36,11 @@ public void process(final Socket connection) {
final var outputStream = connection.getOutputStream()) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
HttpRequest httpRequest = HttpRequest.from(bufferedReader);
HttpResponse httpResponse = new HttpResponse();

Controller controller = controllers.getController(httpRequest);
ResponseEntity responseEntity = controller.service(httpRequest);
String response = HttpResponse.from(responseEntity).getResponse();
controller.service(httpRequest, httpResponse);
String response = httpResponse.getResponse();

outputStream.write(response.getBytes());
outputStream.flush();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.apache.coyote.http11.controller;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.ResponseEntity;
import org.apache.coyote.http11.response.HttpResponse;

import java.io.IOException;

public interface Controller {

ResponseEntity service(HttpRequest request) throws IOException;
void service(HttpRequest request, HttpResponse response) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package org.apache.coyote.http11.controller;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.ContentType;
import org.apache.coyote.http11.response.HttpResponseBody;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseEntity;
import org.apache.coyote.http11.response.*;

import java.io.IOException;

public class IndexPageController implements Controller {

@Override
public ResponseEntity service(HttpRequest request) {
public void service(HttpRequest request, HttpResponse response) throws IOException {
final var responseBody = "Hello world!";
ResponseEntity responseEntity = generateResponseEntity(responseBody);
response.modifyResponse(responseEntity);
}

private static ResponseEntity generateResponseEntity(String responseBody) {
return ResponseEntity
.builder()
.httpStatus(HttpStatus.OK)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import nextstep.jwp.model.User;
import org.apache.coyote.http11.request.*;
import org.apache.coyote.http11.response.ContentType;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseEntity;
import org.apache.coyote.http11.session.HttpCookie;
Expand All @@ -13,6 +14,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.Optional;

Expand All @@ -26,24 +28,29 @@ public class LoginController implements Controller {
private final SessionManager sessionManager = new SessionManager();

@Override
public ResponseEntity service(HttpRequest request) {
public void service(HttpRequest request, HttpResponse response) throws IOException {
response.modifyResponse(generateResponseEntity(request));
}

private ResponseEntity generateResponseEntity(HttpRequest request) {
HttpRequestStartLine httpRequestStartLine = request.getHttpRequestStartLine();
HttpRequestHeader httpRequestHeader = request.getHttpRequestHeader();
HttpRequestBody httpRequestBody = request.getHttpRequestBody();

HttpMethod httpMethod = httpRequestStartLine.getHttpMethod();

String account = httpRequestBody.find("account");

if (httpMethod == HttpMethod.GET && account == null) {
if (httpMethod == HttpMethod.GET) {
HttpCookie httpCookie = httpRequestHeader.getCookie();
Session session = sessionManager.findSession(httpCookie.findJSessionId());
if (session != null) {
return ResponseEntity.builder()
.httpStatus(HttpStatus.FOUND)
.contentType(ContentType.HTML)
.location(INDEX_PAGE_URI)
.build();
Optional<String> jSessionId = httpCookie.findJSessionId();
if (jSessionId.isPresent()) {
Optional<Session> session = sessionManager.findSession(jSessionId.get());
if (session.isPresent()) {
return ResponseEntity.builder()
.httpStatus(HttpStatus.FOUND)
.contentType(ContentType.HTML)
.location(INDEX_PAGE_URI)
.build();
}
}

return ResponseEntity.builder()
Expand All @@ -53,6 +60,7 @@ public ResponseEntity service(HttpRequest request) {
.build();
}

String account = httpRequestBody.find("account");
String password = httpRequestBody.find("password");

User findAccount = findAccount(account);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@
import org.apache.coyote.http11.request.HttpRequestBody;
import org.apache.coyote.http11.request.HttpRequestStartLine;
import org.apache.coyote.http11.response.ContentType;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class RegisterController implements Controller {

private static final Logger log = LoggerFactory.getLogger(RegisterController.class);
private static final String REGISTER_PAGE_URI = "/register.html";
private static final String INDEX_PAGE_URI = "/index.html";

@Override
public ResponseEntity service(HttpRequest request) {
public void service(HttpRequest request, HttpResponse response) throws IOException {
response.modifyResponse(generateResponseEntity(request));
}

private static ResponseEntity generateResponseEntity(HttpRequest request) {
HttpRequestStartLine httpRequestStartLine = request.getHttpRequestStartLine();
HttpRequestBody httpRequestBody = request.getHttpRequestBody();
HttpMethod httpMethod = httpRequestStartLine.getHttpMethod();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@

import org.apache.coyote.http11.request.HttpRequest;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class RequestMapping {

private static final Map<String, Controller> controllers = new HashMap<>();
private final Map<String, Controller> controllers = new ConcurrentHashMap<>();

private RequestMapping() {
registerController();
}

public static RequestMapping init() {
registerController();
return new RequestMapping();
}

private static void registerController() {
private void registerController() {
controllers.put("/", new IndexPageController());
controllers.put("/login", new LoginController());
controllers.put("/register", new RegisterController());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.apache.coyote.http11.controller;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.ContentType;
import org.apache.coyote.http11.response.HttpResponseBody;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseEntity;
import org.apache.coyote.http11.response.*;

import java.io.File;
import java.io.IOException;
Expand All @@ -13,8 +10,7 @@

public class StaticResourceController implements Controller {

@Override
public ResponseEntity service(HttpRequest request) throws IOException {
private ResponseEntity generateResponseEntity(HttpRequest request) throws IOException {
String requestURI = request.getHttpRequestStartLine().getPath();

URL resource = getClass()
Expand All @@ -29,4 +25,9 @@ public ResponseEntity service(HttpRequest request) throws IOException {
.responseBody(HttpResponseBody.from(responseBody))
.build();
}

@Override
public void service(HttpRequest request, HttpResponse response) throws IOException {
response.modifyResponse(generateResponseEntity(request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ public class HttpResponse {
private static final String BLANK_LINE = "";
private static final String BLANK_SPACE = " ";

private final HttpResponseStatusLine httpResponseStatusLine;
private final HttpResponseHeaders httpResponseHeaders;
private final HttpResponseBody httpResponseBody;
private HttpResponseStatusLine httpResponseStatusLine;
private HttpResponseHeaders httpResponseHeaders;
private HttpResponseBody httpResponseBody;

public HttpResponse() {
this(null, null, null);
}

@Builder
public HttpResponse(HttpResponseStatusLine httpResponseStatusLine, HttpResponseHeaders httpResponseHeaders, HttpResponseBody httpResponseBody) {
Expand All @@ -30,6 +34,12 @@ public HttpResponse(HttpResponseStatusLine httpResponseStatusLine, HttpResponseH
this.httpResponseBody = httpResponseBody;
}

public void modifyResponse(ResponseEntity responseEntity) throws IOException {
this.httpResponseStatusLine = HttpResponseStatusLine.of(HTTP11, responseEntity.getHttpStatus());
this.httpResponseHeaders = generateHttpResponseHeaders(responseEntity, getOrGenerateResponseBody(responseEntity));
this.httpResponseBody = getOrGenerateResponseBody(responseEntity);
}

public static HttpResponse from(ResponseEntity responseEntity) throws IOException {
HttpStatus httpStatus = responseEntity.getHttpStatus();
HttpResponseBody responseBody = getOrGenerateResponseBody(responseEntity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

@Getter
public class HttpResponseHeaders {
Expand Down Expand Up @@ -44,11 +45,11 @@ public HttpResponseHeaders setCookie(HttpCookie httpCookie) {
if (httpCookie == null) {
return this;
}
String jSessionId = httpCookie.findJSessionId();
if (jSessionId == null) {
Optional<String> jSessionId = httpCookie.findJSessionId();
if (jSessionId.isEmpty()) {
return this;
}
setHeader("Set-Cookie", String.format("JSESSIONID=%s", jSessionId));
setHeader("Set-Cookie", String.format("JSESSIONID=%s", jSessionId.get()));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;
Expand All @@ -18,7 +19,7 @@ public class HttpCookie {
private final Map<String, String> cookies = new HashMap<>();

public HttpCookie(Map<String, String> cookies) {
cookies.putAll(cookies);
this.cookies.putAll(cookies);
}

private HttpCookie() {
Expand All @@ -44,11 +45,11 @@ public void put(String key, String value) {
cookies.put(key, value);
}

public String find(String key) {
return cookies.get(key);
public Optional<String> find(String key) {
return Optional.ofNullable(cookies.get(key));
}

public String findJSessionId() {
return cookies.get("JSESSIONID");
public Optional<String> findJSessionId() {
return find("JSESSIONID");
}
}
Loading

0 comments on commit 6ed3307

Please sign in to comment.