mardi 8 février 2022

Trying to identify a design pattern or strategy used to isolate, utilize, and manage database connections

I ran into some code and I wanted to research other people's approaches to it, but I'm not sure what the design pattern is called. I tried searching for "database executer" and mostly got results about Java's Executor framework which is unrelated.

The pattern I'm trying to identify uses a single class to manage connections and execute queries through the use of functions that allow you to isolate any issues related to connection management.

Example:

// Service class

public Service {
  private final Executor executor;

  public void query(String query) {
    ResultSet rs = (ResultSet) executor.execute((connection) -> {
      Statement st = connection.createStatement();
      return st.executeQuery(query);
    });
  }
}

// Executer class

public Executer {
  private final DataSource dataSource;

  public Object execute(Function function) {
    Connection connection = dataSource.getConnection();
    try {
      return function(connection);
    } catch(Exception e) {
      log...
    } finally {
      // close or return connection to pool
    }
  }
}

As you can see from above, if you ever have a connection leak you don't need to search through a bunch of DAOs or services, it's all contained in a single executor class. Any idea what this strategy or design pattern is called? Anyone see this before or know of open source projects that utilize this strategy/pattern?

REST API resource naming suffix

Our project came into discussion about URI pattern for Rest API.

The basic idea is a better description / readability of the endpoints themselves, by adding CRUD elements practically as a suffix in the endpoint name.

  • CRUD as /api/.../create, /api/.../read, /api/.../update and /api/.../delete endpoint pattern

So, examples (different examples without consistency for one project):

- GET    /api/v1/endpoint-names/read
- GET    /api/v1/endpoint-names/read/{id}
- GET    /api/v1/endpoint-names/read-paginated/{pageId}
- POST   /api/v1/endpoint-names/create
- PUT    /api/v1/endpoint-names/update-by-id/{id}
- DELETE /api/v1/endpoint-names/delete/{id}

I am aware of some recommendations, but I am interested in additional naming conventions / suggestions for web services with more complicated URI structures.

Or there is no real need for something like this?

lundi 7 février 2022

Best practice around request body of Rest API

I just wanted to create a Rest API. But I'm confused with the request format. As per the current requirement, my API is needing an array of objects as input. Eg. [{'key':'value'},{'key':'value'},{'key':'value'}]

But I'm thinking to have it like

{
  'key':[{'key':'value'},{'key':'value'},{'key':'value'}]
}

Can someone help me with, what is the best practice for having the request format(Array of objects or wrapper around an array of objects).

Design Pattern Factory Method question - why the factory method in ConcreteCreator won't be available yet?

I am reading "Design Patterns" by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. In chapter of factory method, there's one paragraph:

"Factory method in C++ are always virtual functions and are often pure virtual. Just be careful not to call factory methods in the Creator's constructor - the factory method in the ConcreteCreator won't be available yet."

I don't understand why the factory method in ConcreteCreator won't be available yet? is it because C++ is a compiled language therefore the method of the children class won't be available as the parent class is compiled first? Thank you.

How to implement scenario in RabbitMq or any other queue

I have a scenario for which I am trying to figure out how to implement this queue architecture. I was looking into using RabbitMQ but am open to other queue solutions if they are better for the following scenario.

We upload a file from the frontend to the backend. The backend processes (uploads) the file to S3. I plan on creating a message and insert it into a queue that we need to process file ABC.csv. This file contains products that we will need to fetch information on from certain API’s.

The APIs have a rate limit/throttling. Therefore we cannot send all messages together.

Each client (user) provides us with an API key to use. For example, say we need to send emails on behalf of client using send grid. So the client provides us their API and we send out emails on behalf of them. But the issue is Sendgrid has rate limit so we cannot blast those calls.

Now that being said. The csv will have each line as a user to send email to. The csv May gave 50k lines.

The issue I am running into is. If I create a message for each row, then all of User 1 messages will be in front of queue with rate limit for its api key. When user 2 comes, their messages will be behind User 1’s and therefore until user 1’s msgs are not all sent the consumer will not be able to send user 2’s messages.

Question: how can setup queue archetype such that we handle the rate limit set by Sendgrid for each user’s api key and are still able process next user’s messages as they come in, instead of making them wait until the first user’s messages are sent.

Creating a pattern with forward slash and backslash in C++ from an Input Sequence

I'm trying to do a college project where I use C++ to develop something similar to a star pattern. I need help fixing my code. My current one is an attempt to make this pattern upside-down which I also don't know how to invert. Due date: 2/11/22.

This is the original instructions.

 Write a program  that follows the pattern demonstrated with sample input and output below the numbers in the sequence correlate to a column of /s in odd # columns and \s in even columns.

