Notes

My latest writings


Friday, July 5, 2024

Building a E-commerce Microservices Architecture with Spring Boot and Spring Cloud


In this article, we will walk through the creation of a scalable microservices architecture for an e-commerce application using Java Spring Boot and Spring Cloud. The architecture includes several services such as Config Server, Eureka Server, API Gateway, Auth Service, Order Service, Inventory Service, and Notification Service with Kafka.

Project Structure

The project is organized into the following structure:
ecommerce-microservices
├── config-server
├── eureka-server
├── api-gateway
├── auth-service
├── order-service
├── inventory-service
├── notification-service
├── docker-compose.yml (optional)
└── README.md
        

Config Server

The Config Server manages external configurations for all microservices.
config-server/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>config-server</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
config-server/src/main/resources/application.yml
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo
        
config-server/src/main/java/com/example/configserver/ConfigServerApplication.java
package com.example.configserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
        

Why Use Config Server?

Config Server provides a centralized place to manage external properties for applications across all environments. It uses a Git repository to store configuration files, making it easy to version and manage configurations.

How to Deploy and Run Config Server

To deploy the Config Server, ensure you have a Git repository with configuration files. Then, run the application using:
mvn spring-boot:run
This will start the Config Server on port 8888.

Eureka Server

The Eureka Server is a service registry for locating services.
eureka-server/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>eureka-server</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
eureka-server/src/main/resources/application.yml
server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
  instance:
    hostname: localhost
        
eureka-server/src/main/java/com/example/eurekaserver/EurekaServerApplication.java
package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
        

Why Use Eureka Server?

Eureka Server acts as a discovery server for registering and locating microservices. This helps in load balancing and makes it easier to scale services dynamically.

How to Deploy and Run Eureka Server

To deploy the Eureka Server, run the application using:
mvn spring-boot:run
This will start the Eureka Server on port 8761.

API Gateway

The API Gateway routes requests to appropriate services.
api-gateway/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>api-gateway</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth.boot</groupId>
            <artifactId>spring-security-oauth2-autoconfigure</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
api-gateway/src/main/resources/application.yml
server:
  port: 8080

spring:
  application:
    name: api-gateway

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: http://localhost:9000/oauth2/default/.well-known/jwks.json
        
api-gateway/src/main/java/com/example/apigateway/ApiGatewayApplication.java
package com.example.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@SpringBootApplication
@EnableEurekaClient
@EnableResourceServer
public class ApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}
        
api-gateway/src/main/java/com/example/apigateway/config/SecurityConfig.java
package com.example.apigateway.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@Configuration
@EnableResourceServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/h2-console/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .csrf().disable()
            .headers().frameOptions().disable();
    }
}
        

Why Use API Gateway?

The API Gateway handles requests by routing them to the appropriate microservice. It provides a single entry point for the client and helps in securing and managing requests efficiently.

How to Deploy and Run API Gateway

To deploy the API Gateway, run the application using:
mvn spring-boot:run
This will start the API Gateway on port 8080.

Auth Service

The Auth Service handles authentication and authorization using OAuth2.
auth-service/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>auth-service</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
auth-service/src/main/resources/application.yml
server:
  port: 9000

spring:
  application:
    name: auth-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driverClassName: org.h2.Driver
    username: sa
    password: password

spring:
  h2:
    console:
      enabled: true

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.H2Dialect
        
auth-service/src/main/java/com/example/authservice/AuthServiceApplication.java
package com.example.authservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;

@SpringBootApplication
@EnableEurekaClient
@EnableAuthorizationServer
public class AuthServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthServiceApplication.class, args);
    }
}
        
auth-service/src/main/java/com/example/authservice/config/AuthorizationServerConfig.java
package com.example.authservice.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("client-id")
                .secret("{noop}client-secret")
                .authorizedGrantTypes("password", "authorization_code", "refresh_token")
                .scopes("read", "write")
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(36000);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }
}
        
