Skip to content
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

[톰캣 구현하기 3, 4단계] 오도(문민혁) 미션 제출합니다. #452

Merged
merged 10 commits into from
Sep 14, 2023
2 changes: 1 addition & 1 deletion study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ handlebars:
server:
tomcat:
accept-count: 1
max-connections: 1
max-connections: 10
threads:
max: 2
25 changes: 10 additions & 15 deletions study/src/test/java/thread/stage0/SynchronizationTest.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
package thread.stage0;

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

/**
* 다중 스레드 환경에서 두 개 이상의 스레드가 변경 가능한(mutable) 공유 데이터를 동시에 업데이트하면 경쟁 조건(race condition)이 발생한다.
* 자바는 공유 데이터에 대한 스레드 접근을 동기화(synchronization)하여 경쟁 조건을 방지한다.
* 동기화된 블록은 하나의 스레드만 접근하여 실행할 수 있다.
*
* Synchronization
* https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
* 다중 스레드 환경에서 두 개 이상의 스레드가 변경 가능한(mutable) 공유 데이터를 동시에 업데이트하면 경쟁 조건(race condition)이 발생한다. 자바는 공유 데이터에 대한 스레드 접근을
* 동기화(synchronization)하여 경쟁 조건을 방지한다. 동기화된 블록은 하나의 스레드만 접근하여 실행할 수 있다.
* <p>
* Synchronization https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
*/
class SynchronizationTest {

/**
* 테스트가 성공하도록 SynchronizedMethods 클래스에 동기화를 적용해보자.
* synchronized 키워드에 대하여 찾아보고 적용하면 된다.
*
* Guide to the Synchronized Keyword in Java
* https://www.baeldung.com/java-synchronized
* 테스트가 성공하도록 SynchronizedMethods 클래스에 동기화를 적용해보자. synchronized 키워드에 대하여 찾아보고 적용하면 된다.
* <p>
* Guide to the Synchronized Keyword in Java https://www.baeldung.com/java-synchronized
*/
@Test
void testSynchronized() throws InterruptedException {
Expand All @@ -41,7 +36,7 @@ private static final class SynchronizedMethods {

private int sum = 0;

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

Expand Down
28 changes: 12 additions & 16 deletions study/src/test/java/thread/stage0/ThreadPoolsTest.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package thread.stage0;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 스레드 풀은 무엇이고 어떻게 동작할까?
* 테스트를 통과시키고 왜 해당 결과가 나왔는지 생각해보자.
*
* Thread Pools
* https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
*
* Introduction to Thread Pools in Java
* https://www.baeldung.com/thread-pool-java-and-guava
* 스레드 풀은 무엇이고 어떻게 동작할까? 테스트를 통과시키고 왜 해당 결과가 나왔는지 생각해보자.
* <p>
* Thread Pools https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
* <p>
* Introduction to Thread Pools in Java https://www.baeldung.com/thread-pool-java-and-guava
*/
class ThreadPoolsTest {

Expand All @@ -31,8 +27,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 +42,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
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package org.apache.coyote.http11;
package nextstep.jwp.common;

import static org.apache.coyote.http11.HttpStatus.BAD_REQUEST;
import static nextstep.jwp.exception.FormDataExceptionType.INVALID_FORM;

import java.util.HashMap;
import java.util.Map;
import nextstep.jwp.exception.FormDataException;

public class FormData {

Expand Down Expand Up @@ -32,6 +33,6 @@ public String get(String key) {
if (formTable.containsKey(key)) {
return formTable.get(key);
}
throw new HttpException(BAD_REQUEST, "데이터가 존재하지 않습니다");
throw new FormDataException(INVALID_FORM);
}
}
26 changes: 26 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/common/ResourceLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nextstep.jwp.common;

import static nextstep.jwp.exception.ResourceExceptionType.RESOURCE_NOT_FOUND;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import nextstep.jwp.exception.ResourceException;

public class ResourceLoader {

public static String load(String path) {
URL resource = ResourceLoader.class.getClassLoader().getResource(path);
if (resource == null) {
throw new ResourceException(RESOURCE_NOT_FOUND);
}
File file = new File(resource.getFile());
try {
byte[] bytes = Files.readAllBytes(file.toPath());
return new String(bytes);
} catch (IOException e) {
throw new ResourceException(RESOURCE_NOT_FOUND);
}
}
}
28 changes: 28 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/config/ControllerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package nextstep.jwp.config;

import nextstep.jwp.presentation.ExceptionControllerAdvice;
import nextstep.jwp.presentation.FrontController;
import nextstep.jwp.presentation.HomeController;
import nextstep.jwp.presentation.LoginController;
import nextstep.jwp.presentation.RegisterController;
import nextstep.jwp.presentation.RequestMapping;
import nextstep.jwp.presentation.ResourceController;
import nextstep.jwp.service.LoginService;

public class ControllerConfig {

public static final ExceptionControllerAdvice exceptionControllerAdvice = new ExceptionControllerAdvice();
private static final RequestMapping requestMapping = new RequestMapping(
new HomeController(),
new LoginController(new LoginService()),
new RegisterController(),
new ResourceController()
);
public static final FrontController frontController = new FrontController(
requestMapping,
exceptionControllerAdvice
);

private ControllerConfig() {
}
}
15 changes: 15 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/exception/AuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nextstep.jwp.exception;

public class AuthException extends BaseException {

private final AuthExceptionType exceptionType;

public AuthException(AuthExceptionType exceptionType) {
this.exceptionType = exceptionType;
}

@Override
public BaseExceptionType exceptionType() {
return exceptionType;
}
}
33 changes: 33 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/exception/AuthExceptionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package nextstep.jwp.exception;

import static org.apache.coyote.http11.HttpStatus.BAD_REQUEST;
import static org.apache.coyote.http11.HttpStatus.UNAUTHORIZED;

import org.apache.coyote.http11.HttpStatus;

public enum AuthExceptionType implements BaseExceptionType {

INVALID_SESSION_ID(UNAUTHORIZED, "잘못된 세션 아이디입니다"),
USER_NO_EXIST_IN_SESSION(UNAUTHORIZED, "세션에 회원정보가 존재하지 않습니다"),
INVALID_ID_OR_PASSWORD(UNAUTHORIZED, "아이디나 비밀번호를 확인해주세요"),
DUPLICATED_ID(BAD_REQUEST, "이미 존재하는 아이디입니다. 다른 아이디로 가입해주세요"),
;

private final HttpStatus httpStatus;
private final String errorMessage;

AuthExceptionType(HttpStatus httpStatus, String errorMessage) {
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String errorMessage() {
return errorMessage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nextstep.jwp.exception;

public abstract class BaseException extends RuntimeException {

public BaseException() {
}

public abstract BaseExceptionType exceptionType();
}
10 changes: 10 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/exception/BaseExceptionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package nextstep.jwp.exception;

import org.apache.coyote.http11.HttpStatus;

public interface BaseExceptionType {

HttpStatus httpStatus();

String errorMessage();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nextstep.jwp.exception;

public class ControllerException extends BaseException {

private final ControllerExceptionType exceptionType;

public ControllerException(ControllerExceptionType exceptionType) {
this.exceptionType = exceptionType;
}

@Override
public BaseExceptionType exceptionType() {
return exceptionType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nextstep.jwp.exception;

import static org.apache.coyote.http11.HttpStatus.BAD_REQUEST;

import org.apache.coyote.http11.HttpStatus;

public enum ControllerExceptionType implements BaseExceptionType {

UNSUPPORTED_REQUEST(BAD_REQUEST, "지원되지 않는 요청입니다"),
UNSUPPORTED_METHOD(BAD_REQUEST, "존재하지 않는 메서드입니다"),
;

private final HttpStatus httpStatus;
private final String errorMessage;

ControllerExceptionType(HttpStatus httpStatus, String errorMessage) {
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String errorMessage() {
return errorMessage;
}
}
15 changes: 15 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/exception/FormDataException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nextstep.jwp.exception;

public class FormDataException extends BaseException {

private final FormDataExceptionType exceptionType;

public FormDataException(FormDataExceptionType exceptionType) {
this.exceptionType = exceptionType;
}

@Override
public BaseExceptionType exceptionType() {
return exceptionType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package nextstep.jwp.exception;

import static org.apache.coyote.http11.HttpStatus.BAD_REQUEST;

import org.apache.coyote.http11.HttpStatus;

public enum FormDataExceptionType implements BaseExceptionType {

INVALID_FORM(BAD_REQUEST, "데이터가 존재하지 않습니다"),
;

private final HttpStatus httpStatus;
private final String errorMessage;

FormDataExceptionType(HttpStatus httpStatus, String errorMessage) {
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String errorMessage() {
return errorMessage;
}
}
15 changes: 15 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/exception/ResourceException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nextstep.jwp.exception;

public class ResourceException extends BaseException {

private final ResourceExceptionType exceptionType;

public ResourceException(ResourceExceptionType exceptionType) {
this.exceptionType = exceptionType;
}

@Override
public BaseExceptionType exceptionType() {
return exceptionType;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package nextstep.jwp.exception;

import static org.apache.coyote.http11.HttpStatus.BAD_REQUEST;

import org.apache.coyote.http11.HttpStatus;

public enum ResourceExceptionType implements BaseExceptionType {

RESOURCE_NOT_FOUND(BAD_REQUEST, "요청받은 리소스가 존재하지 않습니다"),
;

private final HttpStatus httpStatus;
private final String errorMessage;

ResourceExceptionType(HttpStatus httpStatus, String errorMessage) {
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public HttpStatus httpStatus() {
return httpStatus;
}

@Override
public String errorMessage() {
return errorMessage;
}
}
Loading