Skip to content

Commit

Permalink
[톰캣 구현하기 - 3, 4단계] 다즐(최우창) 미션 제출합니다. (#470)
Browse files Browse the repository at this point in the history
* refactor: 의존성에 맞게 패키지 구조 수정

* feat: 요청 매핑 정보 분리

* feat: 서블릿 기능 구현

* feat: 동시성 확장을 위한 기능 구현

* refactor: 연산 결과가 사용되지 않기에 execute 사용하도록 수정

* refactor: pattern 오타 수정

* refactor: 변수명 오타 수정
  • Loading branch information
woo-chang authored Sep 12, 2023
1 parent 22a9cc3 commit bad7596
Show file tree
Hide file tree
Showing 48 changed files with 592 additions and 430 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nextstep.jwp.controller;

import nextstep.jwp.handle.ViewResolver;
import org.apache.coyote.common.HttpMethod;
import org.apache.coyote.common.HttpStatus;
import org.apache.coyote.request.HttpRequest;
import org.apache.coyote.response.HttpResponse;

public abstract class AbstractController implements Controller {

@Override
public void service(final HttpRequest request, final HttpResponse response) throws Exception {
if (request.getHttpMethod() == HttpMethod.GET) {
doGet(request, response);
return;
}
if (request.getHttpMethod() == HttpMethod.POST) {
doPost(request, response);
return;
}
ViewResolver.renderPage(response, HttpStatus.NOT_FOUND, "404.html");
}

protected abstract void doPost(final HttpRequest request, final HttpResponse response) throws Exception;

protected abstract void doGet(final HttpRequest request, final HttpResponse response) throws Exception;
}
9 changes: 9 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/controller/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nextstep.jwp.controller;

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

public interface Controller {

void service(final HttpRequest request, final HttpResponse response) throws Exception;
}
27 changes: 27 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/controller/FileController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nextstep.jwp.controller;

import nextstep.jwp.handle.ViewResolver;
import org.apache.coyote.common.HttpStatus;
import org.apache.coyote.request.HttpRequest;
import org.apache.coyote.response.HttpResponse;

public class FileController extends AbstractController {

private static final FileController fileController = new FileController();

private FileController() {
}

public static FileController getInstance() {
return fileController;
}

@Override
public void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
ViewResolver.renderPage(response, HttpStatus.OK, request.getUriPath().substring(1));
}

@Override
public void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nextstep.jwp.controller;

import org.apache.coyote.common.ContentType;
import org.apache.coyote.common.HttpStatus;
import org.apache.coyote.request.HttpRequest;
import org.apache.coyote.response.HttpResponse;

public class HelloWorldController extends AbstractController {

private static final String BODY = "Hello world!";
private static final HelloWorldController helloWorldController = new HelloWorldController();

private HelloWorldController() {
}

public static HelloWorldController getInstance() {
return helloWorldController;
}

@Override
public void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
response.setStatus(HttpStatus.OK);
response.setContentType(ContentType.TEXT_HTML.getType());
response.setContent(BODY);
}

@Override
public void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.apache.coyote.handle.handler;
package nextstep.jwp.controller;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.handle.ViewResolver;
import nextstep.jwp.model.User;
import org.apache.coyote.common.ContentType;
import org.apache.coyote.common.HttpStatus;
Expand All @@ -17,57 +17,65 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoginHandler implements Handler {
public class LoginController extends AbstractController {

private static final Logger log = LoggerFactory.getLogger(LoginHandler.class);
private static final Logger log = LoggerFactory.getLogger(LoginController.class);
private static final String SLASH = File.separator;
private static final String LOGIN_PAGE = "login.html";
private static final String LOGIN_SUCCESS_PAGE = "index.html";
private static final String LOGIN_FAIL_PAGE = "401.html";
private static final String ACCOUNT = "account";
private static final String PASSWORD = "password";
private static final String JSESSIONID = "JSESSIONID";
private static final LoginController loginController = new LoginController();

private LoginController() {
}

public static LoginController getInstance() {
return loginController;
}

@Override
public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
final HttpCookie httpCookie = httpRequest.getCookie();
public void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
final HttpCookie httpCookie = request.getCookie();
final String cookie = httpCookie.getCookie(JSESSIONID);
if (cookie == null || SessionManager.findSession(cookie) == null) {
viewResolver.renderPage(httpResponse, HttpStatus.OK, LOGIN_PAGE);
ViewResolver.renderPage(response, HttpStatus.OK, LOGIN_PAGE);
return;
}
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + LOGIN_SUCCESS_PAGE);
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + LOGIN_SUCCESS_PAGE);
}

@Override
public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
final Map<String, String> body = httpRequest.getBody(ContentType.APPLICATION_JSON);
public void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
final Map<String, String> body = request.getBody(ContentType.APPLICATION_JSON);
final String account = body.get(ACCOUNT);
final String password = body.get(PASSWORD);
if (account == null || password == null) {
log.warn("Account Or Password Not Exist");
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + LOGIN_FAIL_PAGE);
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + LOGIN_FAIL_PAGE);
return;
}

final Optional<User> findUser = InMemoryUserRepository.findByAccount(account);
if (findUser.isEmpty() || !findUser.get().checkPassword(password)) {
log.warn("Login Fail");
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + LOGIN_FAIL_PAGE);
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + LOGIN_FAIL_PAGE);
return;
}
loginSuccess(httpResponse, findUser.get());
loginSuccess(response, findUser.get());
}

