Tuesday, February 13, 2024

Command design pattern

 When to implement ?

Suppose we have a situation ,

There are multiple action to execute based on a single value or criteria. There are several solution to do . We can use if.. else if ladder or switch case to do that  and define the action in each separate method . But if the action feature grow then we need to refactor and transfer the defined action in class . It will we time consuming . So in that situation we can implement Command design pattern like below.

 interface CampaignContactCommand {
        void execute();
    }
    
    class PauseContactCommand implements CampaignContactCommand {

        private ContactHelperNode node;

        public PauseContactCommand(ContactHelperNode node) {
            this.node = node;
        }

        @Override
        public void execute() {
            ContactPauseHelper helper = new ContactPauseHelper(node);
            helper.pauseContact();
            helper.release();
        }
    }
    
    class ResumeContactCommand implements CampaignContactCommand{

        private ContactHelperNode node;
        
        public ResumeContactCommand(ContactHelperNode node) {
            this.node = node;
        }
        
        @Override
        public void execute() {
            ContactResumeHelper helper = new ContactResumeHelper(node);
            helper.resumeContact();
            helper.release();
        }
    }
    
    class UnsubscribeContactCommand implements CampaignContactCommand {

        private ContactHelperNode node;

        public UnsubscribeContactCommand(ContactHelperNode node) {
            this.node = node;
        }

        @Override
        public void execute() {
            ContactUnSubHelper helper = new ContactUnSubHelper(node);
            helper.unSubContact();
            helper.release();
        }
    }
    
    class CampaignContactCommandFactory {
        private ContactHelperNode node;

        public CampaignContactCommandFactory(ContactHelperNode node) {
            this.node = node;
        }

        public CampaignContactCommand createCommand() {

            switch (node.getRequest().getRequestType()) {

            case PAUSE:
                return new PauseContactCommand(node);
            case RESUME:
                return new ResumeContactCommand(node);
            case UNSUB:
                return new UnsubscribeContactCommand(node);
            default:
                return null;
            }
        }
    }

Monday, December 25, 2023

Upload file to S3 api

 @Path("files")
@Log4j2
@Component
public class FileUploadController implements ConfigInterface{

    @Context
    private SecurityContext securityContext;
    
    @Inject
    private FileUploadAPIValidator paramValidator;
    
    @Path("/config")
    public Resource getConfigResource() {
        return Resource.from(ConfigController.class);
    }
    
