My program is a simulated online shopping system. The program displays a login screen when it is run, and the user can click the "Forgot Password" button if they do not remember their login. Upon clicking this button, the program opens a frame where the user can enter their email address. When the user enters this email address and hits the "Send Password Recovery Email", a message dialog is supposed to show up informing the user that the email either was successfully sent (if the user has entered in the email address that is actually associated with their ID) or was not sent (if the address the user entered either does not exist in the database or all or is tied to a different user). However, no message dialog pops up when I run the program, and I cannot figure out why. No exception is returned - the program just refuses to display the dialog.
Here is the code for all the relevant parts of the program. Sorry for providing so much code, but since the program isn't returning an exception, I have no idea whatsoever where the code that is causing the program to malfunction is. There are other parts to the program, but they are not directly relevant to the "forgot password" screen.
Application:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
public class Application {
private static Application instance; // Singleton pattern
private static boolean checkEmail = false;
private static String email;
public static Application getInstance() {
if (instance == null) {
instance = new Application();
}
return instance;
}
// Main components of this application
private Connection connection;
public Connection getConnection() {
return connection;
}
public static void setCheckEmail() {
checkEmail = true;
}
public static void setEmail(String theEmail) {
email = theEmail;
}
private DataAdapter dataAdapter;
private User currentUser = null;
public void setCurrentUser(User user) {
this.currentUser = user;
}
public User getCurrentUser() {
return currentUser;
}
// Create the Product View and Controller here!
private ProductView productView = new ProductView();
private CheckoutScreen checkoutScreen = new CheckoutScreen();
private MainScreen mainScreen = new MainScreen();
public MainScreen getMainScreen() {
return mainScreen;
}
public ProductView getProductView() {
return productView;
}
public CheckoutScreen getCheckoutScreen() {
return checkoutScreen;
}
public LoginScreen loginScreen = new LoginScreen();
public LoginScreen getLoginScreen() {
return loginScreen;
}
public LoginController loginController; // = new LoginController(loginScreen, dataAdapter);
private ProductController productController;
public ProductController getProductController() {
return productController;
}
private CheckoutController checkoutController;
public CheckoutController getCheckoutController() {
return checkoutController;
}
public DataAdapter getDataAdapter() {
return dataAdapter;
}
private ForgotPasswordScreen forgotPasswordScreen = new ForgotPasswordScreen();
public ForgotPasswordScreen getForgotPasswordScreen() {
return forgotPasswordScreen;
}
private void initializeDatabase(Statement stmt) throws SQLException { // CHANGE: Added initialization code
// create the tables and insert sample data here!
stmt.execute("create table Product (ProductID int PRIMARY KEY, ProductName char(30), Price double, Quantity double);");
stmt.execute("create table Orders (ProductID int PRIMARY KEY, ProductName char(30), Price double, Quantity double);");
stmt.execute("create table OrderLine (OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity double, Cost double, PRIMARY KEY (ProductID, OrderID);");
stmt.execute("create table User (UserID INT NOT NULL, UserName CHAR(30) NOT NULL, Password CHAR(30) NOT NULL, DisplayName CHAR(30), IsManager BOOL DEFAULT FALSE, PRIMARY KEY(UserID));");
stmt.execute("create table sqlite_sequence (name, seq);");
stmt.execute("INSERT INTO Product VALUES (1, 'Apple', 1.0, 257.0), (2, 'Chair', 100.0, 38.0), (3, 'Smartphone', 699.99, 486.0), (4, 'T-shirt', 20.0, 244.0), (5, 'TV', 250.0, 43.0);");
stmt.execute("INSERT INTO User VALUES (1, 'admin', 'password', 'Admin', TRUE);");
}
private void initializeEmailList(Statement stmt) throws SQLException {
stmt.execute("CREATE TABLE Email (Email CHAR(30) NOT NULL, UserID int NOT NULL);");
stmt.execute("INSERT INTO Email VALUES('admin@example.com', 1);");
}
private Application() {
// create SQLite database connection here!
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
if (!stmt.executeQuery("select * from product").next()) // product table do not exist
initializeDatabase(stmt);
if (!stmt.executeQuery("select * from email").next()) // product table do not exist
initializeEmailList(stmt);
if(checkEmail == true) {
Statement stmt2 = connection.createStatement();
ResultSet resultSet = stmt2.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");
//Application.getInstance().checkEmail(email);
checkEmail = false;
}
}
catch (ClassNotFoundException ex) {
System.out.println("SQLite is not installed. System exits with error!");
System.exit(1);
}
catch (SQLException ex) {
System.out.println("SQLite database is not ready. System exits with error!" + ex.getMessage());
System.exit(2);
}
// Create data adapter here!
dataAdapter = new DataAdapter(connection);
productController = new ProductController(productView, dataAdapter);
checkoutController = new CheckoutController(checkoutScreen, dataAdapter);
loginController = new LoginController(loginScreen, dataAdapter);
}
public static void main(String[] args) {
Application.getInstance().getLoginScreen().setVisible(true);
}
}
ForgotPasswordController:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
public class ForgotPasswordController implements ActionListener {
private ForgotPasswordScreen forgotPasswordScreen;
public ForgotPasswordController(ForgotPasswordScreen forgotPasswordScreen) {
this.forgotPasswordScreen = forgotPasswordScreen;
this.forgotPasswordScreen.getSendEmail().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
Application.setEmail(email);
Application.setCheckEmail();
/*Connection forgotPasswordConnection = Application.getInstance().getConnection();
Statement stmt = forgotPasswordConnection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
//Application.getInstance().checkEmail(email);
Application application = Application.getInstance();
}
}
}
ForgotPasswordScreen:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ForgotPasswordScreen extends JFrame {
private JTextField emailAddress = new JTextField(30);
private JButton sendEmail = new JButton("Send Password Recovery Email");
public JButton getSendEmail() {
return sendEmail;
}
public JTextField getEmailAddress() {
return emailAddress;
}
public ForgotPasswordScreen() {
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 200);
JPanel panelForgotPasswordScreen = new JPanel();
JLabel emailAddressLabel = new JLabel("Email address:");
panelForgotPasswordScreen.add(emailAddressLabel);
panelForgotPasswordScreen.add(emailAddress);
this.getContentPane().add(panelForgotPasswordScreen);
JPanel panelSendEmailButton = new JPanel();
panelSendEmailButton.add(sendEmail);
this.getContentPane().add(sendEmail);
}
}
LoginController:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginController implements ActionListener {
private LoginScreen loginScreen;
private DataAdapter dataAdapter;
public LoginController(LoginScreen loginScreen, DataAdapter dataAdapter) {
this.loginScreen = loginScreen;
this.dataAdapter = dataAdapter;
this.loginScreen.getBtnLogin().addActionListener(this);
this.loginScreen.getBtnForgotPassword().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == loginScreen.getBtnLogin()) {
String username = loginScreen.getTxtUserName().getText().trim();
String password = loginScreen.getTxtPassword().getText().trim();
System.out.println("Login with username = " + username + " and password = " + password);
User user = dataAdapter.loadUser(username, password);
if (user == null) {
JOptionPane.showMessageDialog(null, "This user does not exist!");
}
else {
Application.getInstance().setCurrentUser(user);
this.loginScreen.setVisible(false);
Application.getInstance().getMainScreen().setVisible(true);
}
}
if(e.getSource() == loginScreen.getBtnForgotPassword()) {
Application.getInstance().getForgotPasswordScreen().setVisible(true);
}
}
}
LoginScreen:
import javax.swing.*;
import java.awt.*;
public class LoginScreen extends JFrame {
private JTextField txtUserName = new JTextField(10);
private JTextField txtPassword = new JTextField(10);
private JButton btnLogin = new JButton("Login");
private JButton btnForgotPassword = new JButton("Forgot Password"); //CHANGE: Added a mechanism for the user to recover a forgotten password
public JButton getBtnLogin() {
return btnLogin;
}
public JTextField getTxtPassword() {
return txtPassword;
}
public JTextField getTxtUserName() {
return txtUserName;
}
public JButton getBtnForgotPassword() {
return btnForgotPassword;
}
public LoginScreen() {
this.setSize(300, 400);
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.getContentPane().add(new JLabel ("Store Management System"));
JPanel panelUserName = new JPanel();
panelUserName.add(new JLabel("Username:"));
panelUserName.add(txtUserName);
this.getContentPane().add(panelUserName);
JPanel panelPassword = new JPanel();
panelPassword.add(new JLabel("Password:"));
panelPassword.add(txtPassword);
this.getContentPane().add(panelPassword);
JPanel panelLogin = new JPanel();
panelLogin.setAlignmentX(Component.CENTER_ALIGNMENT); //CHANGE: Centered the login and "forgot password" buttons
panelLogin.add(btnLogin);
JPanel panelForgotPassword = new JPanel();
panelLogin.setAlignmentX(Component.CENTER_ALIGNMENT);
panelForgotPassword.add(btnForgotPassword);
this.getContentPane().add(panelLogin);
this.getContentPane().add(panelForgotPassword);
}
}
EDIT: Following MadProgrammer's advice, I removed the code that tests the validity of the email address inputted by the user from the Application class and added it to my ForgotPasswordController class inside the actionPerformed method; however, I am now receiving a new error: "unreported exception java.sql.SQLException; must be caught or declared to be thrown".
Adding "throws SQLException" to the actionPerformed method does not work in diagnosing the problem because the method it is overriding does not include "throws SQLException"; doing this merely creates a new error saying "java: actionPerformed(java.awt.event.ActionEvent) in ForgotPasswordController cannot implement actionPerformed(java.awt.event.ActionEvent) in java.awt.event.ActionListener overridden method does not throw java.sql.SQLException".
Here is the new code for my actionPerformed method:
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
//Application.setEmail(email);
//Application.setCheckEmail();
/*Connection forgotPasswordConnection = Application.getInstance().getConnection();
Statement stmt = forgotPasswordConnection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
//Application.getInstance().checkEmail(email);
//Application application = Application.getInstance();
Connection connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");
}
}
EDIT 2: I have now removed most of the above code from my ForgotPasswordController method and created a new method within my Application class called emailValidityChecker:
public void emailValidityChecker(String emailAddress, String username) throws SQLException {
Statement stmt2 = connection.createStatement();
ResultSet resultSet = stmt2.executeQuery("SELECT * from User WHERE UserName = " + username);
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "No account has been registered with this username!");
else {
int userID = resultSet.getInt(1);
Statement stmt3 = connection.createStatement();
ResultSet resultSet2 = stmt3.executeQuery("SELECT * from Email where UserID = " + userID);
String correspondingEmail = resultSet2.getString(1);
if (!resultSet2.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (!correspondingEmail.equals(emailAddress))
JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");
}
}
I have also changed my actionPerformed method in my ForgotPasswordController class so that it now looks like this:
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
String username = forgotPasswordScreen.getUsername().getText().trim();
//Application.setEmail(email);
//Application.setCheckEmail();
/*Connection forgotPasswordConnection = Application.getInstance().getConnection();
Statement stmt = forgotPasswordConnection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
//Application.getInstance().checkEmail(email);
//Application application = Application.getInstance();
/*Connection connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
Application.getInstance().emailValidityChecker(email, username);
}
}
Unfortunately, I am experiencing the same error I was describing in my previous edit. I am still getting the message "java: unreported exception java.sql.SQLException; must be caught or declared to be thrown" on the line "Statement stmt2 = connection.createStatement();", and adding "throws SQLException" doesn't help because I then got the exact same exception but on the last line of my actionPerformed method in my ForgotPasswordController class. I could add a try-catch block in my emailValidityChecker method, but this still wouldn't tell me anything about why I am receiving an SQL exception.