auth-service/src/main/java/com/example/authservice/config/WebSecurityConfig.java
package com.example.authservice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    @Override
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build());
        return manager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .permitAll();
    }
}
        

Why Use Auth Service?

The Auth Service handles user authentication and authorization using OAuth2. It provides secure access to resources by issuing JWT tokens.

How to Deploy and Run Auth Service

To deploy the Auth Service, run the application using:
mvn spring-boot:run
This will start the Auth Service on port 9000.

Order Service

The Order Service manages orders within the e-commerce application.
order-service/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>order-service</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
order-service/src/main/resources/application.yml
server:
  port: 9001

spring:
  application:
    name: order-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driverClassName: org.h2.Driver
    username: sa
    password: password

spring:
  h2:
    console:
      enabled: true

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.H2Dialect

spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: order-group
        
order-service/src/main/java/com/example/orderservice/OrderServiceApplication.java
package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
        
order-service/src/main/java/com/example/orderservice/model/Order.java
package com.example.orderservice.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String product;
    private int quantity;
    private double price;

    // Getters and setters
}
        
order-service/src/main/java/com/example/orderservice/repository/OrderRepository.java
package com.example.orderservice.repository;

import com.example.orderservice.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}
        
order-service/src/main/java/com/example/orderservice/controller/OrderController.java
package com.example.orderservice.controller;

import com.example.orderservice.model.Order;
import com.example.orderservice.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    private static final String TOPIC = "order-topic";

    @PostMapping
    public Order createOrder(@RequestBody Order order) {
        Order savedOrder = orderRepository.save(order);
        kafkaTemplate.send(TOPIC, "Order created: " + savedOrder.getId());
        return savedOrder;
    }

    @GetMapping("/{id}")
    public Order getOrder(@PathVariable Long id) {
        return orderRepository.findById(id).orElse(null);
    }
}
        

Why Use Order Service?

The Order Service manages all operations related to orders. It uses Kafka to send notifications whenever an order is created.

How to Deploy and Run Order Service

To deploy the Order Service, run the application using:
mvn spring-boot:run
This will start the Order Service on port 9001.

Inventory Service

The Inventory Service manages product inventory within the e-commerce application.
inventory-service/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>inventory-service</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
        
inventory-service/src/main/resources/application.yml
server:
  port: 9002

spring:
  application:
    name: inventory-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driverClassName: org.h2.Driver
    username: sa
    password: password

spring:
  h2:
    console:
      enabled: true

spring:
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.H2Dialect

spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: inventory-group
        
inventory-service/src/main/java/com/example/inventoryservice/InventoryServiceApplication.java
package com.example.inventoryservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class InventoryServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(InventoryServiceApplication.class, args);
    }
}
        
inventory-service/src/main/java/com/example/inventoryservice/model/Inventory.java
package com.example.inventoryservice.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Inventory {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String product;
    private int quantity;

    // Getters and setters
}
        
inventory-service/src/main/java/com/example/inventoryservice/repository/InventoryRepository.java
package com.example.inventoryservice.repository;

import com.example.inventoryservice.model.Inventory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface InventoryRepository extends JpaRepository<Inventory, Long> {
}
        
inventory-service/src/main/java/com/example/inventoryservice/controller/InventoryController.java
package com.example.inventoryservice.controller;

import com.example.inventoryservice.model.Inventory;
import com.example.inventoryservice.repository.InventoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/inventory")
public class InventoryController {

    @Autowired
    private InventoryRepository inventoryRepository;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    private static final String TOPIC = "inventory-topic";

    @PostMapping
    public Inventory addInventory(@RequestBody Inventory inventory) {
        Inventory savedInventory = inventoryRepository.save(inventory);
        kafkaTemplate.send(TOPIC, "Inventory added: " + savedInventory.getId());
        return savedInventory;
    }

    @GetMapping("/{id}")
    public Inventory getInventory(@PathVariable Long id) {
        return inventoryRepository.findById(id).orElse(null);
    }
}
        

