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);
        }
    }
}

Wednesday, December 13, 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);
    }
}

Sunday, September 18, 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();

}

}


Wednesday, July 6, 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);
}
}










Friday, June 24, 2022

Memorization

 Dynamic programming where a big problem is divided into small subproblems and solve those subproblems . Use the previous optimal solution of subproblems . 

Lets see an example ,

public class Fibonacci {

       public static int fib(int n, Map<Integer, Integer> memo) {

if (memo.containsKey(n))

return memo.get(n);

if (n <= 2)

return 1;

memo.put(n, fib(n - 1, memo) + fib(n - 2, memo));

return memo.get(n);

}

public static void main(String[] args) {

int number = 9;

Map<Integer, Integer> memo = new HashMap<>();

int result = fib(number, memo);

System.out.println(result);

}

}

Here we use memorization , so the previously solved subproblems are stored into the memory and we can use it . What will minimize the time complexity. So, the time complexity reduces from exponential to linear .

Testing controller

------Controller------------- @RestController @RequestMapping("/items") public class ItemController {     private final ItemServic...