https://medium.com/@codingwinner/19-developer-tools-that-keep-me-productive-b1b745412465
Wednesday, 7 August 2024
Monday, 5 August 2024
strategy design pattern example in java
The Strategy Design Pattern is a behavioral pattern that enables us to select an algorithm’s behavior at runtime. This pattern lets us define a set of algorithms, place them in different classes, and makes them interchangeable [1].
This is just a definition but let’s get a better understanding by knowing the problem that we are trying to solve.
The Problem
Let’s say you are working on a feature called File Parser. You need to write an API where you can upload a file and our system should be able to extract the data from it and persist them in the database. Currently we are asked to support CSV, JSON and XML files. Our immediate solution would look something like below.
@Service
public class FileParserService {
public void parse(File file, String fileType) {
if (Objects.equals(fileType, "CSV")) {
// TODO : a huge implementation to parse CSV file and persist data in db
} else if (Objects.equals(fileType, "JSON")) {
// TODO : a huge implementation to parse JSON file and persist data in db
} else if (Objects.equals(fileType, "XML")) {
// TODO : a huge implementation to parse XML file and persist data in db
} else {
throw new IllegalArgumentException("Unsupported file type");
}
}
} Everything looks good now from the business perspective but things will start getting uglier when we want to support more file types in the future. We start adding multiple else if blocks and the size of the class will quickly grow which will eventually become too hard to maintain. Any change to one of the implementations of the file parser will affect the whole class thereby increasing the chance of introducing a bug in an already working functionality.
Not only that, but there is another problem. Let’s say now we need to additionally support sqlite and parquet file types. Two developers will step in and they will start working on the same huge class. It is highly likely that they will get merge conflicts which is not only irritating for any developer but also time consuming to resolve them. Most importantly, even after the conflict resolution, there would be decreased confidence in terms of the feature working as a whole.
The Solution
This is where the Strategy Design pattern steps in to our rescue. We will move all the file parser implementations to separate classes called strategies. In the current class, we shall dynamically fetch the appropriate implementation based on file type and execute the strategy.
Here’s a UML diagram to provide a high-level overview of the design pattern that we are about to implement.
Now, let’s just dive into the code.
We will need a class to maintain different file types supported. Later we will use this to create spring beans (i.e. strategies) with custom names.
public class FileType {
public static final String CSV = "CSV";
public static final String XML = "XML";
public static final String JSON = "JSON";
}Create an interface for our File Parser
public interface FileParser {
void parse(File file);
}Now that we have created an interface, let’s create different implementations for different file types i.e. strategies
@Service(FileType.CSV)
public class CsvFileParser implements FileParser {
@Override
public void parse(File file) {
// TODO : impl to parse csv file
}
}@Service(FileType.JSON)
public class JsonFileParser implements FileParser {
@Override
public void parse(File file) {
// TODO : impl to parse json file
}
}@Service(FileType.XML)
public class XmlFileParser implements FileParser {
@Override
public void parse(File file) {
// TODO : impl to parse xml file
}
}Notice that we have given custom names for the above beans which will help us inject all these three beans to our required class.
Now we need to find a way to choose one of the above implementations based on file type during runtime.
Let’s create a FileParserFactory class. This class is responsible in deciding which implementation to choose given a file type. We will leverage spring boot’s awesome dependency injection feature to fetch the appropriate strategy during runtime. (Refer the comments in the below code block for more details or [2])
@Component
@RequiredArgsConstructor
public class FileParserFactory {
/**
* Spring boot's dependency injection feature will construct this map for us
* and include all implementations available in the map with the key as the bean name
* Logically, the map will look something like below
* {
* "CSV": CsvFileParser,
* "XML": XmlFileParser,
* "JSON": JsonFileParser
* }
*/
private final Map<String, FileParser> fileParsers;
/**
* Return's the appropriate FileParser impl given a file type
* @param fileType one of the file types mentioned in class FileType
* @return FileParser
*/
public FileParser get(String fileType) {
FileParser fileParser = fileParsers.get(fileType);
if (Objects.isNull(fileParser)) {
throw new IllegalArgumentException("Unsupported file type");
}
return fileParser;
}
}Now, let’s make changes to our FileParserService. We will use our FileParserFactory to fetch the appropriate FileParser based on the fileType and call the parse method.
@Service
@RequiredArgsConstructor
public class FileParserService {
private final FileParserFactory fileParserFactory;
public void parse(File file, String fileType) {
FileParser fileParser = fileParserFactory.get(fileType);
fileParser.parse(file);
}
}That’s it. We are done!
Thursday, 1 August 2024
@JsonProperty at DAO layer
@JsonProperty at DAO layer will not work some time.
If you want to map data in proper way use. Bean field name as same as table name.
If your columan name is player_name in table
and in bean if you mention like this
@JsonBeanProperty("player_name")
private String playerFirstName
then data will not mapp .
Make it same as player_name just remove _ with camplecase .
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
public class DummyClass {
@JsonProperty("leaderboard_requested_to_setcurrent")
private String leaderboardRequestedToSetCurrent;
@JsonProperty("workos_conn_id")
private String workConnId;
@JsonProperty("workos_org_id")
private String workOrgId;
@JsonProperty("workos_sso_enable")
private Integer workSsoEnable;
}
when I am using @JsonProperty.
jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(DummyClass.class), companyId);
I am getting null but when I am using
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
public class DummyClass {
private String leaderboard_requested_to_setcurrent;
private String workos_conn_id;
private String workos_org_id;
private Integer workos_sso_enable;
}
Working class
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
public class DummyClass {
@JsonProperty("leaderboard_requested_to_setcurrent")
private String leaderboardRequestedToSetCurrent;
@JsonProperty("workos_conn_id")
private String workosConnId;
@JsonProperty("workos_org_id")
private String workosOrgId;
@JsonProperty("workos_sso_enable")
private Integer workosSsoEnable;
@JsonProperty("leaderboard_scheduled_on")
private String leaderboardScheduledOn;
}
Thursday, 25 July 2024
Java JWT example
package com.codewalla.hrms.authentication.controller;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Date;
public class JWTExample {
public static void main(String[] args) {
int keyLengthBytes = 64;
SecureRandom secureRandom = new SecureRandom();
byte[] keyBytes = new byte[keyLengthBytes];
secureRandom.nextBytes(keyBytes);
String secretKey = Base64.getUrlEncoder().withoutPadding().encodeToString(keyBytes);
String jws = Jwts.builder()
.setSubject("user123")
.setIssuer("example.com")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hour expiration
.signWith(SignatureAlgorithm.HS256,secretKey)
.compact();
System.out.println("Generated JWT: " + jws);
try {
Jws<Claims> claimsJws = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jws);
Claims claims = claimsJws.getBody();
System.out.println("Subject: " + claims.getSubject());
System.out.println("Issuer: " + claims.getIssuer());
System.out.println("Expiration: " + claims.getExpiration());
} catch (Exception e) {
System.out.println("Invalid JWT: " + e.getMessage());
}
}
}
communication between two docker container
To enable communication between two Docker containers, you can use Docker networks. Docker networks allow containers to discover and communicate with each other. Here are the steps to set up communication between two Docker containers:
1. Create a Docker Network
First, create a custom Docker network. This will allow your containers to communicate with each other using their container names as hostnames.
shdocker network create my_network2. Run Containers on the Same Network
Run your containers and attach them to the network you just created.
For example, if you have two containers named
container1andcontainer2:shdocker run -d --name container1 --network my_network my_image1
docker run -d --name container2 --network my_network my_image23. Verify Network Connectivity
You can verify that the containers are on the same network by running:
docker network inspect my_network
This command will show you details about the network, including the containers attached to it.
4. Test Communication
To test the communication between the containers, you can use the
docker execcommand to enter one container and ping the other.For example, from
container1, you can pingcontainer2:docker exec -it container1 ping container2
version: '3'
services:
container1:
image: my_image1
networks:
- my_network
container2:
image: my_image2
networks:
- my_network
networks:
my_network:
driver: bridge
Friday, 12 July 2024
python docker deployment
Run comand
FROM python:3.9-slim
WORKDIR /app
COPY ai-quiz-service/requirements.txt .
COPY config/dev.env /app/.env
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ app/
ENV PYTHONPATH=/app
EXPOSE 8088
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8088"]
FROM python:3.10
# Set the working directory in the container
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# Define build argument for the environment file
ARG ENV_FILE
# Copy the environment file from the build context to the container
COPY ${ENV_FILE} /app/.env
# Make port 80 available to the world outside this container
EXPOSE 8088
# Ensure the PYTHONPATH includes the /app directory
ENV PYTHONPATH=/app
# Run app.py when the container launches
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8088"]