Why Use Inventory Service?

The Inventory Service manages all operations related to inventory. It uses Kafka to send notifications whenever inventory is updated.

How to Deploy and Run Inventory Service

To deploy the Inventory Service, run the application using:
mvn spring-boot:run
This will start the Inventory Service on port 9002.

Communication Between Services

Microservices communicate using REST APIs and Apache Kafka for asynchronous messaging. Services are registered with Eureka and communicate via Eureka Server.

Testing

Unit and integration tests are implemented using Spring Boot Test.
Example test class:
order-service/src/test/java/com/example/orderservice/OrderServiceApplicationTests.java
package com.example.orderservice;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class OrderServiceApplicationTests {

    @Test
    void contextLoads() {
    }

}
        

Directory Structure

Here's the complete directory structure for the project:
ecommerce-microservices/
├── api-gateway/
│   ├── src/main/java/com/example/apigateway/ApiGatewayApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── auth-service/
│   ├── src/main/java/com/example/authservice/AuthController.java
│   ├── src/main/java/com/example/authservice/AuthServiceApplication.java
│   ├── src/main/java/com/example/authservice/SecurityConfig.java
│   ├── src/main/java/com/example/authservice/User.java
│   ├── src/main/java/com/example/authservice/UserRepository.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── config-server/
│   ├── src/main/java/com/example/configserver/ConfigServerApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── eureka-server/
│   ├── src/main/java/com/example/eurekaserver/EurekaServerApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── inventory-service/
│   ├── src/main/java/com/example/inventoryservice/InventoryController.java
│   ├── src/main/java/com/example/inventoryservice/Inventory.java
│   ├── src/main/java/com/example/inventoryservice/InventoryRepository.java
│   ├── src/main/java/com/example/inventoryservice/InventoryServiceApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── notification-service/
│   ├── src/main/java/com/example/notificationservice/KafkaConsumerConfig.java
│   ├── src/main/java/com/example/notificationservice/KafkaListenerService.java
│   ├── src/main/java/com/example/notificationservice/NotificationServiceApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── order-service/
│   ├── src/main/java/com/example/orderservice/OrderController.java
│   ├── src/main/java/com/example/orderservice/Order.java
│   ├── src/main/java/com/example/orderservice/OrderRepository.java
│   ├── src/main/java/com/example/orderservice/OrderServiceApplication.java
│   ├── src/main/resources/application.yml
│   └── pom.xml
├── docker-compose.yml (optional)
└── README.md

Tuesday, March 1, 2016

10 Articles Every Programmer Must Read

Being a Java programmer and Software developer, I have learned a lot from articles titled as What Every Programmer Should Know about ..... , they tend to give a lot of useful and in-depth information about a particular topic, which otherwise is very hard to discover. In my quest of learning I have come across some very useful articles, which I have bookmarked for reference and multiple reading. I personally think that all programmer can benefit by reading these articles, which makes me write this post and share all of these "What Every Programmer Should Know" articles with you guys. These are from my personal bookmarks. In this article, you will see classic what every programmer should know article from topics like memory, Unicode, floating point arithmetic, networking, object oriented design, time, URL Encoding, String and many more. This list is very important for beginner and newcomers, as they are the ones, who lacks practical knowledge. Since most of these post are actually driven by practical knowledge, beginner and intermediate programmers can take a lot from it. Also gaining knowledge of fundamentals early in career helps to avoid mistakes, which has done by other programmers and software developers on their course of learning. Though it’s not easy to grasp all knowledge given in these articles in just one reading. You probably won't understand some details about floating point number or get confused with subtle details of memory, but it’s important to keep these list handy and refer them time to time with a context. So Good luck and Enjoy reading these wonderful articles.  By the way, don't forget to share any What Every Programmer Should know article, if it’s not already in this list.