    /**
     * @author lokman 20/11/2022
     *
     */
    @POST
    @Secured
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    @RequestTracingFilter
    public Response uploadMultipleFile(@FormDataParam("files") List<FormDataBodyPart> files, @FormDataParam("files") List<FormDataContentDisposition> fileDetails) {
        
        log.info("file size :"+ fileDetails.size());
        
        JSONObject response = new JSONObject();
        
        BasicCacheUserPrincipal userPrincipal = (BasicCacheUserPrincipal) securityContext.getUserPrincipal();

        if (userPrincipal == null || userPrincipal.getUser() == null) {
            response.put("responseCode", HttpStatus.SC_UNAUTHORIZED);
            response.put("message", "Unauthorized");
            response.put("success", Boolean.FALSE);

            return Response.status(HttpStatus.SC_UNAUTHORIZED).entity(response.toString()).build();
        }
        
        if (fileDetails.size() == 1 && StringUtil.isBlank(fileDetails.get(0).getFileName())) {

            response.put("responseCode", HttpStatus.SC_OK);
            response.put("message", "No file selected.");
            response.put("success", Boolean.FALSE);

            return Response.status(HttpStatus.SC_UNAUTHORIZED).entity(response.toString()).build();
        }
        
        if (fileDetails.size() > DefaultConfig.MAX_FILE_SIZE) {
            response.put("responseCode", HttpStatus.SC_OK);
            response.put("message", "Maximum 10 files allowed.");
            response.put("success", Boolean.FALSE);

            return Response.status(HttpStatus.SC_UNAUTHORIZED).entity(response.toString()).build();
        }
        
        List<String> fileUrls = new ArrayList<>();
        
        for (int j = 0; j < files.size(); j++) {
            
            FormDataBodyPart formDataBodyPartFile = files.get(j);
            ContentDisposition contentDispositionHeader = formDataBodyPartFile.getContentDisposition();
            InputStream fileInputStream = formDataBodyPartFile.getValueAs(InputStream.class);
            FormDataContentDisposition fileDetail = (FormDataContentDisposition) contentDispositionHeader;
            
            FileUploadAPIValidationResponse verifyResponse = paramValidator.verifyFiles(fileInputStream, fileDetail);
            
            File tempFile = null;
            if(verifyResponse.isValid()) {
                String fileName = userPrincipal.getUser().getId() + "_" + "form" + "_" + System.currentTimeMillis() + "_" + fileDetail.getFileName();
                
                log.info("fileName :"+ fileName);
                
                tempFile = new File(fileName);
                
                FileOutputStream fileOutputStream = writeToFile(verifyResponse.getInputStream(), tempFile);
                log.debug("file length : "+ tempFile.length());
                
                if ((tempFile.length() / CommonUtils.ONE_MEGABYTE_IN_BYTES) > DefaultConfig.MAX_FILE_SIZE) {
                    removeExistingFile(tempFile);
                    fileOutputStream = null;
                    continue;
                }
                
                if (fileOutputStream != null) {
                    String fileUrl = uploadFileToS3(tempFile);
                    if (StringUtil.isNotBlank(fileUrl)) {
                        log.info("fileUrl :" + fileUrl);
                        
                        fileUrls.add(fileUrl);
                    }
                }
            }
            if(tempFile != null) {
                removeExistingFile(tempFile);
            }
        }
        
        log.info("fileUrls :"+ fileUrls.size());
        
        if(fileUrls.isEmpty()) {
            response.put("responseCode", HttpStatus.SC_OK);
            response.put("message", "File upload failed.");
            response.put("success", Boolean.FALSE);
            return Response.status(HttpStatus.SC_OK).entity(response.toString()).build();
        }
        
        response.put("responseCode", HttpStatus.SC_OK);
        response.put("message", "File uploaded successfully.");
        response.put("success", Boolean.TRUE);
        response.put("urls", fileUrls);
        return Response.status(HttpStatus.SC_OK).entity(response.toString()).build();
    }
    
    /**
     * @author lokman 19/11/2022
     *
     */
    private FileOutputStream writeToFile(InputStream inputStream, File tempFile) {
        
        byte[] data = new byte[1024];

        FileOutputStream fileOutputStream = null;
        int read = 0;
        try {
            fileOutputStream = new FileOutputStream(tempFile);
            while ((read = inputStream.read(data)) != -1) {
                fileOutputStream.write(data, 0, read);
            }
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileOutputStream;
    }
    
    /**
     * @author lokman 19/11/2022
     * @param file
     */
    private String uploadFileToS3(File file) {
        try {
            String folder = S3Config.AWS3_SECTION_USER+"/";
            log.debug("Folder : "+folder);
            AWS3ApiResponse response = AWS3APIFactory.getAWS3API().uploadPublicFile(S3Config.AWS3_BUCKET_NAME, folder, file);
            log.info(" s3 upload Success : "+response.isSuccess());
            if(response.isSuccess()) {
                log.info("FileUrl : "+response.getFileUrl());
                return response.getFileUrl();
            }
        } catch (Exception e) {
            log.error("Exception : "+ e);
        }
        return null;
    }
    
    /**
     * @author lokman 19/11/2022
     * @param file
     */
    private void removeExistingFile(File file) {
        try {
            if (file.exists()) {
                boolean fileRemoved = file.delete();
                log.debug("fileRemoved : " + fileRemoved);
            }
        } catch (Exception e) {
            log.error("errorMessage ", e);
        }
    }
}

Tuesday, December 12, 2023

Bulk data insert using prepared statement

