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단계] 썬샷(오진택) 미션 제출합니다. #479

Merged
merged 13 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cache.com.example.cachecontrol;

import cache.com.example.interceptor.NocacheInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Expand All @@ -9,5 +10,7 @@ public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new NocacheInterceptor())
.addPathPatterns("/");
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package cache.com.example.etag;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ShallowEtagHeaderFilter;

@Configuration
public class EtagFilterConfiguration {

// @Bean
// public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
// return null;
// }
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean
= new FilterRegistrationBean<>( new ShallowEtagHeaderFilter());
filterRegistrationBean.addUrlPatterns("/etag", "/resources/*");
filterRegistrationBean.setName("etagFilter");
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cache.com.example.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class NocacheInterceptor implements HandlerInterceptor {

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
response.addHeader("Cache-Control", "no-cache, private");
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cache.com.example.version;

import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

Expand All @@ -20,6 +22,7 @@ public CacheBustingWebConfig(ResourceVersion version) {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
.addResourceLocations("classpath:/static/");
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic());
}
}
9 changes: 6 additions & 3 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ handlebars:

server:
tomcat:
accept-count: 1
max-connections: 1
accept-count: 0
max-connections: 4
threads:
max: 2
max: 4
compression:
enabled: true
min-response-size: 10
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
18 changes: 7 additions & 11 deletions study/src/test/java/thread/stage1/ConcurrencyTest.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package thread.stage1;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

/**
* 스레드를 다룰 때 어떤 상황을 조심해야 할까?
* - 상태를 가진 한 객체를 여러 스레드에서 동시에 접근할 경우
* - static 변수를 가진 객체를 여러 스레드에서 동시에 접근할 경우
*
* 위 경우는 동기화(synchronization)를 적용시키거나 객체가 상태를 갖지 않도록 한다.
* 객체를 불변 객체로 만드는 방법도 있다.
*
* 웹서버는 여러 사용자가 동시에 접속을 시도하기 때문에 동시성 이슈가 생길 수 있다.
* 어떤 사례가 있는지 아래 테스트 코드를 통해 알아보자.
* 스레드를 다룰 때 어떤 상황을 조심해야 할까? - 상태를 가진 한 객체를 여러 스레드에서 동시에 접근할 경우 - static 변수를 가진 객체를 여러 스레드에서 동시에 접근할 경우
* <p>
* 위 경우는 동기화(synchronization)를 적용시키거나 객체가 상태를 갖지 않도록 한다. 객체를 불변 객체로 만드는 방법도 있다.
* <p>
* 웹서버는 여러 사용자가 동시에 접속을 시도하기 때문에 동시성 이슈가 생길 수 있다. 어떤 사례가 있는지 아래 테스트 코드를 통해 알아보자.
*/
class ConcurrencyTest {

Expand Down
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage2/TestHttpUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class TestHttpUtils {

private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofSeconds(1))
.connectTimeout(Duration.ofSeconds((1)))
.build();

public static HttpResponse<String> send(final String path) {
Expand Down
159 changes: 0 additions & 159 deletions tomcat/src/main/java/nextstep/jwp/RequestProcessor.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package nextstep.jwp.controller;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.catalina.Controller;
import org.apache.coyote.common.HttpMethod;
import org.apache.coyote.request.HttpRequest;
import org.apache.coyote.response.HttpResponse;

abstract class AbstractController implements Controller {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 추상 클래스는 HttpServlet과 비슷한 것 같아요.
명세에 가깝게 느껴져서 패키지 위치가 웹앱 쪽이 맞을 지 의문입니다!


protected static final String DEFAULT_FILE_LOCATION = "static/";

public abstract boolean canHandle(HttpRequest request);

@Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
if (request.getHttpMethod().equals(HttpMethod.GET)) {
doGet(request, response);
}
if (request.getHttpMethod().equals(HttpMethod.POST)) {
doPost(request, response);
}
}

protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ }
protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ }

protected String readResponseBody(final String requestUri) throws IOException, URISyntaxException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통적으로 사용할 수 있게 만들기 위해서 추상 클래스에 만들어뒀군요!
IS-A 관계를 잘 사용하신 것 같아요!

final URL url = getClass().getClassLoader().getResource(DEFAULT_FILE_LOCATION + requestUri);
if (url == null) {
URL notFoundUrl = getClass().getClassLoader().getResource(DEFAULT_FILE_LOCATION + "404.html");
final var path = Paths.get(notFoundUrl.toURI());
return Files.readString(path);
}
final var path = Paths.get(url.toURI());
return Files.readString(path);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package nextstep.jwp.controller;

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

public class ErrorPageController extends AbstractController {

@Override
public boolean canHandle(HttpRequest request) {
return false;
}

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
response.setStatusLine(StatusLine.of(request.getHttpVersion(), HttpStatus.NOT_FOUND));
response.addHeader(HttpHeader.CONTENT_TYPE.getName(), ContentType.HTML.getType());
final String content = readResponseBody("500.html");
response.setResponseBody(content);
}
}
Loading