This is one of the classic article, which will take you through may lanes of memory, some old, some new, some known and some unknown. Despite being so conman and omnipresent, not every programmer have enough knowledge of Memory. Knowledge of memory in modern system becomes even more important if you are in space of writing high performance application. Hardware designers have come up with ever more sophisticated memory handling and acceleration techniques–such as CPU caches–but these cannot work optimally without some help from the programmer. I am still reading this article, and I can't tell you how much I have learned from this about RAM, CPU Caches e.g. L1 and L2 cache, different types of memory, direct memory access, memory controller designs and Memory in general. In short, a must read for programmers of all level of experience.


Floating point arithmetic is a tricky topic, and it’s not easy to master. Even many Java programmer doesn't know what can go wrong when comparing float/double value with == operator. Many of us often makes mistake of doing monetary calculation in float and double. This article is another gem of this series and must read for all software developers and programmers. As your experience grows, you are expected to know subtle details of common things, and floating point arithmetic is one of them. As as senior Java developer, you must know how do perform monetary calculation, when to use float, double or BigDecimal classes, how to round floating point numbers etc. Even if you know fundamentals of floating point arithmetic, You will learn something new about floating point calculation by reading this article.


Character encoding is another area, where many programmer struggle, and "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)" aims to fill that gap. On side note, Yes that's the full title of that article. It was written by Joel Spolsky, one of the founder of statckoverflow.com. Joel has written this post on his blog almost 10 years back, but it is still relevant in today’s world. This article will teach you about What is Unicode, What is character encoding, how characters are represented using bytes and many more. One of the best thing about this article is language and flow, even if you don't know anything about Unicode, you can easily follow. In short, one more must read for all programmers, coders and software engineers.


Apart from Character encoding, time and date is another area, where many programmers struggle, including me. Even senior developers lost between GMT, UTC, day light saving and between leap seconds. Frankly speaking, It's not easy to deal with time zones without making any mistake, then add day light savings and effect of that. Problems becomes worse if you using trial and error method, because you will never able to solve your problem by doing that. There are so many things which can go wrong and there are equal number of misconceptions. Things like, whether date contains time-zone or not can confuse you like hell, converting UNIX time to other time-zone can freak you out, forget about clock synchronization and delays. I hope many of your misconception about time will go away and you will build sound fundamental about Time, by reading this classic article.


This article describes common misconceptions about Uniform Resource Locator (URL) encoding, then attempts to clarify URL encoding for HTTP, before presenting frequent problems and their solutions. While this article is not specific to any programming language, it illustrate the problems in Java) and finish by explaining how to fix URL encoding problems in Java, and in a web application at several levels. You will learn basics of URL grammar, general URL syntax in HTTP and other protocol. This article also explores common pitfalls of URLs e.g. character encoding, reserved character at different part of URL, and URL encoding/decoding issues. If you are a Java programmer, then you will also learn about how to handle URLs in Java application, the right way. How to construct URL and using Apache commons HTTP client library. Finally it also suggest best practices or dealing with URLs e.g. you should encode URLs when you build them, making sure your URL-rewrite filters deal with your URL correctly and many more. In short, a must read article for any web developer and programmer.



This is an interesting article from programmers stack exchange, about what should every programmer implementing the technical details of a web application consider before making the site public. This includes things ranging from Interface design and User Experience, Security, Web standards, Performance, Search Engine Optimization(SEO), Technology involved, and about several important resources. Since today's world is hugely dependent upon internet and programmer having their personal site, blog is quite common. Experience learned on this article will not even help in your professional work but also in your personal work. You will learn about all key technology e.g. HTTP, HTML, XML, CSS, JavaScript, browsers compatibility, tips to reduce loading time of your website, XML sitemaps, W3C specifications and several other key details.


This is another article, which is very important for web developers, programmers and blogger. SEO is too big to ignore, since many programmers are also blogger, it’s important to learn few basics of Search Engine Optimization to help Google find their content and present to other fellow programmers. Since no company can survive without web presence in today's inter-connected world, SEO becomes even more important. If you own start-up, selling any product, then SEO is something to care about. All programmers, especially web developers can largely benefit from this article. Remember, Search Engine Optimization is vast and very dynamic subject, and also varies between different search engines e.g. Google, Yahoo, and others. So, In order to master this topic you will always need to update your knowledge.


