diff --git a/pom.xml b/pom.xml
index c955b7da4ece..8daec02b429a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -214,6 +214,7 @@
gateway
serialized-lob
server-session
+ service-oriented-architecture
virtual-proxy
function-composition
diff --git a/service-oriented-architecture/pom.xml b/service-oriented-architecture/pom.xml
new file mode 100644
index 000000000000..9e5c715a02fd
--- /dev/null
+++ b/service-oriented-architecture/pom.xml
@@ -0,0 +1,102 @@
+
+
+
+ 4.0.0
+
+
+ com.iluwatar
+ java-design-patterns
+ 1.26.0-SNAPSHOT
+
+ service-oriented-architecture
+ service-oriented-architecture
+ service-oriented-architecture
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ pom
+ 3.2.4
+ import
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-parent
+ 2023.0.1
+ pom
+ import
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
\ No newline at end of file
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/SOAExampleApplication.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/SOAExampleApplication.java
new file mode 100644
index 000000000000..a2e79a53a29b
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/SOAExampleApplication.java
@@ -0,0 +1,25 @@
+package com.iluwatar.soa;
+
+import com.iluwatar.soa.services.config.ServiceConfiguration;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@Slf4j
+public class SOAExampleApplication {
+
+ public static void main(String[] args) {
+ ServiceConfiguration.configureAndRegisterServices();
+ SpringApplication.run(SOAExampleApplication.class, args);
+ LOGGER.info("SOA Example Application started successfully!");
+ LOGGER.info("You can access the application via: http://localhost:8080/login");
+ LOGGER.info(
+ "This endpoint will retsurn a personalized greeting based on the weather conditions.");
+ LOGGER.info("You can explore other endpoints as well for different functionalities.");
+ }
+
+
+}
+
+
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/GreetingController.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/GreetingController.java
new file mode 100644
index 000000000000..a30fb77d0f7e
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/GreetingController.java
@@ -0,0 +1,21 @@
+package com.iluwatar.soa.controller;
+
+import com.iluwatar.soa.services.interfaces.PersonalizedGreetingService;
+import com.iluwatar.soa.services.registry.ServiceRegistry;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("home")
+public class GreetingController {
+
+ @GetMapping("/greeting")
+ public String getGreeting() {
+ PersonalizedGreetingService personalizedGreetingService =
+ (PersonalizedGreetingService) ServiceRegistry.getService("personalizedGreetingService");
+ return personalizedGreetingService.generateGreeting();
+ }
+}
+
+
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/LoginController.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/LoginController.java
new file mode 100644
index 000000000000..d45e766a1f9a
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/controller/LoginController.java
@@ -0,0 +1,15 @@
+/*
+package com.iluwatar.soa.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class LoginController {
+
+ @GetMapping("/login")
+ public String loginPage() {
+ return "loginPage";
+ }
+}
+*/
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/model/WeatherCondition.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/model/WeatherCondition.java
new file mode 100644
index 000000000000..24f31bb353a8
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/model/WeatherCondition.java
@@ -0,0 +1,8 @@
+package com.iluwatar.soa.model;
+
+public enum WeatherCondition {
+ SUNNY,
+ RAINY,
+ CLOUDY,
+ FOGGY
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/security/WebSecurityConfig.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/security/WebSecurityConfig.java
new file mode 100644
index 000000000000..b76b8c776aa7
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/security/WebSecurityConfig.java
@@ -0,0 +1,60 @@
+package com.iluwatar.soa.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.SecurityFilterChain;
+
+
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig {
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http
+ .authorizeHttpRequests(requests -> requests
+ .requestMatchers("/login").permitAll()
+ .anyRequest().authenticated()
+ )
+ .formLogin(form -> form
+ .defaultSuccessUrl("/home/greeting", true)
+ .permitAll()
+ )
+ .logout(LogoutConfigurer::permitAll);
+
+ return http.build();
+ }
+
+
+ @Bean
+ public UserDetailsService userDetailsService() {
+ UserDetails user =
+ User.builder()
+ .username("user")
+ .password(passwordEncoder().encode("password"))
+ .roles("USER")
+ .build();
+ UserDetails admin =
+ User.builder()
+ .username("admin")
+ .password(passwordEncoder().encode("password"))
+ .roles("USER", "ADMIN")
+ .build();
+ return new InMemoryUserDetailsManager(user, admin);
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/GreetingServiceImpl.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/GreetingServiceImpl.java
new file mode 100644
index 000000000000..23df6469157b
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/GreetingServiceImpl.java
@@ -0,0 +1,13 @@
+package com.iluwatar.soa.services.classes;
+
+import com.iluwatar.soa.services.interfaces.GreetingService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class GreetingServiceImpl implements GreetingService {
+
+ public String getGenericGreeting() {
+ return "Hello, how are you today?";
+ }
+
+}
\ No newline at end of file
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/PersonalizedGreetingServiceImpl.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/PersonalizedGreetingServiceImpl.java
new file mode 100644
index 000000000000..7a1e3f57bad6
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/PersonalizedGreetingServiceImpl.java
@@ -0,0 +1,38 @@
+package com.iluwatar.soa.services.classes;
+
+import com.iluwatar.soa.model.WeatherCondition;
+import com.iluwatar.soa.services.interfaces.GreetingService;
+import com.iluwatar.soa.services.interfaces.PersonalizedGreetingService;
+import com.iluwatar.soa.services.interfaces.WeatherService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class PersonalizedGreetingServiceImpl implements PersonalizedGreetingService {
+
+ private final GreetingService greetingService;
+ private final WeatherService weatherService;
+
+ @Override
+ public String generateGreeting() {
+ String weatherGreeting = getWeatherGreeting();
+ return weatherGreeting + "! " + greetingService.getGenericGreeting();
+ }
+
+ private String getWeatherGreeting() {
+ WeatherCondition currentWeather = weatherService.getCurrentWeather();
+ return switch (currentWeather) {
+ case SUNNY -> "What a good sunny day!";
+ case RAINY -> "What a rainy day!";
+ case CLOUDY -> "What a cloudy day!";
+ case FOGGY -> "What a foggy day!";
+ default -> {
+ LOGGER.error("Unexpected weather condition: {}", currentWeather);
+ yield "unexpected weather condition";
+ }
+ };
+ }
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/WeatherServiceImpl.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/WeatherServiceImpl.java
new file mode 100644
index 000000000000..26ab7453032e
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/classes/WeatherServiceImpl.java
@@ -0,0 +1,17 @@
+package com.iluwatar.soa.services.classes;
+
+import com.iluwatar.soa.model.WeatherCondition;
+import java.util.Random;
+import com.iluwatar.soa.services.interfaces.WeatherService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class WeatherServiceImpl implements WeatherService {
+ private final Random random = new Random();
+
+ public WeatherCondition getCurrentWeather() {
+ WeatherCondition[] conditions = WeatherCondition.values();
+ int randomConditionIndex = random.nextInt(conditions.length);
+ return conditions[randomConditionIndex];
+ }
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/config/ServiceConfiguration.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/config/ServiceConfiguration.java
new file mode 100644
index 000000000000..4272161c89e3
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/config/ServiceConfiguration.java
@@ -0,0 +1,42 @@
+package com.iluwatar.soa.services.config;
+
+import com.iluwatar.soa.services.classes.GreetingServiceImpl;
+import com.iluwatar.soa.services.classes.PersonalizedGreetingServiceImpl;
+import com.iluwatar.soa.services.classes.WeatherServiceImpl;
+import com.iluwatar.soa.services.interfaces.GreetingService;
+import com.iluwatar.soa.services.interfaces.PersonalizedGreetingService;
+import com.iluwatar.soa.services.interfaces.WeatherService;
+import com.iluwatar.soa.services.registry.ServiceRegistry;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public final class ServiceConfiguration {
+
+ private ServiceConfiguration() {
+ throw new IllegalStateException("Utility class");
+ }
+
+ public static void configureAndRegisterServices() {
+ LOGGER.info("Configuring and registering services...");
+
+ GreetingService greetingService = new GreetingServiceImpl();
+ WeatherService weatherService = new WeatherServiceImpl();
+ PersonalizedGreetingService personalizedGreetingService =
+ new PersonalizedGreetingServiceImpl(greetingService, weatherService);
+
+ ServiceRegistry.registerService("greetingService", greetingService);
+ ServiceRegistry.registerService("weatherService", weatherService);
+ ServiceRegistry.registerService("personalizedGreetingService", personalizedGreetingService);
+
+ LOGGER.info("Services configured and registered successfully.");
+
+ logServiceRegistry();
+ }
+
+ private static void logServiceRegistry() {
+ LOGGER.info("Current service registry:");
+ ServiceRegistry.registry.forEach(
+ (serviceName, serviceInstance) -> LOGGER.info("- {} : {}", serviceName,
+ serviceInstance.getClass().getName()));
+ }
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/GreetingService.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/GreetingService.java
new file mode 100644
index 000000000000..3013c79f5f5a
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/GreetingService.java
@@ -0,0 +1,7 @@
+package com.iluwatar.soa.services.interfaces;
+
+public interface GreetingService {
+
+ String getGenericGreeting();
+
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/PersonalizedGreetingService.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/PersonalizedGreetingService.java
new file mode 100644
index 000000000000..8f8726aa204c
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/PersonalizedGreetingService.java
@@ -0,0 +1,7 @@
+package com.iluwatar.soa.services.interfaces;
+
+public interface PersonalizedGreetingService {
+
+ String generateGreeting();
+
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/WeatherService.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/WeatherService.java
new file mode 100644
index 000000000000..effe780fc13d
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/interfaces/WeatherService.java
@@ -0,0 +1,7 @@
+package com.iluwatar.soa.services.interfaces;
+
+import com.iluwatar.soa.model.WeatherCondition;
+
+public interface WeatherService {
+ WeatherCondition getCurrentWeather();
+}
diff --git a/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/registry/ServiceRegistry.java b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/registry/ServiceRegistry.java
new file mode 100644
index 000000000000..84449948cd5b
--- /dev/null
+++ b/service-oriented-architecture/src/main/java/com/iluwatar/soa/services/registry/ServiceRegistry.java
@@ -0,0 +1,17 @@
+package com.iluwatar.soa.services.registry;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ServiceRegistry {
+ public static final Map registry = new ConcurrentHashMap<>();
+
+ public static void registerService(String serviceName, T serviceInstance) {
+ registry.put(serviceName, serviceInstance);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T getService(String serviceName) {
+ return (T) registry.get(serviceName);
+ }
+}
diff --git a/service-oriented-architecture/src/main/resources/application.properties b/service-oriented-architecture/src/main/resources/application.properties
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/service-oriented-architecture/src/main/resources/static/NameGreeting.html b/service-oriented-architecture/src/main/resources/static/NameGreeting.html
new file mode 100644
index 000000000000..566549bdf8fa
--- /dev/null
+++ b/service-oriented-architecture/src/main/resources/static/NameGreeting.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Title
+
+
+
+
+
\ No newline at end of file
diff --git a/service-oriented-architecture/src/main/resources/static/WeatherGreeting.html b/service-oriented-architecture/src/main/resources/static/WeatherGreeting.html
new file mode 100644
index 000000000000..fb4496d6015e
--- /dev/null
+++ b/service-oriented-architecture/src/main/resources/static/WeatherGreeting.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ SOA Services
+
+
+
+Welcome to your services!
+Select a service:
+
+
+