How to redirec to to HTML if exception occured - html

I've been trying to search for a way to redirect to an HTML file if a SQLException occurs. I'm going to give you an example.
I have my connection class something like this:
public class DBConection{
Connection con = null;
public DBConnection() throws RuntimeException{
try {
Class.forName("org.gjt.mm.mysql.Driver");
String user = "root";
String pass = "12345";
String db = "java";
con = DriverManager.getConnection("jdbc:mysql://localhost/" + db, user, pass);
}catch (ClassNotFoundException ex) {
throw new RuntimeException();
}catch (SQLException ex) {
throw new RuntimeException();
}
}
}
and I'm calling it from a Servlet class,
public class ElectionsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String RETURN_PAGE = "index.jsp";
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
DBConnection con = new DBConnection();
response.sendRedirect(RETURN_PAGE);
}
}
If an error ocurres during the DBConnection I want to redirect it to my RETURN_PAGE. Can anybody help me?

Just use the builtin container managed exception handling facilities. You need to rethrow the caught exception as ServletException and define the error page as <error-page> in web.xml.
You only need to change your DB access logic accordingly. It's far from sane, safe and efficient. The exception handling is also strange. You seem to have ripped this from a completely outdated resource given the fact that you're using the deprecated MySQL JDBC driver class name.
Here's a basic kickoff example:
public final class Database {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost/java";
private static final String USER = "root";
private static final String PASS = "12345";
static {
try {
Class.forName(DRIVER);
}
catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("The JDBC driver is missing in classpath!", e);
}
}
private Database() {
// Don't allow construction.
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASS);
}
}
Finally use and handle it in the servlet as follows:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
Connection connection = null;
// ...
try{
connection = Database.getConnection();
// ...
}
catch (SQLException e) {
throw new ServletException("DB fail!", e);
}
finally {
// ...
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
}
(better would be to wrap the DB job in a DAO class which in turn throws a SQLException, but that's a different problem)
And declare the error page in web.xml as follows:
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/WEB-INF/errorpages/database.jsp</location>
</error-page>
You can of course also use <location>/index.jsp</location> but that's not very friendly to the enduser as it's completely confusing why he returns back to there. Rather put that as a link in the database.jsp error page along with something user friendly like
Sorry, an unrecoverable problem has occurred while communicating with the DB. Please click the following link to return to the index page.
See also:
Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern

The question is already answered, but I'll add a few comments:
I don't see the need of catching SQLException and ClassNotFoundException only to rethow RuntimeException instances. If you're planning to do nothing when this exception raises in your DBConnection class, just add throws to your constructor signature. With that, the compiler will check that a try-catch block be added when using your constructor.
There's no need of adding throws RuntimeException to your constructor signature. RuntimeException is a non-checked exception.

Add try-catch block to your doPost method and if any exception occurs in try block, catch that exception and redirect to RETURN_PAGE.
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try{
DBConnection con = new DBConnection();
}catch(Exception e){
response.sendRedirect(RETURN_PAGE);
}
}

Related

IntelliJ cannot find MySQL JDBC driver

I have added MySQL JDBC driver but I keep getting the following error: No suitable driver found for jdbc.
Here's the code that I'm trying:
public class Test extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jsp1", "root", "");
System.out.println("Connected successfully");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here are the project settings.
As soon as I add MySQL jar, one following problem appears:
I have tried all of the three options above, but I keep getting the same error.

CAS cannot find authentication handler that supports UsernamePasswordCredential

