Skip to content

[톰캣 구현하기 - 3, 4단계] 포이(김보준) 미션 제출합니다. #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4f9f96c
refactor: controller 내부에서 메서드의 분기를 선택하도록 변경
poi1649 Sep 7, 2023
b770054
test: thread 학습 테스트 해결
poi1649 Sep 7, 2023
c4be812
feat: 스레드 풀 적용
poi1649 Sep 7, 2023
30c90ae
fix: 쓰레드풀에서 bounded한 큐를 가지도록 변경
poi1649 Sep 7, 2023
614abcb
refactor: Session의 아이디 전략을 SessionManager로 이관
poi1649 Sep 7, 2023
c343e27
refactor: 사용되지 않는 임포트 제거
poi1649 Sep 7, 2023
23a5b47
refactor: http request, response의 패키지 구조 변경
poi1649 Sep 10, 2023
3c41804
style: 상수가 아닌 변수의 변수명 수정
poi1649 Sep 10, 2023
8dc5d7d
refactor: ThreadPool을 Executors 를 사용하여 생성하도록 변경
poi1649 Sep 11, 2023
1b757c2
refactor: request에서 헤더를 가져갈 수 있도록 변경
poi1649 Sep 11, 2023
c6446dd
refactor: 사용하지 않는 필드 제거
poi1649 Sep 11, 2023
b11fec8
refactor: InterruptedException 발생 시 쓰레드 인터럽트 실행하도록 변경
poi1649 Sep 11, 2023
6ff516f
style: 변수명 변경
poi1649 Sep 11, 2023
70e16fb
chore: 사용하지 않는 메서드 제거 일부 패키지명 변경
poi1649 Sep 12, 2023
02056ad
refactor: request안에서 path 를 확인하도록 변경
poi1649 Sep 12, 2023
b0ac39e
refactor: controller의 중복코드 제거
poi1649 Sep 12, 2023
e7c2995
refactor: Servlet의 필드를 외부에서 주입하도록 변경
poi1649 Sep 12, 2023
18eb843
test: 테스트 주입 변수 수정
poi1649 Sep 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ handlebars:

server:
tomcat:
accept-count: 1
max-connections: 1
accept-count: 0
max-connections: 2
threads:
max: 2
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage0/SynchronizationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private static final class SynchronizedMethods {

private int sum = 0;

public void calculate() {
public synchronized void calculate() {
setSum(getSum() + 1);
}

Expand Down
6 changes: 3 additions & 3 deletions study/src/test/java/thread/stage0/ThreadPoolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void testNewFixedThreadPool() {
executor.submit(logWithSleep("hello fixed thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedQueueSize = 0;
final int expectedPoolSize = 2;
final int expectedQueueSize = 1;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size());
Expand All @@ -46,7 +46,7 @@ void testNewCachedThreadPool() {
executor.submit(logWithSleep("hello cached thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedPoolSize = 3;
final int expectedQueueSize = 0;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
Expand Down
1 change: 1 addition & 0 deletions study/src/test/java/thread/stage1/ConcurrencyTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package thread.stage1;

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down
42 changes: 41 additions & 1 deletion tomcat/src/main/java/nextstep/Application.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
package nextstep;

import java.util.List;
import java.util.Map;
import nextstep.jwp.controller.Controller;
import nextstep.jwp.controller.HomeController;
import nextstep.jwp.controller.LoginController;
import nextstep.jwp.controller.RegisterController;
import nextstep.servlet.DispatcherServletManager;
import nextstep.servlet.StaticResourceResolver;
import nextstep.servlet.interceptor.Interceptor;
import nextstep.servlet.interceptor.SessionInterceptor;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.http11.message.HttpMethod;
import org.apache.coyote.http11.message.request.RequestLine;

public class Application {

public static void main(String[] args) {
final var tomcat = new Tomcat(new DispatcherServletManager());
final var tomcat = configTomcat();
tomcat.start();
}

private static Tomcat configTomcat() {
final DispatcherServletManager servletManger = configServletManager();
return new Tomcat(servletManger);
}

private static DispatcherServletManager configServletManager() {
final Map<List<RequestLine>, Interceptor> interceptors = Map.of(
List.of(
new RequestLine(HttpMethod.GET, "/login"),
new RequestLine(HttpMethod.POST, "/login")
)
, new SessionInterceptor()
);

final List<Controller> controllers = List.of(
new HomeController(),
new LoginController(),
new RegisterController()
);

final StaticResourceResolver staticResourceResolver = new StaticResourceResolver();

return new DispatcherServletManager(
interceptors,
controllers,
staticResourceResolver
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nextstep.jwp.controller;

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

public abstract class AbstractController implements Controller {

@Override
public ResponseEntity handle(HttpRequest request) {
if (request.getMethod() == HttpMethod.GET) {
return doGet();
}
return doPost(request);
}

abstract ResponseEntity doGet();

abstract ResponseEntity doPost(HttpRequest request);
}
5 changes: 2 additions & 3 deletions tomcat/src/main/java/nextstep/jwp/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package nextstep.jwp.controller;

import java.io.IOException;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.message.request.HttpRequest;

public interface Controller {

boolean canHandle(HttpRequest request);

ResponseEntity handle(HttpRequest request) throws IOException;
ResponseEntity handle(HttpRequest request);
}
24 changes: 24 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/controller/HomeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package nextstep.jwp.controller;

import static nextstep.servlet.StaticResourceResolver.HOME_PAGE;

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

public class HomeController extends AbstractController {

@Override
public boolean canHandle(HttpRequest request) {
return request.isPathMatch("/") || request.isPathMatch("/index.html");
}

@Override
ResponseEntity doGet() {
return ResponseEntity.forward(HttpStatusCode.OK, HOME_PAGE);
}

@Override
ResponseEntity doPost(HttpRequest request) {
throw new IllegalArgumentException("지원하지 않는 HTTP Method 입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
package nextstep.jwp.controller.rest;
package nextstep.jwp.controller;

import static nextstep.jwp.controller.StaticResourceController.HOME_PAGE;
import static nextstep.jwp.controller.StaticResourceController.UNAUTHORIZED_PAGE;
import static nextstep.servlet.StaticResourceResolver.HOME_PAGE;
import static nextstep.servlet.StaticResourceResolver.LOGIN_PAGE;
import static nextstep.servlet.StaticResourceResolver.UNAUTHORIZED_PAGE;

import java.util.NoSuchElementException;
import nextstep.jwp.controller.ResponseEntity;
import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.HttpHeaders;
import org.apache.coyote.http11.HttpMethod;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatusCode;
import org.apache.coyote.http11.message.HttpHeaders;
import org.apache.coyote.http11.message.HttpStatusCode;
import org.apache.coyote.http11.message.request.HttpRequest;

public class LoginController implements RestController {
public class LoginController extends AbstractController {

@Override
public boolean canHandle(HttpRequest request) {
return request.getPath().equals("/login") && request.getMethod() == HttpMethod.POST;
return request.isPathMatch("/login");
}

@Override
public ResponseEntity handle(HttpRequest request) {
ResponseEntity doGet() {
return ResponseEntity.forward(HttpStatusCode.OK, LOGIN_PAGE);
}

@Override
ResponseEntity doPost(HttpRequest request) {
try {
final User user = InMemoryUserRepository.findByAccount(request.getJsonProperty("account"))
.orElseThrow(() -> new NoSuchElementException("존재하지 않는 계정입니다."));
Expand All @@ -30,7 +34,7 @@ public ResponseEntity handle(HttpRequest request) {
session.setAttribute("user", user);
headers.setCookie("JSESSIONID", session.getId());
headers.put(HttpHeaders.LOCATION, HOME_PAGE);
return new ResponseEntity(HttpStatusCode.FOUND, headers, "");
return new ResponseEntity(HttpStatusCode.FOUND, headers, "", true);
}
return ResponseEntity.found(UNAUTHORIZED_PAGE);
} catch (NoSuchElementException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package nextstep.jwp.controller.rest;
package nextstep.jwp.controller;

import static nextstep.jwp.controller.StaticResourceController.HOME_PAGE;
import static nextstep.jwp.controller.StaticResourceController.REGISTER_PAGE;
import static nextstep.servlet.StaticResourceResolver.HOME_PAGE;
import static nextstep.servlet.StaticResourceResolver.REGISTER_PAGE;

import nextstep.jwp.controller.ResponseEntity;
import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.HttpMethod;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.message.HttpStatusCode;
import org.apache.coyote.http11.message.request.HttpRequest;

public class RegisterController implements RestController {
public class RegisterController extends AbstractController {

@Override
public boolean canHandle(HttpRequest request) {
return request.getPath().equals("/register") && request.getMethod() == HttpMethod.POST;
return request.isPathMatch("/register");
}

@Override
public ResponseEntity handle(HttpRequest request) {
ResponseEntity doGet() {
return ResponseEntity.forward(HttpStatusCode.OK, REGISTER_PAGE);
}

@Override
ResponseEntity doPost(HttpRequest request) {
final var user = new User(
request.getJsonProperty("account"),
request.getJsonProperty("password"),
Expand Down
19 changes: 13 additions & 6 deletions tomcat/src/main/java/nextstep/jwp/controller/ResponseEntity.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
package nextstep.jwp.controller;

import java.util.Map;
import org.apache.coyote.http11.HttpHeaders;
import org.apache.coyote.http11.HttpStatusCode;
import org.apache.coyote.http11.message.HttpHeaders;
import org.apache.coyote.http11.message.HttpStatusCode;

public class ResponseEntity {

private final HttpStatusCode statusCode;
private final HttpHeaders headers;
private final String body;
private final boolean isRestResponse;

public ResponseEntity(HttpStatusCode statusCode, HttpHeaders headers, String body) {
public ResponseEntity(HttpStatusCode statusCode, HttpHeaders headers, String body, boolean isRestResponse) {
this.statusCode = statusCode;
this.headers = headers;
this.body = body;
this.isRestResponse = isRestResponse;
}

public static ResponseEntity ok(String body) {
return new ResponseEntity(HttpStatusCode.OK, HttpHeaders.defaultHeaders(), body);
public static ResponseEntity forward(HttpStatusCode statusCode, String path) {
final var headers = HttpHeaders.defaultHeaders();
return new ResponseEntity(statusCode, headers, path, false);
}

public static ResponseEntity found(String location) {
final var headers = HttpHeaders.defaultHeaders();
headers.put(HttpHeaders.LOCATION, location);
return new ResponseEntity(HttpStatusCode.FOUND, headers, "");
return new ResponseEntity(HttpStatusCode.FOUND, headers, "", true);
}

public String getBody() {
Expand All @@ -37,4 +40,8 @@ public HttpStatusCode getStatusCode() {
public Map<String, String> getHeaders() {
return headers.getHeaders();
}

public boolean isRestResponse() {
return isRestResponse;
}
}

This file was deleted.

12 changes: 7 additions & 5 deletions tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,28 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import nextstep.jwp.model.User;

public class InMemoryUserRepository {

private static final Map<String, User> database = new ConcurrentHashMap<>();
private static long sequence = 1L;
private static final AtomicLong sequence = new AtomicLong(1);

static {
final var user = new User(sequence++, "gugu", "password", "[email protected]");
final var user = new User(sequence.getAndIncrement(), "gugu", "password", "[email protected]");
database.put(user.getAccount(), user);
}

private InMemoryUserRepository() {
}

public static void save(User user) {
final var newUser = new User(sequence++, user.getAccount(), user.getPassword(), user.getEmail());
final var newUser = new User(sequence.getAndIncrement(), user.getAccount(), user.getPassword(), user.getEmail());
database.put(user.getAccount(), newUser);
}

public static Optional<User> findByAccount(String account) {
return Optional.ofNullable(database.get(account));
}

private InMemoryUserRepository() {}
}
Loading