Sample input:
1 1 3 1 2 3 5 2 1 2 2 3 7 2 3 1 2 1 3 5 2 3 1 2 5 7 3 1 3 4 2 5 3 2 4 4 1 2 1 3 3 2 1 2

Sample output:

                                             o                                                                       
                                            /|\                                                                      
                                            < >                                                                      
                                            / \                                                                      
                                           /   \                                                                     
                                        /\/     \              /\                                                    
                                     /\/         \  /\        /  \                                                   
                                /\  /             \/  \      /    \          /\                                      
                               /  \/                   \/\  /      \        /  \                                     
                              /                           \/        \    /\/    \  /\            /\                  
               /\            /                                       \  /        \/  \          /  \                 
              /  \/\  /\    /                                         \/              \    /\  /    \                
       /\    /      \/  \  /                                                           \  /  \/      \/\             
    /\/  \  /            \/                                                             \/              \/\    /\    
   /      \/                                                                                               \  /  \/\ 
/\/                                                                                                         \/      \

This is the code I tried so far. Code:

#include <iostream>
using namespace std;

//Array to print the slashes to create the pattern
void patternPrint(int n)
{
    for (int i = 0; i < n; i++) //For loop to create the pattern upside down
    {
        for (int j = 0; j <= i; j++) {
            if (j % 2 == 0)
            {
                cout << "\\" + "\n" + "  "; //on each next even column there will be 2 spaces + breakline for diagonal line
            }
            else
            {
                cout << "/" + "\n"; //on each next odd column there will be 2 spaces + breakline for diagonal line
            }

            cout << endl;
        }
    }
}

int main()
{
    int rows;
    int patternsize;

    cout << "Please choose how many rows you want your pattern to have";
    cin >> rows;
    cout << "Please enter a sequence of numbers to create your pattern. It will be alternating / and '\'s. Seperate each # with the enter key: ";
    int *array = new int[rows];
    for (int i = 0; i <= rows; i++)
    {
        std::cin >> array[i];
    }
   
    patternsize = sizeof(array)/sizeof(array[0]);
    cout << "Your pattern's amount of rows is = " << patternsize;
   
    patternPrint(patternsize);
   
    delete (array);
    return 0;
}

Implementing MVC design pattern in a real project JAVA Swing

I'm learning about design patterns and trying to implement the MVC design pattern in an old project. I can't really find actual project tutorials so I thought I would share my code here and ask for your guidance.

//import java.beans.Statement;
import java.sql.Connection;
import java.sql.*;


public class Home extends javax.swing.JFrame {
    
    public Home() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        upPanel = new javax.swing.JPanel();
        lblHome = new javax.swing.JLabel();
        midPanel = new javax.swing.JPanel();
        sPane = new javax.swing.JScrollPane();
        dataTbl = new javax.swing.JTable();
        tfSearch = new javax.swing.JTextField();
        btnSearch = new javax.swing.JButton();
        btnRefresh = new javax.swing.JButton();
        btnAddCon = new javax.swing.JButton();
        btnEditCon = new javax.swing.JButton();
        btnDelCon = new javax.swing.JButton();
        lblContacts = new javax.swing.JLabel();
        btnGroups = new javax.swing.JButton();
        botPanel = new javax.swing.JPanel();
        credTxt = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Iris");
        setBackground(new java.awt.Color(255, 250, 250));
        setResizable(false);
        setSize(new java.awt.Dimension(1000, 600));

        upPanel.setBackground(new java.awt.Color(0, 156, 255));
        upPanel.setForeground(new java.awt.Color(255, 250, 250));
        upPanel.setPreferredSize(new java.awt.Dimension(1319, 100));

        lblHome.setBackground(new java.awt.Color(0, 156, 255));
        lblHome.setFont(new java.awt.Font("sansserif", 0, 36)); // NOI18N
        lblHome.setForeground(new java.awt.Color(255, 250, 250));
        lblHome.setText("Contacts");