I have a custom handler like this:
Public class DatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler {
#Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
final String username = credential.getUsername();
logger.debug("***Username:"+username);
logger.debug("***Password:"+credential.getPassword());
return createHandlerResult(credential, new SimplePrincipal(), null);
}
#Override
public boolean supports(final Credential credential) {
return true;
}
}
To me, this should always log a user in no matter what. But I see in the logs this:
ERROR [org.apereo.cas.authentication.PolicyBasedAuthenticationManager]
- <Authentication has failed. Credentials may be incorrect or CAS cannot find authentication handler that supports
[UsernamePasswordCredential(username=sadf, source=MyJDBCAuthenticationManager)] of type [UsernamePasswordCredential].
Examine the configuration to ensure a method of authentication is defined and analyze CAS logs at DEBUG level to trace the authentication event.
which makes no sense to me as I can see in the logs that cas is calling the authenticatUsernamePasswordInternal method. Obviously this handler supports, well everything.
Why can't I log in?
I think you best use principalFactory.createPrincipal to create the principal rather than returning an new SimplePrincipal().
In your AuthenticationEventExecutionPlanConfigurer & DatabaseAuthenticationHandler, add the following:
AuthenticationEventExecutionPlanConfigurer.java
#Autowired
#Qualifier("principalFactory")
private PrincipalFactory principalFactory;
#Bean
public DatabaseAuthenticationHandler databaseAuthenticationHandler() {
return new DatabaseAuthenticationHandler(principalFactory);
}
DatabaseAuthenticationHandler
Public class DatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler {
private final PrincipalFactory principalFactory;
public DatabaseAuthenticationHandler (PrincipalFactory principalFactory){
this.principalFactory = principalFactory;
}
#Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
UsernamePasswordCredential credential, String originalPassword) throws GeneralSecurityException, PreventedException {
final String username = credential.getUsername();
logger.debug("***Username:"+username);
logger.debug("***Password:"+credential.getPassword());
/////// below here's the change /////////
return createHandlerResult(credential, this.principalFactory.createPrincipal(username), null);
}
#Override
public boolean supports(final Credential credential) {
return true;
}
}
See if the above works, thanks.
The root cause of this problem is that you pass a null parameter to createHandlerResult method,you can change it to new ArrayList<>. I also encountered this problem(My CAS version is 5.3.9).And I also tried the solution gaving by Ng Sek Long,but it didn't work.Then I tried to solve it by myself. I searched for the error message in CAS code and found it in PolicyBasedAuthenticationManager class.
try {
PrincipalResolver resolver = this.getPrincipalResolverLinkedToHandlerIfAny(handler, transaction);
LOGGER.debug("Attempting authentication of [{}] using [{}]", credential.getId(), handler.getName());
this.authenticateAndResolvePrincipal(builder, credential, resolver, handler);
AuthenticationCredentialsThreadLocalBinder.bindInProgress(builder.build());
Pair<Boolean, Set<Throwable>> failures = this.evaluateAuthenticationPolicies(builder.build(), transaction);
proceedWithNextHandler = !(Boolean)failures.getKey();
} catch (Exception var15) {
LOGGER.error("Authentication has failed. Credentials may be incorrect or CAS cannot find authentication handler that supports [{}] of type [{}]. Examine the configuration to ensure a method of authentication is defined and analyze CAS logs at DEBUG level to trace the authentication event.", credential, credential.getClass().getSimpleName());
this.handleAuthenticationException(var15, handler.getName(), builder);
proceedWithNextHandler = true;
}
In the above code snippet, the authenticateAndResolvePrincipal method declaired two kinds of exception.Looked at this method, I found there is a line of code which may throws that two.
AuthenticationHandlerExecutionResult result = handler.authenticate(credential);
The key code which lead to this problem is in DefaultAuthenticationHandlerExecutionResult class.
public DefaultAuthenticationHandlerExecutionResult(final AuthenticationHandler source, final CredentialMetaData metaData, final Principal p, #NonNull final List<MessageDescriptor> warnings) {
this(StringUtils.isBlank(source.getName()) ? source.getClass().getSimpleName() : source.getName(), metaData, p, warnings);
if (warnings == null) {
throw new NullPointerException("warnings is marked #NonNull but is null");
}
}
So, if you use createHandlerResult(credential, new SimplePrincipal(), null), NullPointerException will throw at runtime.It will be catched by catch (Exception var15) code bock and log the error message you see.

Spying method calls the actual Method

