diff --git a/client-session/README.md b/client-session/README.md new file mode 100644 index 000000000..82204eb34 --- /dev/null +++ b/client-session/README.md @@ -0,0 +1,114 @@ +--- +title: Client Session Pattern +category: Architectural +language: en +tags: +- Decoupling +--- + +## Name + +[Client Session pattern](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-client) + +## Intent + +- Create stateless servers that removes the problem of clustering, as users can switch between servers seamlessly. +- Makes data more resilient in case of server fail-over. +- Works well with smaller data sizes. + +## Explanation + +Real-World Example + +> You're looking to create a data management app allowing users to send requests to the server to +> modify and make changes to data stored on their devices. These requests are small in size and the +> data is individual to each user, negating the need for a large scale database implementation. +> Using the client session pattern, you are able to handle multiple concurrent requests, load +> balancing clients across different servers with ease due to servers remaining stateless. You also +> remove the need to store session IDs on the server side due to clients providing all the +> information that a server needs to perform their process. + +In Plain words + +> Instead of storing information about the current client and the information being accessed on the +> server, it is maintained client side only. Client has to send session data with each request to +> the server and has to send an updated state back to the client, which is stored on the clients +> machine. The server doesn't have to store the client information. +> ([ref](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-client)) + +**Programmatic Example** + +Here is the sample code to describe the client-session pattern. In the below code we are first +creating an instance of the Server. This server instance will then be used to get Session objects +for two clients. As you can see from the code below the Session object can be used to store any +relevant information that are required by the server to process the client request. These session +objects will then be passed on with every Request to the server. The Request will have the Session +object that stores the relevant client details along with the required data for processing the +request. The session information in every request helps the server identify the client and process +the request accordingly. + +```java +public class App { + + public static void main(String[] args) { + var server = new Server("localhost", 8080); + var session1 = server.getSession("Session1"); + var session2 = server.getSession("Session2"); + var request1 = new Request("Data1", session1); + var request2 = new Request("Data2", session2); + server.process(request1); + server.process(request2); + } +} + +@Data +@AllArgsConstructor +public class Session { + + /** + * Session id. + */ + private String id; + + /** + * Client name. + */ + private String clientName; + +} + +@Data +@AllArgsConstructor +public class Request { + + private String data; + + private Session session; + +} +``` + +## Architecture Diagram + +![alt text](./etc/session_state_pattern.png "Session State Pattern") + +## Applicability + +Use the client state pattern when: + +- Processing smaller amounts of data to prevent larger requests and response sizes. +- Remove the need for servers to save client states. Doing so also removes the need to store session IDs. +- Clustering is an issue and needs to be avoided. Stateless servers allow clients to be easily distributed across servers. +- Creates resilience from data losses due to server fails. + +## Consequences + +- The server is stateless. Any compute API will not store any data. +- Struggles to deal with large amounts of data. Creates longer send and receive times due to larger amounts of session data to manage. +- Security. All data is stored on the client's machine. This means that any vulnerabilities on the clients side can expose all data being sent and received by the server. + + +## Credits + +- [Dzone - Practical PHP patterns](https://dzone.com/articles/practical-php-patterns/practical-php-patterns-client) +- [Client Session State Design Pattern - Ram N Java](https://www.youtube.com/watch?v=ycOSj9g41pc) diff --git a/client-session/etc/session_state_pattern.png b/client-session/etc/session_state_pattern.png new file mode 100644 index 000000000..f1e23be95 Binary files /dev/null and b/client-session/etc/session_state_pattern.png differ diff --git a/client-session/pom.xml b/client-session/pom.xml new file mode 100644 index 000000000..b7ff08637 --- /dev/null +++ b/client-session/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + client-session + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.client.session.App + + + + + + + + + diff --git a/client-session/src/main/java/com/iluwatar/client/session/App.java b/client-session/src/main/java/com/iluwatar/client/session/App.java new file mode 100644 index 000000000..282d8a7f3 --- /dev/null +++ b/client-session/src/main/java/com/iluwatar/client/session/App.java @@ -0,0 +1,55 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.client.session; + +/** + * The Client-Session pattern allows the session data to be stored on the client side and send this + * data to the server with each request. + * + *