private void loginSuccess(final HttpResponse httpResponse, final User user) {
private void loginSuccess(final HttpResponse response, final User user) {
final Session session = new Session(UUID.randomUUID().toString());
session.setAttribute("user", user);
SessionManager.add(session);
httpResponse.addCookie(JSESSIONID, session.getId());
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + LOGIN_SUCCESS_PAGE);
response.addCookie(JSESSIONID, session.getId());
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + LOGIN_SUCCESS_PAGE);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.apache.coyote.handle.handler;
package nextstep.jwp.controller;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.handle.ViewResolver;
import nextstep.jwp.model.User;
import org.apache.coyote.common.ContentType;
import org.apache.coyote.common.HttpStatus;
Expand All @@ -16,9 +16,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RegisterHandler implements Handler {
public class RegisterController extends AbstractController {

private static final Logger log = LoggerFactory.getLogger(RegisterHandler.class);
private static final Logger log = LoggerFactory.getLogger(RegisterController.class);
private static final String SLASH = File.separator;
private static final String REGISTER_PAGE = "register.html";
private static final String REGISTER_SUCCESS_PAGE = "index.html";
Expand All @@ -27,43 +27,51 @@ public class RegisterHandler implements Handler {
private static final String PASSWORD = "password";
private static final String EMAIL = "email";
private static final String JSESSIONID = "JSESSIONID";
private static final RegisterController registerController = new RegisterController();

private RegisterController() {
}

public static RegisterController getInstance() {
return registerController;
}

@Override
public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
viewResolver.renderPage(httpResponse, HttpStatus.OK, REGISTER_PAGE);
public void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
ViewResolver.renderPage(response, HttpStatus.OK, REGISTER_PAGE);
}

@Override
public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
final Map<String, String> body = httpRequest.getBody(ContentType.APPLICATION_JSON);
public void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
final Map<String, String> body = request.getBody(ContentType.APPLICATION_JSON);
final String account = body.get(ACCOUNT);
final String password = body.get(PASSWORD);
final String email = body.get(EMAIL);
if (account == null || password == null || email == null) {
log.warn("Account Or Password Or Email Not Exist");
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + REGISTER_FAIL_PAGE);
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + REGISTER_FAIL_PAGE);
return;
}

final Optional<User> findUser = InMemoryUserRepository.findByAccount(body.get(ACCOUNT));
if (findUser.isPresent()) {
log.warn("Registered Account");
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + REGISTER_FAIL_PAGE);
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + REGISTER_FAIL_PAGE);
return;
}
final User user = new User(account, password, email);
registerSuccess(httpResponse, user);
registerSuccess(response, user);
}

private void registerSuccess(final HttpResponse httpResponse, final User user) {
private void registerSuccess(final HttpResponse response, final User user) {
InMemoryUserRepository.save(user);
final Session session = new Session(UUID.randomUUID().toString());
session.setAttribute("user", user);
SessionManager.add(session);
httpResponse.addCookie(JSESSIONID, session.getId());
httpResponse.setStatus(HttpStatus.FOUND);
httpResponse.setLocation(SLASH + REGISTER_SUCCESS_PAGE);
response.addCookie(JSESSIONID, session.getId());
response.setStatus(HttpStatus.FOUND);
response.setLocation(SLASH + REGISTER_SUCCESS_PAGE);
}
}
18 changes: 13 additions & 5 deletions tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
package nextstep.jwp.db;

import nextstep.jwp.model.User;

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 final AtomicLong auto_increment = new AtomicLong(1);

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

public static void save(User user) {
database.put(user.getAccount(), user);
final User saveUser = new User(
auto_increment.getAndIncrement(),
user.getAccount(),
user.getPassword(),
user.getEmail()
);
database.put(saveUser.getAccount(), saveUser);
}

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

private InMemoryUserRepository() {}
private InMemoryUserRepository() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.jwp.exception;

public class HandlerMappingException extends RuntimeException {

public HandlerMappingException() {
super("Handler Mapping Fail");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.jwp.exception;

public class NotFoundHandlerException extends RuntimeException {

public NotFoundHandlerException() {
super("Match Handler Not Found");
}
}
28 changes: 28 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/handle/HandlerMapping.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package nextstep.jwp.handle;

import java.util.HashMap;
import java.util.Map;
import nextstep.jwp.exception.NotFoundHandlerException;
import nextstep.jwp.handle.mapping.MappingInfo;
import org.apache.coyote.request.HttpRequest;

public class HandlerMapping {

private final Map<MappingInfo, HandlerMethod> handlerMapping = new HashMap<>();

public HandlerMapping() {
}

public void addMappingInfo(final MappingInfo mappingInfo, final HandlerMethod handlerMethod) {
handlerMapping.put(mappingInfo, handlerMethod);
}

public HandlerMethod getHandlerMethod(final HttpRequest request) {
return handlerMapping.keySet()
.stream()
.filter(mappingInfo -> mappingInfo.support(request))
.findFirst()
.map(handlerMapping::get)
.orElseThrow(NotFoundHandlerException::new);
}
}
23 changes: 23 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/handle/HandlerMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nextstep.jwp.handle;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import nextstep.jwp.controller.Controller;
import org.apache.coyote.request.HttpRequest;
import org.apache.coyote.response.HttpResponse;

public class HandlerMethod {

private final Controller controller;
private final Method method;

public HandlerMethod(final Controller controller, final Method method) {
this.controller = controller;
this.method = method;
}

public void invokeMethod(final HttpRequest request, final HttpResponse response)
throws InvocationTargetException, IllegalAccessException {
method.invoke(controller, request, response);
}
}
Loading

0 comments on commit bad7596

Please sign in to comment.