     public Optional<List<UUID>> addInBatch(List<ApiActionLogs> apiActionLogs) {
        
        if (apiActionLogs == null || apiActionLogs.isEmpty()) {
            return Optional.ofNullable(Collections.emptyList());
        }
        List<UUID> insertedUUIDList = new ArrayList<>();
        ByteArrayToUUIDConverter byteArrayToUUIDConverter = new ByteArrayToUUIDConverter();
        try (Connection connection = ConnectionUtil.getWriteConnection()) {
            connection.setAutoCommit(false);
            String sql = String.format(
                    "INSERT INTO %s (uuid, agency_id, user_id, `action`, api_bulk_action_queues_uuid, message_log, "
                    + "status, response_code, request_data, created_at, updated_at) "
                    + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", "api_action_logs ");
            
            try (PreparedStatement statement = connection.prepareStatement(sql,                                  Statement.RETURN_GENERATED_KEYS)) {
                int counter = 0;
                int batchSize = 100;
                List<UUID> batchRequests = new ArrayList<>();
                
                for (ApiActionLogs apiActionLog : apiActionLogs) {
                    if (apiActionLog == null
                            || apiActionLog.getAgencyId() == null
                            || apiActionLog.getUserId() == null
                            || apiActionLog.getApiBulkActionQueuesUuid() == null) {
                        continue;
                    }
                    statement.clearParameters();
                    apiActionLog.setUuid(UUID.randomUUID());
                    
                    statement.setBytes(1, byteArrayToUUIDConverter.to(apiActionLog.getUuid()));
                    statement.setString(2, apiActionLog.getAgencyId().toString());
                    statement.setString(3, apiActionLog.getUserId().toString());
                    statement.setString(4, apiActionLog.getAction() == null ? null : apiActionLog.getAction().name());
                    statement.setBytes(5,  byteArrayToUUIDConverter.to(apiActionLog.getApiBulkActionQueuesUuid()));
                    statement.setString(6, apiActionLog.getMessageLog());
                    statement.setString(7, apiActionLog.getStatus() == null ? null : apiActionLog.getStatus().name());
                    statement.setString(8, apiActionLog.getResponseCode());
                    statement.setString(9, apiActionLog.getRequestData() == null ? null : apiActionLog.getRequestData().toString());
                    statement.setTimestamp(10, Timestamp.valueOf(LocalDateTime.now()));
                    statement.setTimestamp(11, Timestamp.valueOf(LocalDateTime.now()));
                    
                    statement.addBatch();
                    
                    batchRequests.add(apiActionLog.getUuid());
                    
                    if ((counter + 1) % batchSize == 0 || (counter + 1) == apiActionLogs.size()) {
                        try {
                            statement.executeBatch(); // Execute Batch Operations
                            insertedUUIDList.addAll(batchRequests);
                            batchRequests.clear();
                        } catch (Exception e) {
                            log.error("Error :{}", e);
                            System.out.println("Error "+e);
                            if (!connection.isClosed()) {
                                connection.rollback();
                            }
                            batchRequests.clear();
                        }
                        
                        statement.clearBatch();
                    }
                    
                    counter++;
                }
            } catch (Exception e) {
                log.error("Error :{}", e);
                System.out.println("Error2 "+e);
                e.printStackTrace();
            }

            connection.commit(); // execute prepare statement
            
            if(!insertedUUIDList.isEmpty()) {
                
                return Optional.ofNullable(insertedUUIDList);
            }
            
        } catch (Exception e) {
            log.error("Error :{}", e);
            System.out.println("Error3 "+e);
            e.printStackTrace();
        }

        return Optional.ofNullable(Collections.emptyList());
    }

Tuesday, November 21, 2023

Chain Responsibility design pattern

 Chain Responsibility design pattern:

Chain responsibility design pattern is a behavioral design pattern . We will implement this design pattern to achieve loose coupling in software where several operation will execute one by one with same request . 

In this design pattern same request is pass through the chain until finish all the task in the chain .

Senarios: - Suppose we want to build an Notification sender application . That can notify user / developer through sms/ email etc . So we can create a class Notify user class and can implement message send logic there .  But in those logic there should have some other logic such as - loading credential information form db etc.

Another thing- in future we want to send notification to other , so respective service should execute one by one . If we don't follow a structured way and code base grows it will difficult to handle and need more refactoring .

So , we can create a chain of responsibility and execute one by one .

One service execute its work and can pass request to the next service in the chain .

Lets see the example of chain responsibility design pattern below-

1. Create an abstract class. Every service will override its execute method with same request

 AbstractService

public abstract class AbstractService {

    private AbstractService next;

    /**
     * Build the chain of objects
     */
    public static synchronized AbstractService link(AbstractService first, AbstractService... chain) {
        AbstractService head = first;
        for (AbstractService nextChain : chain) {
            head.next = nextChain;
            head = nextChain;
        }
        return first;
    }

    /**
     * Subclasses will implement this method with concrete checks.
     */
    public abstract Request execute(Request request);

    /**
     * Runs check on the next object in chain or ends traversing if we're in last in
     * the chain
     */
    protected Request executeNext(Request request) {
        if (next == null)
            return request;
        return next.executeNext(request);
    }

}

 Request:

public class Request {

    private String title;

    public void setTitile(String title) {
        this.title = title;
    }
}

AdminNotifyService:

public class AdminNotifyService extends AbstractService{

    @Override
    public Request execute(Request request) {
       
        System.out.println("AdminNotifyService.........");
       
        return executeNext(request);
    }
}

UserNotifyService:

public class UserNotifyService extends AbstractService{

    @Override
    public Request execute(Request request) {
       
        System.out.println("UserNotifyService.......");
       
        return executeNext(request);
    }
}

 MainApp:

public class MainApp {

    public static void main(String[] args) {
       
        Request request = new Request();
        request.setTitile("chain responsibility");
       
        AbstractService abstractService = AbstractService.link(new AdminNotifyService(), new UserNotifyService());
        abstractService.execute(request);
    }
}

Saturday, September 17, 2022

Implementing queue

 package LinearDSA;


/**

 * @author lokman 17/09/2022

 *

 */

public class Queue {

private ListNode front;

private ListNode rear;

private int length = 0;

public Queue() {

this.front = null;

this.rear = null;

}

private class ListNode {

private int data;

private ListNode next;

public ListNode(int data) {

this.data = data;

this.next = null;

}

}

public int length() {

return length;

}

public boolean isEmpty() {

return length == 0;

}

public void enqueue(int data) {

ListNode temp = new ListNode(data);

if (isEmpty()) {

front = temp;

} else {

rear.next = temp;

}

rear = temp;

length++;

}

public int dequeue() {

if(isEmpty()) {

System.out.println("Queue is empty");

}

int data  = front.data;

front = front.next;

if(front == null) {

rear = null;

}

length--;

return data;

}

public void print() {

if (isEmpty()) {

return;

}

ListNode current = front;

while (current != null) {

System.out.print(current.data + "-->");

current = current.next;

}

System.out.println("null");

}

public static void main(String[] args) {

Queue queue = new Queue();

queue.enqueue(10);

queue.enqueue(20);

queue.enqueue(30);

queue.print();

queue.dequeue();

queue.print();

}

}


Tuesday, July 5, 2022

GridTraveler problem

 Q:Say that you are a 2D grid traveler . you begin in the top left corner and your goal is to travel to bottom right corner . You can travel either down or right .

So how many ways you can travel through the grid?



So we can divide the problems into subproblems and the solution is same as the subproblems .By using recurrence relation we can use recursion to solve the problem . But if the input size is large then it will be time consuming to solve because the time complexity here is 2^(m+n). 

So  , we can use memorization technique.
Below is my java solution.

public class GridTravelerUsingRecursion {

private int gridTraveler(int m, int n, Map<String, Integer> memo) {
if (m == 0 || n == 0) {
return 0;
}
if (m == 1 || n == 1) {
return 1;
}
String key = m + "," + n;
if (memo.containsKey(key)) {
return memo.get(key);
} else {
int recursiveResult = gridTraveler(m - 1, n, memo) + gridTraveler(m, n - 1, memo);
memo.put(key, recursiveResult);
}
return memo.get(key);
}

public static void main(String[] args) {
int m = 20, n = 20;
Map<String, Integer> memo = new HashMap<>();
GridTravelerUsingRecursion grid = new GridTravelerUsingRecursion();
int result = grid.gridTraveler(m, n, memo);
System.out.println(result);
}
}










Command design pattern

 When to implement ? Suppose we have a situation , There are multiple action to execute based on a single value or criteria. There are sever...