In this example, The {@link Server} class represents the server that would process the + * incoming {@link Request} and also assign {@link Session} to a client. Here one instance of Server + * is created. The we create two sessions for two different clients. These sessions are then passed + * on to the server in the request along with the data. The server is then able to interpret the + * client based on the session associated with it. + *

+ */ +public class App { + + /** + * Program entry point. + * + * @param args Command line args + */ + public static void main(String[] args) { + var server = new Server("localhost", 8080); + var session1 = server.getSession("Session1"); + var session2 = server.getSession("Session2"); + var request1 = new Request("Data1", session1); + var request2 = new Request("Data2", session2); + server.process(request1); + server.process(request2); + } +} diff --git a/client-session/src/main/java/com/iluwatar/client/session/Request.java b/client-session/src/main/java/com/iluwatar/client/session/Request.java new file mode 100644 index 000000000..008011f18 --- /dev/null +++ b/client-session/src/main/java/com/iluwatar/client/session/Request.java @@ -0,0 +1,42 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.client.session; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * The Request class which contains the Session details and data. + */ +@Data +@AllArgsConstructor +public class Request { + + private String data; + + private Session session; + +} diff --git a/client-session/src/main/java/com/iluwatar/client/session/Server.java b/client-session/src/main/java/com/iluwatar/client/session/Server.java new file mode 100644 index 000000000..6d9dc3dbc --- /dev/null +++ b/client-session/src/main/java/com/iluwatar/client/session/Server.java @@ -0,0 +1,65 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.client.session; + +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * The Server class. The client communicates with the server and request processing and getting a new session. + */ +@Slf4j +@Data +@AllArgsConstructor +public class Server { + private String host; + + private int port; + + + /** + * Creates a new session. + * + * @param name name of the client + * + * @return Session Object + */ + public Session getSession(String name) { + return new Session(UUID.randomUUID().toString(), name); + } + + /** + * Processes a request based on the session. + * + * @param request Request object with data and Session + */ + public void process(Request request) { + LOGGER.info("Processing Request with client: " + request.getSession().getClientName() + " data: " + request.getData()); + } + +} diff --git a/client-session/src/main/java/com/iluwatar/client/session/Session.java b/client-session/src/main/java/com/iluwatar/client/session/Session.java new file mode 100644 index 000000000..bb9f7246c --- /dev/null +++ b/client-session/src/main/java/com/iluwatar/client/session/Session.java @@ -0,0 +1,48 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.client.session; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * The Session class. Each client get assigned a Session which is then used for further communications. + */ +@Data +@AllArgsConstructor +public class Session { + + /** + * Session id. + */ + private String id; + + /** + * Client name. + */ + private String clientName; + +} diff --git a/client-session/src/test/java/com/iluwatar/client/session/AppTest.java b/client-session/src/test/java/com/iluwatar/client/session/AppTest.java new file mode 100644 index 000000000..0e33f74f4 --- /dev/null +++ b/client-session/src/test/java/com/iluwatar/client/session/AppTest.java @@ -0,0 +1,38 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.client.session; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void appStartsWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/client-session/src/test/java/com/iluwatar/client/session/ServerTest.java b/client-session/src/test/java/com/iluwatar/client/session/ServerTest.java new file mode 100644 index 000000000..dc09441f0 --- /dev/null +++ b/client-session/src/test/java/com/iluwatar/client/session/ServerTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.client.session; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ServerTest { + + @Test + void checkGetSession() { + Server server = new Server("localhost", 8080); + Session session = server.getSession("Session"); + assertEquals("Session", session.getClientName()); + } +} diff --git a/pom.xml b/pom.xml index 09e4dea4f..90c4b2941 100644 --- a/pom.xml +++ b/pom.xml @@ -198,6 +198,7 @@ composite-view metadata-mapping service-to-worker + client-session embedded-value currying serialized-entity