I am writing a JUnit with Mockito. But on the line
when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);
It calls the actual method, which is causing the test failure. Interesting point is that it directly makes the actual call at start of the test case when when()...thenReturn() statemnts gets executed. Can you please tell me how I can fix this? My test is as per below
#Test
public void testDecryptData_Success() throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
encryptDecryptUtil = spy(new EncryptDecryptUtil());
Key keyMock = Mockito.mock(Key.class);
when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);
String inputData = "TestMessage";
String version = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
byte[] enCryptedValue= new byte[] {9,2,5,8,9};
Cipher cipherMock = Mockito.mock(Cipher.class);
when(Cipher.getInstance(any(String.class))).thenReturn(cipherMock);
when(cipherMock.doFinal(any(byte[].class))).thenReturn(enCryptedValue);
String encryptedMessage = encryptDecryptUtil.encryptData(inputData);
assert(encryptedMessage.contains(version));
assertTrue(!encryptedMessage.contains(inputData));
}
On the third line it self, it calls the actual method.
Main code is as per below.
public class EncryptDecryptUtil {
private String publicKeyStoreFileName =
GetPropValues.getPropValue(PublisherConstants.KEYSTORE_PATH);
private String pubKeyStorePwd = "changeit";
private static final String SHA1PRNG = "SHA1PRNG";
private static final String pubKeyAlias="jceksaes";
private static final String JCEKS = "JCEKS";
private static final String AES_PADDING = "AES/CBC/PKCS5Padding";
private static final String AES = "AES";
private static final int CONST_16 = 16;
private static final int CONST_0 = 0;
private static final String KEY_STORE = "aes-keystore";
private static final String KEY_STORE_TYPE = "jck";
private static final Logger logger = Logger.getLogger(KafkaPublisher.class);
public Key getKeyFromKeyStore( String keystoreVersion) {
KeyStore keyStore = null;
Key key = null;
try {
keyStore = KeyStore.getInstance(JCEKS);
FileInputStream stream = null;
stream = new FileInputStream(publicKeyStoreFileName+KEY_STORE+PublisherConstants.UNDERSCORE+keystoreVersion+PublisherConstants.DOT+KEY_STORE_TYPE);
keyStore.load(stream, pubKeyStorePwd.toCharArray());
stream.close();
key = keyStore.getKey(pubKeyAlias, pubKeyStorePwd.toCharArray());
} catch (KeyStoreException e) {
e.printStackTrace();
}
catch (FileNotFoundException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (CertificateException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (IOException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
}
return key;
}
public String encryptData(String data) {
String keystoreVersion = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
SecretKey secKey = new SecretKeySpec(getKeyFromKeyStore(keystoreVersion).getEncoded(), AES);
String base64EncodedEncryptedMsg = null;
Cipher cipher = null;
try { ------- Logic -------------------}
catch() { }
}
}
Have a look at the "Important gotcha on spying real objects" section of the Spy documentation.
Essentially, you cannot use the when(...).thenReturn(...) pattern with Spies, because as you have discovered, it calls the real method!
Instead, you use a different pattern which does exactly the same thing:
doReturn(...).when(spy).someMethod();
So, for your example:
doReturn(keyMock).when(encryptDecryptUtil).getKeyFromKeyStore(any(String.class));
Some advice which is unrelated to your question: If I read your code correctly, then EncryptDecryptUtil is the class that you are testing. As a general rule, you should not mock, stub, or spy on the object that you are actually testing, because then you are not testing the true object. You are actually testing a version of the object creating by the Mockito library. Furthermore, it's an uncommon pattern which will make your tests hard to read and maintain. If you find yourself having to do this, then the best thing would be to refactor your code so that the methods you are mocking (or spying on) and the methods you are testing are in different classes.

MySQL connection pooling with JERSEY

I'm developping a RESTful API with Jersey and MySQL.
I'm actually using the JDBC driver to connect to the database and I create a new connection everytime I want to acess it. As it clearly is a memory leakage, I started to implement the ServletContextClassclass but I don't know how to call the method when I need to get the result of a SQL query.
Here is how I did it wrong:
DbConnection.java
public class DbConnection {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
}
catch (SQLException e) {
throw e;
}
}
}
DbData.java
public ArrayList<Product> getAllProducts(Connection connection) throws Exception {
ArrayList<Product> productList = new ArrayList<Product>();
try {
PreparedStatement ps = connection.prepareStatement("SELECT id, name FROM product");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setName(rs.getString("name"));
productList.add(product);
}
return productList;
} catch (Exception e) {
throw e;
}
}
Resource.java
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId) throws Exception {
try {
DbConnection database= new DbConnection();
Connection connection = database.getConnection();
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Here is where I ended up trying to implement the new class:
ServletContextClass.java
public class ServletContextClass implements ServletContextListener {
public Connection getConnection() throws Exception {
try {
String connectionURL = "jdbc:mysql://root:port/path";
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
return connection;
} catch (SQLException e) {
throw e;
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
DbConnection database = new DbConnection();
try {
Connection connection = database.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
//con.close ();
}
}
But problem is, I don't know what to do next. Any help? Thanks
You need to set the Connection variable as an attribute of the ServletContext. Also, I would recommend using connection as a static class variable so you can close it in the contextDestroyed method.
You can retrieve the connection attribute in any of your servlets later on for doing your DB operations.
public class ServletContextClass implements ServletContextListener {
public static Connection connection;
public Connection getConnection(){
try {
String connectionURL = "jdbc:mysql://root:port/path";
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(connectionURL, "root", "password");
} catch (SQLException e) {
// Do something
}
}
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
getConnection();
arg0.getServletContext().setAttribute("connection", connection);
}
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
try{
if(connection != null){
connection.close();
}
}catch(SQLException se){
// Do something
}
}
}
Finally access your connection attribute inside your Servlet (Resource). Make sure you pass #Context ServletContext to your Response method so you can access your context attributes.
#GET
#Path("task/{taskId}")
#Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(#PathParam("taskId") int taskId, #Context ServletContext context) throws Exception {
try {
Connection connection = (Connection) context.getAttribute("connection");
Task task = new Task();
DbData dbData = new DbData();
task = dbData.getTask(connection, taskId);
return Response.status(200).entity(task).build();
} catch (Exception e) {
throw e;
}
}
Now that we have solved your current issue, we need to know what can go wrong with this approach.
Firstly, you are only creating one connection object which will be used everywhere. Imagine multiple users simultaneously accessing your API, the single connection will be shared among all of them which will slow down your response time.
Secondly, your connection to DB will die after sitting idle for a while (unless you configure MySql server not to kill idle connections which is not a good idea), and when you try to access it, you will get SQLExceptions thrown all over. This can be solved inside your servlet, you can check if your connection is dead, create it again, and then update the context attribute.
The best way to go about your Mysql Connection Pool will be to use a JNDI resource. You can create a pool of connections which will be managed by your servlet container. You can configure the pool to recreate connections if they go dead after sitting idle. If you are using Tomcat as your Servlet Container, you can check this short tutorial to get started with understanding the JNDI connection pool.

jsp mysql server connection timeout

hi i am doing an jsp project. and i deploy my project on apache tomcat. i use mysql as databese.
when i deploy project on remote server it is run good. but after some hours it gives me sql error. then i go back my apache server and start projecet again it run and after some hours it gives me same sql error again. i dont know the problem. is that caused from my java connection code or it is about mysql server. can some one tell me why it gives me sql error.?
public class ConnectionManager {
private String className = "com.mysql.jdbc.Driver";
private String userName ="username";
private String password = "password";
private String url = "jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8";
/**
* #uml.property name="connectionInstance"
* #uml.associationEnd
*/
private static ConnectionManager connectionInstance = null;
public ConnectionManager(){
}
public static synchronized ConnectionManager getInstance() {
if(connectionInstance == null) {
connectionInstance = new ConnectionManager();
}
return connectionInstance;
}
public Connection getConnection(){
Connection conn = null;
try {
Class.forName(className);
conn = DriverManager.getConnection (url, userName, password);
System.out.println("Connection Established");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
MySQL has a default connection timeout of 8 hours. So this means that you've kept a SQL connection open for too long. Your code suggests that you're creating only one connection on application's startup and reusing it application wide. This is very bad. This is not threadsafe.
You need to change your code so that you're not declaring and storing the SQL Connection as a static or instance variable anywhere in your code. Instead, it should be declared, created and closed within the shortest possible scope. Preferably within the very same method block as where you're executing the SQL query.
Here's a minor rewrite of your ConnectionManager which does the job properly:
public class ConnectionManager {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String USERNAME ="username";
private static final String PASSWORD = "password";
private static final String URL = "jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8";
static {
try {
Class.forName(DRIVER);
}
catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(DRIVER + " missing in classpath!", e);
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
}
Use it as follows:
public class SomeDAO {
public SomeEntity find(Long id) throws SQLException {
Connection connection = null;
// ...
try {
connection = ConnectionManager.getConnection();
// ...
}
finally {
// ...
if (connection != null) try { connection.close(); } catch(SQLException ignore) {}
}
return someEntity;
}
To improve connecting performance, use a connection pool instead of DriverManager.
See also:
Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern
Are you closing connections properly after using them.