        javax.swing.GroupLayout upPanelLayout = new javax.swing.GroupLayout(upPanel);
        upPanel.setLayout(upPanelLayout);
        upPanelLayout.setHorizontalGroup(
            upPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(upPanelLayout.createSequentialGroup()
                .addGap(570, 570, 570)
                .addComponent(lblHome, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGap(632, 632, 632))
        );
        upPanelLayout.setVerticalGroup(
            upPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(upPanelLayout.createSequentialGroup()
                .addGap(24, 24, 24)
                .addComponent(lblHome, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGap(60, 60, 60))
        );

        getContentPane().add(upPanel, java.awt.BorderLayout.PAGE_START);

        midPanel.setBackground(new java.awt.Color(255, 250, 250));

        sPane.setBackground(new java.awt.Color(255, 250, 250));
        sPane.setName(""); // NOI18N

        dataTbl.setBackground(new java.awt.Color(248, 248, 255));
        dataTbl.setForeground(new java.awt.Color(0, 156, 255));
        dataTbl.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        sPane.setViewportView(dataTbl);

        tfSearch.setBackground(new java.awt.Color(248, 248, 255));
        tfSearch.setFont(new java.awt.Font("sansserif", 0, 14)); // NOI18N
        tfSearch.setForeground(new java.awt.Color(51, 51, 51));
        tfSearch.setToolTipText("Search by contact info ");
        tfSearch.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
        tfSearch.setSelectionColor(new java.awt.Color(0, 156, 255));
        tfSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tfSearchActionPerformed(evt);
            }
        });

        btnSearch.setBackground(new java.awt.Color(0, 156, 255));
        btnSearch.setFont(new java.awt.Font("sansserif", 1, 14)); // NOI18N
        btnSearch.setForeground(new java.awt.Color(255, 250, 250));
        btnSearch.setText("Search");
        btnSearch.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        btnSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSearchActionPerformed(evt);
            }
        });

        btnRefresh.setBackground(new java.awt.Color(218, 165, 32));
        btnRefresh.setFont(new java.awt.Font("sansserif", 1, 18)); // NOI18N
        btnRefresh.setForeground(new java.awt.Color(255, 250, 250));
        btnRefresh.setText("Refresh");
        btnRefresh.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));

        btnAddCon.setBackground(new java.awt.Color(40, 155, 15));
        btnAddCon.setFont(new java.awt.Font("sansserif", 1, 14)); // NOI18N
        btnAddCon.setForeground(new java.awt.Color(255, 250, 250));
        btnAddCon.setText("Add");
        btnAddCon.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        btnAddCon.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddConActionPerformed(evt);
            }
        });

        btnEditCon.setBackground(new java.awt.Color(0, 156, 255));
        btnEditCon.setFont(new java.awt.Font("sansserif", 1, 14)); // NOI18N
        btnEditCon.setForeground(new java.awt.Color(255, 250, 250));
        btnEditCon.setText("Edit");
        btnEditCon.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        btnEditCon.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnEditConActionPerformed(evt);
            }
        });

        btnDelCon.setBackground(new java.awt.Color(195, 5, 5));
        btnDelCon.setFont(new java.awt.Font("sansserif", 1, 14)); // NOI18N
        btnDelCon.setForeground(new java.awt.Color(255, 250, 250));
        btnDelCon.setText("Delete");
        btnDelCon.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));

        lblContacts.setBackground(new java.awt.Color(255, 250, 250));
        lblContacts.setFont(new java.awt.Font("sansserif", 3, 14)); // NOI18N
        lblContacts.setForeground(new java.awt.Color(0, 156, 255));
        lblContacts.setText("Contacts:");

        btnGroups.setBackground(new java.awt.Color(0, 156, 255));
        btnGroups.setFont(new java.awt.Font("sansserif", 1, 18)); // NOI18N
        btnGroups.setForeground(new java.awt.Color(255, 250, 250));
        btnGroups.setText("Groups");
        btnGroups.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        btnGroups.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnGroupsActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout midPanelLayout = new javax.swing.GroupLayout(midPanel);
        midPanel.setLayout(midPanelLayout);
        midPanelLayout.setHorizontalGroup(
            midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(midPanelLayout.createSequentialGroup()
                .addGap(161, 161, 161)
                .addComponent(tfSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 328, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(btnSearch)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(btnRefresh)
                .addGap(55, 55, 55)
                .addComponent(btnGroups)
                .addGap(85, 85, 85))
            .addComponent(sPane, javax.swing.GroupLayout.Alignment.TRAILING)
            .addGroup(midPanelLayout.createSequentialGroup()
                .addGap(47, 47, 47)
                .addGroup(midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(midPanelLayout.createSequentialGroup()
                        .addComponent(btnAddCon)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(btnEditCon)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnDelCon))
                    .addComponent(lblContacts))
                .addGap(90, 1058, Short.MAX_VALUE))
        );
        midPanelLayout.setVerticalGroup(
            midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, midPanelLayout.createSequentialGroup()
                .addGap(48, 48, 48)
                .addGroup(midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(tfSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnSearch)
                    .addComponent(btnRefresh)
                    .addComponent(btnGroups))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 60, Short.MAX_VALUE)
                .addComponent(sPane, javax.swing.GroupLayout.PREFERRED_SIZE, 312, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(lblContacts)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnDelCon)
                    .addComponent(btnEditCon)
                    .addComponent(btnAddCon))
                .addGap(12, 12, 12))
        );

        sPane.getAccessibleContext().setAccessibleName("");

        getContentPane().add(midPanel, java.awt.BorderLayout.CENTER);

        botPanel.setBackground(new java.awt.Color(0, 156, 255));
        botPanel.setForeground(new java.awt.Color(255, 250, 250));
        botPanel.setToolTipText("");
        botPanel.setPreferredSize(new java.awt.Dimension(1319, 60));

        credTxt.setEditable(false);
        credTxt.setBackground(new java.awt.Color(0, 156, 255));
        credTxt.setFont(new java.awt.Font("sansserif", 3, 12)); // NOI18N
        credTxt.setForeground(new java.awt.Color(255, 250, 250));
        credTxt.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        credTxt.setText("Iris - Developed by Bachar Sabra and Charbel El-Khoury.");
        credTxt.setBorder(null);
        credTxt.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                credTxtActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout botPanelLayout = new javax.swing.GroupLayout(botPanel);
        botPanel.setLayout(botPanelLayout);
        botPanelLayout.setHorizontalGroup(
            botPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(botPanelLayout.createSequentialGroup()
                .addGap(402, 402, 402)
                .addComponent(credTxt, javax.swing.GroupLayout.DEFAULT_SIZE, 513, Short.MAX_VALUE)
                .addGap(428, 428, 428))
        );
        botPanelLayout.setVerticalGroup(
            botPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(botPanelLayout.createSequentialGroup()
                .addGap(14, 14, 14)
                .addComponent(credTxt)
                .addGap(30, 30, 30))
        );

        getContentPane().add(botPanel, java.awt.BorderLayout.PAGE_END);

        pack();
        setLocationRelativeTo(null);
    }// </editor-fold>                        

    private void tfSearchActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
    }                                        

    private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
    }                                         

    private void credTxtActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
    }                                       

    private void btnAddConActionPerformed(java.awt.event.ActionEvent evt) {                                          
        AddContact addContact = new AddContact();
        
        addContact.setVisible(true);
        addContact.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }                                         

    private void btnEditConActionPerformed(java.awt.event.ActionEvent evt) {                                           
        EditContact editContact = new EditContact();
        
        editContact.setVisible(true);
        editContact.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }                                          

    private void btnGroupsActionPerformed(java.awt.event.ActionEvent evt) {                                          
        Groups groups = new Groups();
        
        groups.setVisible(true);
        groups.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        dispose();
    }                                         

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
//        getContacts();
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Home.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Home.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Home.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Home.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Home().setVisible(true);
            }
        });
    }



    public static void getContacts() {
        try {
            Connection conn = null;
            Statement stmt = null;
            conn = JDBCCon.getCon();
            stmt = (Statement) conn.createStatement();
            ResultSet myRs;
            myRs = stmt.executeQuery("SELECT * FROM `contacts` ;");
            while (myRs.next()) {
            System.out.println("working in main");
            System.out.println(myRs.getString("Last_Name") + ", " + myRs.getString("First_Name"));
            }

        } catch (Exception e) {
            System.out.println("Error in getContacts function : "+ e);
        }
    }


    private void searchContacts() {
        String seach = tfSearch.getText();
        try {
            Connection conn = null;
            Statement stmt = null;
            conn = JDBCCon.getCon();
            stmt = (Statement) conn.createStatement();
            ResultSet myRs;
            myRs = stmt.executeQuery("SELECT * FROM `conatcts` WHERE First_Name = '"+seach+"' OR Last_Name = "+seach+" ;");
            if (myRs.next() != false) {
                System.out.println("no groups found");
            }else{
                System.out.println("groups ");
            }

        } catch (Exception e) {
            System.out.println("Error in searchGroups function : "+ e);
        }

    }


    // Variables declaration - do not modify                     
    private javax.swing.JPanel botPanel;
    private javax.swing.JButton btnAddCon;
    private javax.swing.JButton btnDelCon;
    private javax.swing.JButton btnEditCon;
    private javax.swing.JButton btnGroups;
    private javax.swing.JButton btnRefresh;
    private javax.swing.JButton btnSearch;
    private javax.swing.JTextField credTxt;
    private javax.swing.JTable dataTbl;
    private javax.swing.JLabel lblContacts;
    private javax.swing.JLabel lblHome;
    private javax.swing.JPanel midPanel;
    private javax.swing.JScrollPane sPane;
    private javax.swing.JTextField tfSearch;
    private javax.swing.JPanel upPanel;
    // End of variables declaration                   

}

From what I understand it goes View for design like JFrames, Buttons, Pannels etc...Controller for ActionEvents and maybe constructers, setters and getters and Model for the main class and maybe database connection and queries.