Skip to content

Commit

Permalink
[톰캣 구현하기 - 3, 4단계] 헙크(정현승) 미션 제출합니다. (#421)
Browse files Browse the repository at this point in the history
* refactor: 클래스 네이밍 수정

* refactor: Controller 구조 도입

* feat: Thread 학습테스트 작성

* feat: 동시성 확장

* test: IndexControllerTest 테스트 케이스 작성

* test: LoginControllerTest 테스트 케이스 작성

* test: RegisterControllerTest 테스트 케이스 작성

* test: UnAuthorizedControllerTest 테스트 케이스 작성

* test: RootControllerTest 테스트 케이스 작성

* refactor: byte로 값을 가져오록 수정

* refactor: 피드백 반영

* refactor: Controller 인터페이스 수정

* refactor: Controller의 canHandle 제거 및 RequestMapping 리팩터링

* refactor: RequestBody 정팩메 반환 타입 수정 및 기본 자원 반환 로직 수정

* fix: 테스트 케이스 수정
  • Loading branch information
HubCreator authored Sep 14, 2023
1 parent aea21d0 commit a666458
Show file tree
Hide file tree
Showing 37 changed files with 996 additions and 247 deletions.
8 changes: 5 additions & 3 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ server:
enabled: true
min-response-size: 10
tomcat:
accept-count: 1
max-connections: 1
accept-count: 4 # 작업큐의 사이즈
max-connections: 2 # 수립가능한 connection의 총 개수
threads:
max: 2
max: 4 # 생성할 수 있는 thread의 총 개수
# min-spare: 10 # 항상 활성화 되어있는(idle) thread의 개수 (코어 스레드)

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
3 changes: 2 additions & 1 deletion study/src/test/java/thread/stage0/ThreadTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ void testExtendedThread() throws InterruptedException {
@Test
void testRunnableThread() throws InterruptedException {
// 하단의 RunnableThread 클래스를 Runnable 인터페이스의 구현체로 만들고 Thread 클래스를 활용하여 스레드 객체를 생성한다.
Thread thread = new Thread(new RunnableThread("hello thread"));
RunnableThread runnableThread = new RunnableThread("hello thread");
Thread thread = new Thread(runnableThread);

// 생성한 thread 객체를 시작한다.
thread.start();
Expand Down
15 changes: 10 additions & 5 deletions tomcat/src/main/java/org/apache/catalina/connector/Connector.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
package org.apache.catalina.connector;

import org.apache.coyote.http11.Handler;
import org.apache.coyote.http11.Http11Processor;
import org.apache.coyote.http11.RequestMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

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 MAX_THREAD_COUNT = 250;

private final ThreadPoolExecutor executor;
private final ServerSocket serverSocket;
private boolean stopped;

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

public Connector(final int port, final int acceptCount) {
public Connector(final int port, final int acceptCount, final int maxThreads) {
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxThreads);
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
}
Expand Down Expand Up @@ -67,8 +72,8 @@ private void process(final Socket connection) {
if (connection == null) {
return;
}
var processor = new Http11Processor(connection, new Handler());
new Thread(processor).start();
var processor = new Http11Processor(connection, new RequestMapping());
executor.submit(processor);
}

public void stop() {
Expand Down
114 changes: 0 additions & 114 deletions tomcat/src/main/java/org/apache/coyote/http11/Handler.java

This file was deleted.

21 changes: 13 additions & 8 deletions tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import nextstep.jwp.exception.UncheckedServletException;
import org.apache.coyote.Processor;
import org.apache.coyote.http11.request.Request;
import org.apache.coyote.http11.response.Response;
import org.apache.coyote.http11.controller.Controller;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,11 +17,11 @@ public class Http11Processor implements Runnable, Processor {
private static final Logger log = LoggerFactory.getLogger(Http11Processor.class);

private final Socket connection;
private final Handler handler;
private final RequestMapping requestMapping;

public Http11Processor(final Socket connection, final Handler handler) {
public Http11Processor(final Socket connection, final RequestMapping requestMapping) {
this.connection = connection;
this.handler = handler;
this.requestMapping = requestMapping;
}

@Override
Expand All @@ -34,14 +35,18 @@ public void process(final Socket connection) {
try (final var outputStream = connection.getOutputStream();
final var bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {

final Request request = Request.from(bufferedReader);
final Response response = handler.handle(request);
final HttpRequest httpRequest = HttpRequest.from(bufferedReader);
final Controller controller = requestMapping.getController(httpRequest);
final HttpResponse response = HttpResponse.create();
controller.service(httpRequest, response);
final String result = response.toString();

outputStream.write(result.getBytes());
outputStream.flush();
} catch (IOException | UncheckedServletException e) {
log.error(e.getMessage(), e);
log.error("", e);
} catch (Exception e) {
log.error("예상치 못한 오류 : ", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public enum HttpMethod {
GET,
POST
POST,
DELETE,
}
35 changes: 35 additions & 0 deletions tomcat/src/main/java/org/apache/coyote/http11/RequestMapping.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.apache.coyote.http11;

import org.apache.coyote.http11.controller.Controller;
import org.apache.coyote.http11.controller.DefaultController;
import org.apache.coyote.http11.controller.IndexController;
import org.apache.coyote.http11.controller.LoginController;
import org.apache.coyote.http11.controller.RegisterController;
import org.apache.coyote.http11.controller.RootController;
import org.apache.coyote.http11.controller.UnAuthorizedController;
import org.apache.coyote.http11.controller.Uri;
import org.apache.coyote.http11.request.HttpRequest;

import java.util.EnumMap;
import java.util.Map;


public class RequestMapping {
private final Map<Uri, Controller> controllerMap;

public RequestMapping() {
this.controllerMap = new EnumMap<>(Uri.class);
controllerMap.put(Uri.ROOT, new RootController());
controllerMap.put(Uri.INDEX, new IndexController());
controllerMap.put(Uri.LOGIN, new LoginController());
controllerMap.put(Uri.UNAUTHORIZED, new UnAuthorizedController());
controllerMap.put(Uri.REGISTER, new RegisterController());
controllerMap.put(Uri.DEFAULT, new DefaultController());
}

public Controller getController(final HttpRequest httpRequest) {
final String path = httpRequest.getRequestLine().getPath();
final Uri uri = Uri.from(path);
return controllerMap.get(uri);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.apache.coyote.http11.controller;

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

public abstract class AbstractController implements Controller {

@Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
final HttpMethod httpMethod = request.getRequestLine().getHttpMethod();
if (httpMethod == HttpMethod.GET) {
doGet(request, response);
return;
}
if (httpMethod == HttpMethod.POST) {
doPost(request, response);
return;
}
throw new UnsupportedOperationException();
}

protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
throw new UnsupportedOperationException();
}

protected void doPost(HttpRequest request, HttpResponse response) throws Exception {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.apache.coyote.http11.controller;

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

public interface Controller {
void service(HttpRequest request, HttpResponse response) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.apache.coyote.http11.controller;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseBody;
import org.apache.coyote.http11.response.StaticResource;

public class DefaultController extends AbstractController {

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
final String path = request.getRequestLine().getPath();
final StaticResource staticResource = StaticResource.from(path);
final ResponseBody responseBody = ResponseBody.from(staticResource);

response.setHttpStatus(HttpStatus.OK);
response.setResponseBody(responseBody);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.apache.coyote.http11.controller;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.ResponseBody;
import org.apache.coyote.http11.response.StaticResource;

public class IndexController extends AbstractController {

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
final StaticResource staticResource = StaticResource.from(Uri.INDEX.getFullPath());
final ResponseBody responseBody = ResponseBody.from(staticResource);
response.setHttpStatus(HttpStatus.OK);
response.setResponseBody(responseBody);
response.setResponseHeaders(responseBody);
}
}
Loading

0 comments on commit a666458

Please sign in to comment.