-
Notifications
You must be signed in to change notification settings - Fork 388
[3단계 - Tomcat 구현하기] 비토(오상훈) 미션 제출합니다. #594
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
Changes from all commits
fed02f6
7e91356
44fc288
7ed4d23
078af63
25e67eb
8e570a7
3b1799d
f986e25
dda9c17
c53b87a
b24f95f
8672b31
61ff56c
74fce63
75f9655
4ae9b63
9bff59a
b3ae80d
a522403
3273872
a4cc800
5f3957e
7277aa2
79da605
2740606
5de4b86
76debc6
365c1bf
7c78ae2
7c54713
c9082d1
2320bd1
0bd1a98
027ff0c
f758221
581fdcf
e854bc8
5e51288
f933ab4
a7205ea
3604089
a47cab2
d64f3b6
2baf5a6
e1fbb9f
f3255e9
5b53b77
ff86414
5a28c68
bd236dc
0039a00
3e6b67d
cd9c986
dbf14ba
afa9586
7b0131d
ef947a1
98f9e5b
222b4ad
c4a0070
4ec21d2
4fc70b6
1b628be
f5a4916
84a3721
245384b
99a54b9
05d3356
dae1388
99c5f8e
459958d
3037360
9e8ea4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,12 @@ | ||
| 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; | ||
|
|
||
| /** | ||
| * 스레드 풀은 무엇이고 어떻게 동작할까? | ||
|
|
@@ -31,8 +30,8 @@ void testNewFixedThreadPool() { | |
| executor.submit(logWithSleep("hello fixed thread pools")); | ||
|
|
||
| // 올바른 값으로 바꿔서 테스트를 통과시키자. | ||
| final int expectedPoolSize = 0; | ||
| final int expectedQueueSize = 0; | ||
| final int expectedPoolSize = 2; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Executors.newFixedThreadPool(...)와 Executors.newCachedThreadPool()는 어떤 차이가 있나요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| final int expectedQueueSize = 1; | ||
|
|
||
| assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); | ||
| assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size()); | ||
|
|
@@ -46,7 +45,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()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.techcourse.controller; | ||
|
|
||
| import org.apache.coyote.http11.HttpMethod; | ||
| import org.apache.coyote.http11.httprequest.HttpRequest; | ||
| import org.apache.coyote.http11.httpresponse.HttpResponse; | ||
|
|
||
| public abstract class AbstractController implements Controller { | ||
|
|
||
| @Override | ||
| public void service(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| if (httpRequest.isMethod(HttpMethod.GET)) { | ||
| doGet(httpRequest, httpResponse); | ||
| } | ||
| if (httpRequest.isMethod(HttpMethod.POST)) { | ||
| doPost(httpRequest, httpResponse); | ||
| } | ||
|
|
||
| throw new IllegalArgumentException("유효하지 않은 메소드입니다."); | ||
| } | ||
|
|
||
| abstract protected void doPost(HttpRequest httpRequest, HttpResponse httpResponse); | ||
|
|
||
| abstract protected void doGet(HttpRequest httpRequest, HttpResponse httpResponse); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| package org.apache.coyote.http11.controller; | ||
| package com.techcourse.controller; | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. public interface Controller {
void service(HttpRequest request, HttpResponse response) throws Exception;
}
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 형식으로 수정했습니다! |
||
| import org.apache.coyote.http11.httprequest.HttpRequest; | ||
| import org.apache.coyote.http11.httpresponse.HttpResponse; | ||
|
|
||
| public interface Controller { | ||
|
|
||
| HttpResponse service(HttpRequest httpRequest); | ||
| void service(HttpRequest request, HttpResponse response) throws Exception; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package com.techcourse.controller; | ||
|
|
||
| import com.techcourse.db.InMemoryUserRepository; | ||
| import com.techcourse.model.User; | ||
| import org.apache.coyote.http11.exception.UnauthorizedException; | ||
| import org.apache.coyote.http11.httprequest.HttpRequest; | ||
| import org.apache.coyote.http11.httpresponse.HttpResponse; | ||
| import org.apache.coyote.http11.session.Session; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class LoginController extends AbstractController { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(LoginController.class); | ||
| private static final String LOGIN_PATH = "/login"; | ||
| private static final String ACCOUNT = "account"; | ||
| private static final String PASSWORD = "password"; | ||
| private static final String INDEX_PATH = "/index.html"; | ||
|
|
||
| @Override | ||
| protected void doPost(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| if (validateUserInput(httpRequest)) { | ||
| log.error("입력하지 않은 항목이 있습니다."); | ||
| redirectLoginPage(httpRequest, httpResponse); | ||
| return; | ||
| } | ||
| acceptLogin(httpRequest, httpResponse); | ||
| } | ||
|
|
||
| private void redirectLoginPage(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| httpResponse.location(httpRequest, LOGIN_PATH); | ||
| } | ||
|
|
||
| private boolean validateUserInput(HttpRequest httpRequest) { | ||
| return !httpRequest.containsBody(ACCOUNT) || !httpRequest.containsBody(PASSWORD); | ||
| } | ||
|
|
||
| private void acceptLogin(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| String account = httpRequest.getBodyValue(ACCOUNT); | ||
| String password = httpRequest.getBodyValue(PASSWORD); | ||
|
|
||
| InMemoryUserRepository.findByAccount(account) | ||
| .filter(user -> user.checkPassword(password)) | ||
| .ifPresentOrElse( | ||
| user -> redirectWithCookie(httpRequest, httpResponse, user), | ||
| () -> { | ||
| log.error("존재하지 않는 계정이거나 비밀번호 불일치"); | ||
| throw new UnauthorizedException("존재하지 않는 계정입니다"); | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| private void redirectWithCookie(HttpRequest httpRequest, HttpResponse httpResponse, User user) { | ||
| Session session = httpRequest.getSession(); | ||
| session.setUser(user); | ||
| log.info(user.toString()); | ||
| httpResponse.location(httpRequest, INDEX_PATH); | ||
| httpResponse.setSession(session); | ||
| } | ||
|
|
||
| @Override | ||
| protected void doGet(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| Session session = httpRequest.getSession(); | ||
| if (!session.hasUser()) { | ||
| httpResponse.ok(httpRequest); | ||
| httpResponse.staticResource(LOGIN_PATH); | ||
| return; | ||
| } | ||
| User user = (User) session.getUser(); | ||
| log.info(user.toString()); | ||
| httpResponse.location(httpRequest, INDEX_PATH); | ||
| httpResponse.setSession(session); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package com.techcourse.controller; | ||
|
|
||
| import com.techcourse.db.InMemoryUserRepository; | ||
| import com.techcourse.model.User; | ||
| import org.apache.coyote.http11.httprequest.HttpRequest; | ||
| import org.apache.coyote.http11.httpresponse.HttpResponse; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class RegisterController extends AbstractController { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(RegisterController.class); | ||
| private static final String REGISTER_PATH = "/register"; | ||
| private static final String ACCOUNT = "account"; | ||
| private static final String PASSWORD = "password"; | ||
| private static final String EMAIL = "email"; | ||
| private static final String INDEX_PATH = "/index.html"; | ||
|
|
||
| @Override | ||
| protected void doPost(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| if (validateUserInput(httpRequest)) { | ||
| log.error("입력하지 않은 항목이 있습니다."); | ||
| redirectPage(httpRequest, httpResponse, REGISTER_PATH); | ||
| return; | ||
| } | ||
| acceptRegister(httpRequest, httpResponse); | ||
| } | ||
|
|
||
| private void acceptRegister(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| String account = httpRequest.getBodyValue(ACCOUNT); | ||
| String password = httpRequest.getBodyValue(PASSWORD); | ||
| String email = httpRequest.getBodyValue(EMAIL); | ||
| if (InMemoryUserRepository.containsByAccount(account)) { | ||
| log.error("이미 존재하는 account입니다"); | ||
| redirectPage(httpRequest, httpResponse, REGISTER_PATH); | ||
| return; | ||
| } | ||
| InMemoryUserRepository.save(new User(account, password, email)); | ||
| redirectPage(httpRequest, httpResponse, INDEX_PATH); | ||
| } | ||
|
|
||
| private boolean validateUserInput(HttpRequest httpRequest) { | ||
| return !httpRequest.containsBody(ACCOUNT) | ||
| || !httpRequest.containsBody(PASSWORD) | ||
| || !httpRequest.containsBody(EMAIL); | ||
| } | ||
|
|
||
| @Override | ||
| protected void doGet(HttpRequest httpRequest, HttpResponse httpResponse) { | ||
| httpResponse.ok(httpRequest); | ||
| httpResponse.staticResource(httpRequest.getPath()); | ||
| } | ||
|
|
||
| private void redirectPage(HttpRequest httpRequest, HttpResponse httpResponse, String path) { | ||
| httpResponse.location(httpRequest, path); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package org.apache.coyote.http11; | ||
|
|
||
| public enum CharSet { | ||
|
|
||
| UTF_8(";charset=utf-8") | ||
| ; | ||
|
|
||
| private final String charset; | ||
|
|
||
| CharSet(String charset) { | ||
| this.charset = charset; | ||
| } | ||
|
|
||
| public String getCharset() { | ||
| return charset; | ||
| } | ||
| } |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왜 synchronized를 붙이라고 했을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
만약 synchronized가 없으면 테스트 코드에서 실행되고 있는 1000개의 스레드 중 일부가
sum이 정확히 변경되어 저장하기 전에 접근하게 되면서 정확하게 1000번 증가한 값이 나오지 않게 됩니다.그래서 synchronized를 사용해 한번에 하나의 스레드만 접근 가능하게 하고 다른 스레드는 그동안 대기하게 만들어 스레드 안전성을 보장해줍니다.