C programming language have the concept of "undefined behaviour". Undefined behaviour is a broad topic with a lot of nuances and that's one reason of Why I like Java, less number of undefined behaviour, less confusion, more stability and more peace. Many seemingly reasonable things in C actually have undefined behaviour, and this is a common source of bugs in programs. Beyond that, any undefined behaviour in C gives license to the implementation (the compiler and runtime) to produce code that formats your hard drive, does completely unexpected things, or worse. Read this excellent article to deep dive on sea of undefined behaviour


From the article itself "You’re a programmer. Have you ever wondered how multi-player games work? From the outside it seems magical: two or more players sharing a consistent experience across the network like they actually exist together in the same virtual world. But as programmers we know the truth of what is actually going on underneath is quite different from what you see. It turns out that it’s all an illusion." This is very interesting article about networking, written for game programmers but I think every programmer and developer can benefit from this.


This is my article on java.lang.String and what I personally thing every Java programmer should know about it. String is very important in day to day programming in Java and that's why good knowledge is must for any Java developer. This article touches many important areas of String including string pool, string literal, comparing String using == vs equals(), converting bytes to String, Why String is immutable, properly concatenating Strings and many more. Advanced programmer may already know all these stuffs but even then it’s good to revise them.


This question was ask by one computer programming student in StackOverFlow. Just like we learn a lot about general programming concepts e.g. operating system, algorithm, data-structure, computer architecture, and other stuff, its also important to know about security. Though Security is vast topic ranging from encryption/decryption, SSL, web security, obfuscation, authentication, authorization etc, a basic minimum knowledge is must for every programmer. I personally didn't know much about Security when I started my career, its when I start writing Servlet/JSP based Java web application, I come to know about web security and several security threats like SQL Injection, Denial of Service, XML Injection, Cross site scripting and others. As Java developer, now I follow secure Java coding practices provided by fortify, PMP and other static code analysis providers.  This article is very good collection of topics and links about Security and whether you are doing coding or not, you will surely benefit from this resource.


This is the bonus article, but must read for every Programmer. In order to write high performance application in any programming language e.g. Java or C++, you ought to know fundamental latency numbers e.g. how much time it take to read a variable from memory, from L1 Cache, from L2 cache, from random read in SSD and from disk. How much time it take to lock unlock on mutex, to send a data packet from one city to another or doing a roundtrip on same data centre. These latency numbers are independent of any programming language and part of core knowledge, a developer must have to write high frequency low latency applications. Good thing about this link is that it also provides you comparative analysis of how these latency numbers have evolved over the years. You can see what these latency numbers were in 2006 and what they are now.


That's all in this list of article every Programmer must read. By reading articles titles as What Every Programmer or Developer Should know, you gain in-depth knowledge of a particular topic. Frankly speaking there are too many things to learn for programmers, learning a programming language like Java is just a tip of iceberg, but isn't it many of us have passion for learning. Programming is a challenging job, and only things which help you all along your career is fundamental knowledge e.g. things about Memory, Unicode, floating point numbers, time, security is very important for any programmer, but they are still good to learn for many beginner and developers.


article first appeared @javarevisited

Friday, June 26, 2020

Java Security: Illegal key size or default parameters.?

The Problem

Java 1.6.0.12 installed on my Linux server and the code below runs just perfectly.
String key = "av45k1pfb024xa3bl359vsb4esortvks74sksr5oy4s5serondry84jsrryuhsr5ys49y5seri5shrdliheuirdygliurguiy5ru";
try {
    Cipher c = Cipher.getInstance("ARCFOUR");

    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "ARCFOUR");
    c.init(Cipher.DECRYPT_MODE, secretKeySpec);

    return new String(c.doFinal(Hex.decodeHex(data.toCharArray())), "UTF-8");

} catch (InvalidKeyException e) {
    throw new CryptoException(e);
}

