// Path: src/main/java/info/gianlucacosta/easypmd/pmdscanner/ScanMessage.java
// public interface ScanMessage extends Serializable {
// 
//     boolean isShowableInGuardedSections();
// 
//     int getLineNumber();
// 
//     Task createTask(Options options, FileObject fileObject);
// 
//     Annotation createAnnotation(Options options);
// }
// 
// Path: src/main/java/info/gianlucacosta/easypmd/util/Throwables.java
// public interface Throwables {
// 
//     /**
//      * Converts the stack trace of a Throwable to a string
//      *
//      * @param throwable
//      * @return the string representation of the stack trace
//      */
//     static String getStackTraceString(Throwable throwable) {
//         final Writer result = new StringWriter();
//         final PrintWriter printWriter = new PrintWriter(result);
// 
//         throwable.printStackTrace(printWriter);
// 
//         return result.toString();
//     }
// 
//     /**
//      * Returns the throwable message, or the message of its cause, recursively,
//      * or a simple message if no message was found in the chain
//      *
//      * @param throwable The subject throwable
//      * @return a non-empty string
//      */
//     static String getNonEmptyMessage(Throwable throwable) {
//         String message = throwable.getMessage();
// 
//         if (message == null || message.isEmpty()) {
//             Throwable cause = throwable.getCause();
// 
//             if (cause != null) {
//                 return getNonEmptyMessage(cause);
//             } else {
//                 return "(no message)";
//             }
//         } else {
//             return message;
//         }
//     }
// 
//     /**
//      * Returns a string showing a Throwable (type and message) and the related
//      * stack trace
//      *
//      * @param throwable
//      * @return
//      */
//     static String toStringWithStackTrace(Throwable throwable) {
//         return String.format(
//                 "%s (%s)\n%s",
//                 throwable.getClass().getName(),
//                 throwable.getMessage(),
//                 getStackTraceString(throwable)
//         );
//     }
// }


import java.sql.SQLException;
import java.sql.Statement;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Logger;
import info.gianlucacosta.easypmd.pmdscanner.ScanMessage;
import info.gianlucacosta.easypmd.util.Throwables;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

            return Optional.empty();
        }
    }

    @Override
    public void putEntry(String pathString, CacheEntry cacheEntry) {
        try {
            updateStatement.setLong(1, cacheEntry.getLastModificationMillis());
            updateStatement.setObject(2, cacheEntry.getScanMessages());
            updateStatement.setString(3, pathString);
            if (updateStatement.executeUpdate() == 0) {
                insertStatement.setString(1, pathString);
                insertStatement.setLong(2, cacheEntry.getLastModificationMillis());
                insertStatement.setObject(3, cacheEntry.getScanMessages());

                if (insertStatement.executeUpdate() == 0) {
                    throw new IllegalStateException(
                            String.format(
                                    "Neither UPDATE nor INSERT could add messages to the cache for path: %s",
                                    pathString
                            )
                    );
                }
            }
        } catch (Exception ex) {
            logger.warning(
                    () -> String.format(
                            "Could not write to db-cache messages for path: %s.\nCause: %s",
                            pathString,
// Path: src/main/java/info/gianlucacosta/easypmd/pmdscanner/ScanMessage.java
// public interface ScanMessage extends Serializable {
// 
//     boolean isShowableInGuardedSections();
// 
//     int getLineNumber();
// 
//     Task createTask(Options options, FileObject fileObject);
// 
//     Annotation createAnnotation(Options options);
// }
// 
// Path: src/main/java/info/gianlucacosta/easypmd/util/Throwables.java
// public interface Throwables {
// 
//     /**
//      * Converts the stack trace of a Throwable to a string
//      *
//      * @param throwable
//      * @return the string representation of the stack trace
//      */
//     static String getStackTraceString(Throwable throwable) {
//         final Writer result = new StringWriter();
//         final PrintWriter printWriter = new PrintWriter(result);
// 
//         throwable.printStackTrace(printWriter);
// 
//         return result.toString();
//     }
// 
//     /**
//      * Returns the throwable message, or the message of its cause, recursively,
//      * or a simple message if no message was found in the chain
//      *
//      * @param throwable The subject throwable
//      * @return a non-empty string
//      */
//     static String getNonEmptyMessage(Throwable throwable) {
//         String message = throwable.getMessage();
// 
//         if (message == null || message.isEmpty()) {
//             Throwable cause = throwable.getCause();
// 
//             if (cause != null) {
//                 return getNonEmptyMessage(cause);
//             } else {
//                 return "(no message)";
//             }
//         } else {
//             return message;
//         }
//     }
// 
//     /**
//      * Returns a string showing a Throwable (type and message) and the related
//      * stack trace
//      *
//      * @param throwable
//      * @return
//      */
//     static String toStringWithStackTrace(Throwable throwable) {
//         return String.format(
//                 "%s (%s)\n%s",
//                 throwable.getClass().getName(),
//                 throwable.getMessage(),
//                 getStackTraceString(throwable)
//         );
//     }
// }


// Path: src/main/java/info/gianlucacosta/easypmd/pmdscanner/messages/cache/HsqlDbStorage.java
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Logger;
import info.gianlucacosta.easypmd.pmdscanner.ScanMessage;
import info.gianlucacosta.easypmd.util.Throwables;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;


            return Optional.empty();
        }
    }

    @Override
    public void putEntry(String pathString, CacheEntry cacheEntry) {
        try {
            updateStatement.setLong(1, cacheEntry.getLastModificationMillis());
            updateStatement.setObject(2, cacheEntry.getScanMessages());
            updateStatement.setString(3, pathString);
            if (updateStatement.executeUpdate() == 0) {
                insertStatement.setString(1, pathString);
                insertStatement.setLong(2, cacheEntry.getLastModificationMillis());
                insertStatement.setObject(3, cacheEntry.getScanMessages());

                if (insertStatement.executeUpdate() == 0) {
                    throw new IllegalStateException(
                            String.format(
                                    "Neither UPDATE nor INSERT could add messages to the cache for path: %s",
                                    pathString
                            )
                    );
                }
            }
        } catch (Exception ex) {
            logger.warning(
                    () -> String.format(
                            "Could not write to db-cache messages for path: %s.\nCause: %s",
                            pathString,
                            Throwables.toStringWithStackTrace(ex)