From 32b8e57b00b80ccf2fed0cc762261a6d6b48b3d3 Mon Sep 17 00:00:00 2001 From: Mikhail Ignatov Date: Wed, 24 May 2023 00:26:15 +0300 Subject: [PATCH 1/3] Refactoring & MultiThreading rev1 --- .../src/main/java/ru/netology/Main.java | 78 +------------- .../src/main/java/ru/netology/Server.java | 102 ++++++++++++++++++ 2 files changed, 106 insertions(+), 74 deletions(-) create mode 100644 01_web/http-server/src/main/java/ru/netology/Server.java diff --git a/01_web/http-server/src/main/java/ru/netology/Main.java b/01_web/http-server/src/main/java/ru/netology/Main.java index 200f477..5c17dde 100644 --- a/01_web/http-server/src/main/java/ru/netology/Main.java +++ b/01_web/http-server/src/main/java/ru/netology/Main.java @@ -1,82 +1,12 @@ package ru.netology; -import java.io.*; -import java.net.ServerSocket; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.LocalDateTime; -import java.util.List; - public class Main { public static void main(String[] args) { - final var validPaths = List.of("/index.html", "/spring.svg", "/spring.png", "/resources.html", "/styles.css", "/app.js", "/links.html", "/forms.html", "/classic.html", "/events.html", "/events.js"); - - try (final var serverSocket = new ServerSocket(9999)) { - while (true) { - try ( - final var socket = serverSocket.accept(); - final var in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - final var out = new BufferedOutputStream(socket.getOutputStream()); - ) { - // read only request line for simplicity - // must be in form GET /path HTTP/1.1 - final var requestLine = in.readLine(); - final var parts = requestLine.split(" "); - - if (parts.length != 3) { - // just close socket - continue; - } - - final var path = parts[1]; - if (!validPaths.contains(path)) { - out.write(( - "HTTP/1.1 404 Not Found\r\n" + - "Content-Length: 0\r\n" + - "Connection: close\r\n" + - "\r\n" - ).getBytes()); - out.flush(); - continue; - } - - final var filePath = Path.of(".", "public", path); - final var mimeType = Files.probeContentType(filePath); - - // special case for classic - if (path.equals("/classic.html")) { - final var template = Files.readString(filePath); - final var content = template.replace( - "{time}", - LocalDateTime.now().toString() - ).getBytes(); - out.write(( - "HTTP/1.1 200 OK\r\n" + - "Content-Type: " + mimeType + "\r\n" + - "Content-Length: " + content.length + "\r\n" + - "Connection: close\r\n" + - "\r\n" - ).getBytes()); - out.write(content); - out.flush(); - continue; - } + int poolSize = 64; + int port = 9999; + Server server = new Server(poolSize); + server.start(port); - final var length = Files.size(filePath); - out.write(( - "HTTP/1.1 200 OK\r\n" + - "Content-Type: " + mimeType + "\r\n" + - "Content-Length: " + length + "\r\n" + - "Connection: close\r\n" + - "\r\n" - ).getBytes()); - Files.copy(filePath, out); - out.flush(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } } } diff --git a/01_web/http-server/src/main/java/ru/netology/Server.java b/01_web/http-server/src/main/java/ru/netology/Server.java new file mode 100644 index 0000000..b86fd08 --- /dev/null +++ b/01_web/http-server/src/main/java/ru/netology/Server.java @@ -0,0 +1,102 @@ +package ru.netology; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Server { + + + final List validPaths = List.of("/index.html", "/spring.svg", "/spring.png", "/resources.html", "/styles.css", "/app.js", "/links.html", "/forms.html", "/classic.html", "/events.html", "/events.js"); + + ExecutorService executorService; + + public Server(int poolSize) { + this.executorService = Executors.newFixedThreadPool(poolSize); + } + + public void start(int port) { + try (final var serverSocket = new ServerSocket(port)) { + while (true) { + final var socket = serverSocket.accept(); + executorService.submit(() -> connect(socket)); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void connect(Socket socket) { + try (socket; + final var in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + final var out = new BufferedOutputStream(socket.getOutputStream()); + ) { + // read only request line for simplicity + // must be in form GET /path HTTP/1.1 + final var requestLine = in.readLine(); + final var parts = requestLine.split(" "); + + if (parts.length != 3) { + // just close socket + return; + } + + final var path = parts[1]; + if (!validPaths.contains(path)) { + out.write(( + "HTTP/1.1 404 Not Found\r\n" + + "Content-Length: 0\r\n" + + "Connection: close\r\n" + + "\r\n" + ).getBytes()); + out.flush(); + return; + } + + final var filePath = Path.of(".", "public", path); + final var mimeType = Files.probeContentType(filePath); + + // special case for classic + if (path.equals("/classic.html")) { + final var template = Files.readString(filePath); + final var content = template.replace( + "{time}", + LocalDateTime.now().toString() + ).getBytes(); + out.write(( + "HTTP/1.1 200 OK\r\n" + + "Content-Type: " + mimeType + "\r\n" + + "Content-Length: " + content.length + "\r\n" + + "Connection: close\r\n" + + "\r\n" + ).getBytes()); + out.write(content); + out.flush(); + return; + } + + final var length = Files.size(filePath); + out.write(( + "HTTP/1.1 200 OK\r\n" + + "Content-Type: " + mimeType + "\r\n" + + "Content-Length: " + length + "\r\n" + + "Connection: close\r\n" + + "\r\n" + ).getBytes()); + Files.copy(filePath, out); + out.flush(); + } + catch (IOException e) { + e.printStackTrace(); + } + } +} From 28b9db5d39ef433c94315a3f2c5588cafe6bf7ab Mon Sep 17 00:00:00 2001 From: Mikhail Ignatov Date: Tue, 13 Jun 2023 13:09:54 +0300 Subject: [PATCH 2/3] 2.1. Servlets Containers --- .../netology/controller/PostController.java | 20 +++++--- .../netology/repository/PostRepository.java | 47 ++++++++++++++----- .../java/ru/netology/servlet/MainServlet.java | 22 ++++++--- 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/04_serlvets/servlets/src/main/java/ru/netology/controller/PostController.java b/04_serlvets/servlets/src/main/java/ru/netology/controller/PostController.java index dcd224a..7a345c8 100644 --- a/04_serlvets/servlets/src/main/java/ru/netology/controller/PostController.java +++ b/04_serlvets/servlets/src/main/java/ru/netology/controller/PostController.java @@ -1,6 +1,7 @@ package ru.netology.controller; import com.google.gson.Gson; +import ru.netology.exception.NotFoundException; import ru.netology.model.Post; import ru.netology.service.PostService; @@ -11,31 +12,38 @@ public class PostController { public static final String APPLICATION_JSON = "application/json"; private final PostService service; + private final Gson gson; public PostController(PostService service) { this.service = service; + gson = new Gson(); } public void all(HttpServletResponse response) throws IOException { response.setContentType(APPLICATION_JSON); final var data = service.all(); - final var gson = new Gson(); + //final var gson = new Gson(); response.getWriter().print(gson.toJson(data)); } - public void getById(long id, HttpServletResponse response) { - // TODO: deserialize request & serialize response + public void getById(long id, HttpServletResponse response) throws IOException, NotFoundException { + response.setContentType(APPLICATION_JSON); + final var post = service.getById(id); + response.getWriter().println(gson.toJson(post)); } public void save(Reader body, HttpServletResponse response) throws IOException { response.setContentType(APPLICATION_JSON); - final var gson = new Gson(); + //final var gson = new Gson(); final var post = gson.fromJson(body, Post.class); final var data = service.save(post); response.getWriter().print(gson.toJson(data)); } - public void removeById(long id, HttpServletResponse response) { - // TODO: deserialize request & serialize response + public void removeById(long id, HttpServletResponse response) throws IOException { + response.setContentType(APPLICATION_JSON); + final var data = service.getById(id); + service.removeById(id); + response.getWriter().print(gson.toJson(data)); } } diff --git a/04_serlvets/servlets/src/main/java/ru/netology/repository/PostRepository.java b/04_serlvets/servlets/src/main/java/ru/netology/repository/PostRepository.java index b02cc29..6a756b7 100644 --- a/04_serlvets/servlets/src/main/java/ru/netology/repository/PostRepository.java +++ b/04_serlvets/servlets/src/main/java/ru/netology/repository/PostRepository.java @@ -1,25 +1,48 @@ package ru.netology.repository; +import ru.netology.exception.NotFoundException; import ru.netology.model.Post; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; // Stub public class PostRepository { - public List all() { - return Collections.emptyList(); - } + private final ConcurrentHashMap posts; + private final AtomicLong idCounter = new AtomicLong(0L); - public Optional getById(long id) { - return Optional.empty(); - } + public PostRepository() { + this.posts = new ConcurrentHashMap<>(); + } - public Post save(Post post) { - return post; - } + public List all() { + return new ArrayList<>(posts.values()); + } - public void removeById(long id) { - } + public Optional getById(long id) { + return Optional.ofNullable(posts.get(id)); + } + + public Post save(Post post) { + if (post.getId() == 0) { + long id = idCounter.incrementAndGet(); + post.setId(id); + posts.put(id, post); + } else if (post.getId() != 0) { + Long currentId = post.getId(); + posts.put(currentId, post); + } + return post; + } + + public void removeById(long id) { + if (posts.containsKey(id)) { + posts.remove(id); + } else { + throw new NotFoundException("Удаление поста номер " + id + " не выполнено"); + } + } } diff --git a/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java b/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java index 03b14ba..9c00881 100644 --- a/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java +++ b/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java @@ -9,6 +9,12 @@ import javax.servlet.http.HttpServletResponse; public class MainServlet extends HttpServlet { + public static final String apiPosts = "/api/posts"; + public static final String apiPostsD = "/api/posts/\\d+"; + public static final String str = "/"; + public static final String getMethod = "GET"; + public static final String postMethod = "POST"; + public static final String deleteMethod = "DELETE"; private PostController controller; @Override @@ -25,23 +31,23 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) { final var path = req.getRequestURI(); final var method = req.getMethod(); // primitive routing - if (method.equals("GET") && path.equals("/api/posts")) { + if (method.equals(getMethod) && path.equals(apiPosts)) { controller.all(resp); return; } - if (method.equals("GET") && path.matches("/api/posts/\\d+")) { + if (method.equals(getMethod) && path.matches(apiPostsD)) { // easy way - final var id = Long.parseLong(path.substring(path.lastIndexOf("/"))); + final var id = parseId(path); controller.getById(id, resp); return; } - if (method.equals("POST") && path.equals("/api/posts")) { + if (method.equals(postMethod) && path.equals(apiPosts)) { controller.save(req.getReader(), resp); return; } - if (method.equals("DELETE") && path.matches("/api/posts/\\d+")) { + if (method.equals(deleteMethod) && path.matches(apiPostsD)) { // easy way - final var id = Long.parseLong(path.substring(path.lastIndexOf("/"))); + final var id = parseId(path); controller.removeById(id, resp); return; } @@ -51,5 +57,9 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) { resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } + + private long parseId(String path) { + return Long.parseLong(path.substring(path.lastIndexOf(str))); + } } From 7315bb1de4a37b8d216815136a428fc1e6eeade8 Mon Sep 17 00:00:00 2001 From: Mikhail Ignatov Date: Thu, 15 Jun 2023 00:50:37 +0300 Subject: [PATCH 3/3] Java Config --- 04_serlvets/servlets/pom.xml | 5 +++ .../java/ru/netology/config/JavaConfig.java | 25 +++++++++++++++ .../java/ru/netology/servlet/MainServlet.java | 31 +++++++++---------- 3 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 04_serlvets/servlets/src/main/java/ru/netology/config/JavaConfig.java diff --git a/04_serlvets/servlets/pom.xml b/04_serlvets/servlets/pom.xml index 66de66c..584f169 100644 --- a/04_serlvets/servlets/pom.xml +++ b/04_serlvets/servlets/pom.xml @@ -28,6 +28,11 @@ 2.8.6 compile + + org.springframework + spring-context + 5.3.15 + \ No newline at end of file diff --git a/04_serlvets/servlets/src/main/java/ru/netology/config/JavaConfig.java b/04_serlvets/servlets/src/main/java/ru/netology/config/JavaConfig.java new file mode 100644 index 0000000..aad57e2 --- /dev/null +++ b/04_serlvets/servlets/src/main/java/ru/netology/config/JavaConfig.java @@ -0,0 +1,25 @@ +package ru.netology.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.netology.controller.PostController; +import ru.netology.repository.PostRepository; +import ru.netology.service.PostService; + +@Configuration +public class JavaConfig { + @Bean + public PostController postController(PostService service) { + return new PostController(service); + } + + @Bean + public PostService postService(PostRepository repository) { + return new PostService(repository); + } + + @Bean + public PostRepository postRepository() { + return new PostRepository(); + } +} \ No newline at end of file diff --git a/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java b/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java index 9c00881..afd177f 100644 --- a/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java +++ b/04_serlvets/servlets/src/main/java/ru/netology/servlet/MainServlet.java @@ -1,27 +1,26 @@ package ru.netology.servlet; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import ru.netology.config.JavaConfig; import ru.netology.controller.PostController; -import ru.netology.repository.PostRepository; -import ru.netology.service.PostService; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MainServlet extends HttpServlet { - public static final String apiPosts = "/api/posts"; - public static final String apiPostsD = "/api/posts/\\d+"; - public static final String str = "/"; - public static final String getMethod = "GET"; - public static final String postMethod = "POST"; - public static final String deleteMethod = "DELETE"; + private final String API_POSTS = "/api/posts"; + private final String API_POSTS_D = "/api/posts/\\d+"; + private final String STR = "/"; + private final String GET_METHOD = "GET"; + private final String POST_METHOD = "POST"; + private final String DELETE_METHOD = "DELETE"; private PostController controller; @Override public void init() { - final var repository = new PostRepository(); - final var service = new PostService(repository); - controller = new PostController(service); + final var context = new AnnotationConfigApplicationContext(JavaConfig.class); + controller = context.getBean(PostController.class); } @Override @@ -31,21 +30,21 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) { final var path = req.getRequestURI(); final var method = req.getMethod(); // primitive routing - if (method.equals(getMethod) && path.equals(apiPosts)) { + if (method.equals(GET_METHOD) && path.equals(API_POSTS)) { controller.all(resp); return; } - if (method.equals(getMethod) && path.matches(apiPostsD)) { + if (method.equals(GET_METHOD) && path.matches(API_POSTS_D)) { // easy way final var id = parseId(path); controller.getById(id, resp); return; } - if (method.equals(postMethod) && path.equals(apiPosts)) { + if (method.equals(POST_METHOD) && path.equals(API_POSTS)) { controller.save(req.getReader(), resp); return; } - if (method.equals(deleteMethod) && path.matches(apiPostsD)) { + if (method.equals(DELETE_METHOD) && path.matches(API_POSTS_D)) { // easy way final var id = parseId(path); controller.removeById(id, resp); @@ -59,7 +58,7 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) { } private long parseId(String path) { - return Long.parseLong(path.substring(path.lastIndexOf(str))); + return Long.parseLong(path.substring(path.lastIndexOf(STR))); } }