When installed Java 1.6.0.26 on my server user and when I try to run my application, I get the following exception. My guess would be that it has something to do with the Java installation configuration because it works in the first one, but doesn't work in the later version.I keep getting this Error. 

Caused by: java.security.InvalidKeyException: Illegal key size or default parameters
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.a(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.init(DashoA13*..) ~[na:1.6]
    at javax.crypto.Cipher.init(DashoA13*..) ~[na:1.6]
    at my.package.Something.decode(RC4Decoder.java:25) ~[my.package.jar:na]
    ... 5 common frames omitted

Solution

Most likely you don't have the unlimited strength file installed now. 
Extract the jar files from the zip and save them in ${java.home}/jre/lib/security/

This is a code only solution. No need to download or mess with configuration files. It's a reflection based solution, tested on java 8 Call this method once, early in your program.
 //Imports

import javax.crypto.Cipher;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
//method

public static void fixKeyLength() {
    String errorString = "Failed manually overriding key-length permissions.";
    int newMaxKeyLength;
    try {
        if ((newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES")) < 256) {
            Class c = Class.forName("javax.crypto.CryptoAllPermissionCollection");
            Constructor con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Object allPermissionCollection = con.newInstance();
            Field f = c.getDeclaredField("all_allowed");
            f.setAccessible(true);
            f.setBoolean(allPermissionCollection, true);

            c = Class.forName("javax.crypto.CryptoPermissions");
            con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Object allPermissions = con.newInstance();
            f = c.getDeclaredField("perms");
            f.setAccessible(true);
            ((Map) f.get(allPermissions)).put("*", allPermissionCollection);

            c = Class.forName("javax.crypto.JceSecurityManager");
            f = c.getDeclaredField("defaultPolicy");
            f.setAccessible(true);
            Field mf = Field.class.getDeclaredField("modifiers");
            mf.setAccessible(true);
            mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
            f.set(null, allPermissions);

            newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
        }
    } catch (Exception e) {
        throw new RuntimeException(errorString, e);
    }
    if (newMaxKeyLength < 256)
        throw new RuntimeException(errorString); // hack failed
}
  
Follow this stackoverflow.com Q&A discussion for more information    
© Delthas

Tuesday, July 12, 2016

Basics about Linux File Permissions


In this section we'll learn about how to set Linux permissions on files and directories. Permissions specify what a particular person may or may not do with respect to a file or directory. As such, permissions are important in creating a secure environment. For instance you don't want other people to be changing your files and you also want system files to be safe from damage (either accidental or deliberate). Luckily, permissions in a Linux system are quite easy to work with.

So what are they?

Linux permissions dictate 3 things you may do with a file, read, write and execute. They are referred to in Linux by a single letter each.
  • r read - you may view the contents of the file.
  • w write - you may change the contents of the file.
  • x execute - you may execute or run the file if it is a program or script.
For every file we define 3 sets of people for whom we may specify permissions.
  • owner - a single person who owns the file. (typically the person who created the file but ownership may be granted to some one else by certain users)
  • group - every file belongs to a single group.
  • others - everyone else who is not in the group or the owner.
Three permissions and three groups of people. That's about all there is to permissions really. Now let's see how we can view and change them.

View Permissions

To view permissions for a file we use the long listing option for the command ls.
ls -l [path]
  1. ls -l /home/ryan/linuxtutorialwork/frog.png
  2. -rwxr----x 1 harry users 2.7K Jan 4 07:32 /home/ryan/linuxtutorialwork/frog.png
In the above example the first 10 characters of the output are what we look at to identify permissions.
  • The first character identifies the file type. If it is a dash ( - ) then it is a normal file. If it is a d then it is a directory.
  • The following 3 characters represent the permissions for the owner. A letter represents the presence of a permission and a dash ( - ) represents the absence of a permission. In this example the owner has all permissions (read, write and execute).
  • The following 3 characters represent the permissions for the group. In this example the group has the ability to read but not write or execute. Note that the order of permissions is always read, then write then execute.
  • Finally the last 3 characters represent the permissions for others (or everyone else). In this example they have the execute permission and nothing else.

Change Permissions



To change permissions on a file or directory we use a command called chmod It stands for change file mode bits which is a bit of a mouthfull but think of the mode bits as the permission indicators.
chmod [permissions] [path]
chmod has permission arguments that are made up of 3 components
  • Who are we changing the permission for? [ugoa] - user (or owner), group, others, all
  • Are we granting or revoking the permission - indicated with either a plus ( + ) or minus ( - )
  • Which permission are we setting? - read ( r ), write ( w ) or execute ( x )
The following examples will make their usage clearer.
Grant the execute permission to the group. Then remove the write permission for the owner.
  1. ls -l frog.png
  2. -rwxr----x 1 harry users 2.7K Jan 4 07:32 frog.png
  3. chmod g+x frog.png
  4. ls -l frog.png
  5. -rwxr-x--x 1 harry users 2.7K Jan 4 07:32 frog.png
  6. chmod u-w frog.png
  7. ls -l frog.png
  8. -r-xr-x--x 1 harry users 2.7K Jan 4 07:32 frog.png
Don't want to assign permissions individually? We can assign multiple permissions at once.
  1. ls -l frog.png
  2. -rwxr----x 1 harry users 2.7K Jan 4 07:32 frog.png
  3. chmod g+wx frog.png
  4. ls -l frog.png
  5. -rwxrwx--x 1 harry users 2.7K Jan 4 07:32 frog.png
  6. chmod go-x frog.png
  7. ls -l frog.png
  8. -rwxrw---- 1 harry users 2.7K Jan 4 07:32 frog.png
It may seem odd that as the owner of a file we can remove our ability to read, write and execute that file but there are valid reasons we may wish to do this. Maybe we have a file with data in it we wish not to accidentally change for instance. While we may remove these permissions, we may not remove our ability to set those permissions and as such we always have control over every file under our ownership.

Setting Permissions Shorthand


The method outlined above is not too hard for setting permissions but it can be a little tedious if we have a specific set of permissions we should like to apply regularly to certain files (scripts for instance that we'll see in section 13). Luckily, there is a shorthand way to specify permissions that makes this easy.
To understand how this shorthand method works we first need a little background in number systems. Our typical number system is decimal. It is a base 10 number system and as such has 10 symbols (0 - 9) used. Another number system is octal which is base 8 (0-7). Now it just so happens that with 3 permissions and each being on or off, we have 8 possible combinations (2^3). Now we can also represent our numbers using binary which only has 2 symbols (0 and 1). The mapping of octal to binary is in the table below.
OctalBinary
00 0 0
10 0 1
20 1 0
30 1 1
41 0 0
51 0 1
61 1 0
71 1 1

Now the interesting point to note is that we may represent all 8 octal values with 3 binary bits and that every possible combination of 1 and 0 is included in it. So we have 3 bits and we also have 3 permissions. If you think of 1 as representing on and 0 as off then a single octal number may be used to represent a set of permissions for a set of people. Three numbers and we can specify permissions for the user, group and others. Let's see some examples. (refer to the table above to see how they match)
  1. ls -l frog.png
  2. -rw-r----x 1 harry users 2.7K Jan 4 07:32 frog.png
  3. chmod 751 frog.png
  4. ls -l frog.png
  5. -rwxr-x--x 1 harry users 2.7K Jan 4 07:32 frog.png
  6. chmod 240 frog.png
  7. ls -l frog.png
  8. --w-r----- 1 harry users 2.7K Jan 4 07:32 frog.png
People often remember commonly used number sequences for different types of files and find this method quite convenient. For example 755 or 750 are commonly used for scripts.

Permissions for Directories

The same series of permissions may be used for directories but they have a slightly different behaviour.
  • r - you have the ability to read the contents of the directory (ie do an ls)
  • w - you have the ability to write into the directory (ie create files and directories)
  • x - you have the ability to enter that directory (ie cd)
Let's see some of these in action
  1. ls testdir
  2. file1 file2 file3
  3. chmod 400 testdir
  4. ls -ld testdir
  5. -r-------- 1 ryan users 2.7K Jan 4 07:32 testdir
  6. cd testdir
  7. cd: testdir: Permission denied
  8. ls testdir
  9. file1 file2 file3
  10. chmod 100 testdir
  11. ls -ld testdir
  12. ---x------ 1 ryan users 2.7K Jan 4 07:32 testdir
  13. cd testdir
  14. ls testdir
  15. ls: cannot open directory testdir/: Permission denied
Note, on lines 5 and 14 above when we ran ls I included the -d option which stands for directory. Normally if we give ls an argument which is a directory it will list the contents of that directory. In this case however we are interested in the permissions of the directory directly and the -d option allows us to obtain that.
These permissions can seem a little confusing at first. What we need to remember is that these permissions are for the directory itself, not the files within. So, for example, you may have a directory which you don't have the read permission for. It may have files within it which you do have the read permission for. As long as you know the file exists and it's name you can still read the file.
  1. ls -ld testdir
  2. --x------- 1 ryan users 2.7K Jan 4 07:32 testdir
  3. cd testdir
  4. ls testdir
  5. ls: cannot open directory .: Permission denied
  6. cat samplefile.txt
  7. Kyle 20
  8. Stan 11
  9. Kenny 37

The root user

On a Linux system there are only 2 people usually who may change the permissions of a file or directory. The owner of the file or directory and the root user. The root user is a superuser who is allowed to do anything and everything on the system. Typically the administrators of a system would be the only ones who have access to the root account and would use it to maintain the system. Typically normal users would mostly only have access to files and directories in their home directory and maybe a few others for the purposes of sharing and collaborating on work and this helps to maintain the security and stability of the system.

Basic Security

Your home directory is your own personal space on the system. You should make sure that it stays that way.
Most users would give themselves full read, write and execute permissions for their home directory and no permissions for the group or others however some people for various reasons may have a slighly different set up.
Normally, for optimal security, you should not give either the group or others write access to your home directory, but execute without read can come in handy sometimes. This allows people to get into your home directory but not allow them to see what is there. An example of when this is used is for personal web pages.
It is typical for a system to run a webserver and allow users to each have their own web space. A common set up is that if you place a directory in your home directory called public_html then the webserver will read and display the contents of it. The webserver runs as a different user to you however so by default will not have access to get in and read those files. This is a situation where it is necessary to grant execute on your home directory so that the webserver user may access the required resources.

Summary

chmod
Change permissions on a file or directory.
ls -ld
View the permissions for a specific directory.
Security
Correct permissions are important for the security of a system.
Usage
Setting the right permissions is important in the smooth running of certain tasks on Linux. (we will see an example of this in Section 13 on scripting)

Source @ ryanstutorials.net

Works

What can I do


Branding

Social media Branding is far and away the best technique a company has to boost engagement with its customer base. Even a minimum of involvement, such as making one post a day.

Web Design

Web design is the process of creating websites. It encompasses several different aspects, including webpage layout, content production, and graphic design.

Development

Web Development refers to building, creating, and an maintaining websites. It includes aspects such as web design, web publishing, web programming and database management.

Graphic Design

Graphic design is the process of visual communication and problem-solving through the use of typography, photography, and illustration. The field is considered a subset of visual communication and communication design.

Photography

Photography is the art, application and practice of creating durable images by recording light or other electromagnetic radiation, either electronically by means of an image sensor, or chemically by means of a light-sensitive material such as photographic film.

User Experience

User experience (UX) design is the process design teams use to create products that provide meaningful and relevant experiences to users. This involves the design of the entire process of acquiring and integrating the product, including aspects of branding, design.

Contact

Get in touch with me


Adress/Street

Bangalore, India