All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xdev.db.jdbc.CachedVTPageScroller Maven / Gradle / Ivy

package xdev.db.jdbc;

/*-
 * #%L
 * XDEV Application Framework
 * %%
 * Copyright (C) 2003 - 2020 XDEV Software
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */


import java.lang.ref.SoftReference;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

import xdev.vt.VirtualTable;


/**
 * This class extends VTPageScroller by a means of caching page VTs
 * that have already been loaded.
* The page caching is based on start row index and page row count.
* Cached pages are held in soft references, meaning they are released as soon * as memory runs low. * * @author Thomas Muenz */ public class CachedVTPageScroller extends VTPageScroller { // ///////////////////////////////////////////////////////////////////////// // instance fields // // ////////////////// private final HashMap> cachedPages = new HashMap>(); // ///////////////////////////////////////////////////////////////////////// // static methods // // ///////////////// /** * Null safe retrieval of a VirtualTable object from a * SoftReference object. * * @param ref * the SoftReference object that points to a * VirtualTable object or null. * @return null if ref is null or the * VirtualTable object that is referenced by * ref. */ private static final VirtualTable getVTFromReference(final SoftReference ref) { return ref == null ? null : ref.get(); } /** * Creates a new Long object from two ints * rowIndexFrom and rowCount defining a page for * use as a hash key.
* * @param rowIndexFrom * the row index in the original ResultSet object of * the first row int the page * @param rowCount * the number of rows in the page. * @return a Long object combining both int values to a single * hash key value. */ protected static final Long createHashKey(final int rowIndexFrom, final int rowCount) { return (((long)rowIndexFrom) << 32) + rowCount; } // ///////////////////////////////////////////////////////////////////////// // constructors // // /////////////// /** * Creates a new CachedVTPageScroller object by calling * super(rs). * * @param rs * the scrollable ResultSet object to be used for * the to be created CachedVTPageScroller object. * @throws SQLException * if rs is not scrollable or * rs.getType() throws a SQLExcpetion */ public CachedVTPageScroller(final ResultSet rs) throws SQLException { super(rs); } /** * Creates a new CachedVTPageScroller object by calling * super(rs, rowsPerPage). * * @param rs * the scrollable ResultSet object to be used for * the to be created CachedVTPageScroller object. * @param rowsPerPage * the number of rows to be retrieved per "page". * @throws SQLException * if rs is not scrollable or * rs.getType() throws a SQLExcpetion */ public CachedVTPageScroller(final ResultSet rs, int rowsPerPage) throws SQLException { super(rs,rowsPerPage); } /** * Creates a new CachedVTPageScroller object by calling * super(rs, rowsPerPage, firstRowIndex). * * @param rs * the scrollable ResultSet object to be used for * the to be created CachedVTPageScroller object. * @param rowsPerPage * the number of rows to be retrieved per "page". * @param firstRowIndex * the current row index of the first row in the first "page" to * be created. * @throws SQLException * if rs is not scrollable or * rs.getType() throws a SQLExcpetion */ public CachedVTPageScroller(final ResultSet rs, final int rowsPerPage, final int firstRowIndex) throws SQLException { super(rs,rowsPerPage,firstRowIndex); } /** * Creates a new CachedVTPageScroller object by calling * super(rs, rowsPerPage, firstRowIndex, totalRows). * * @param rs * the scrollable ResultSet object to be used for * the to be created CachedVTPageScroller object. * @param rowsPerPage * the number of rows to be retrieved per "page". * @param firstRowIndex * the current row index of the first row in the first "page" to * be created. * @param totalRows * a hint to how much rows the ResultSet object * provides in total. * @throws SQLException * if rs is not scrollable or * rs.getType() throws a SQLExcpetion */ public CachedVTPageScroller(final ResultSet rs, final int rowsPerPage, final int firstRowIndex, final Integer totalRows) throws SQLException { super(rs,rowsPerPage,firstRowIndex,totalRows); } // ///////////////////////////////////////////////////////////////////////// // getters // // /////////////////// /** * @return the cachedPages */ protected HashMap> getCachedPages() { return this.cachedPages; } // ///////////////////////////////////////////////////////////////////////// // setters // // /////////////////// /** * {@inheritDoc} */ @Override public CachedVTPageScroller setAllowNegativeRowIndex(boolean allowNegativePosition) { super.setAllowNegativeRowIndex(allowNegativePosition); return this; } /** * {@inheritDoc} */ @Override public CachedVTPageScroller setCurrentRowIndex(int currentRowIndex) { super.setCurrentRowIndex(currentRowIndex); return this; } /** * {@inheritDoc} */ @Override public CachedVTPageScroller setRowsPerPage(int rowsPerPage) { super.setRowsPerPage(rowsPerPage); return this; } /** * {@inheritDoc} */ @Override public CachedVTPageScroller setTotalRows(Integer totalRows) { super.setTotalRows(totalRows); return this; } // ///////////////////////////////////////////////////////////////////////// // override methods // // /////////////////// /** * Sets the cursor (current row) of the wrapped scrollable * ResultSet object to rowIndexFrom and creates a * new VirtualTable object from that row on with a length of * rowCount rows. *

* Additionally, the created VirtualTable object is cached.
* Cached VT objects will be reused by methods like * currentPage(), nextPage(), * previousPage() if rowIndexFrom and * rowCount of the page they request fit to a already cached VT * object. * * @param rowIndexFrom * the index of the ResultSet object row to be the * first row of the created "page". * @param rowCount * the amount of rows to be contained in the created "page" * @return a newly created VirtualTable object with rows from * rowIndexFrom till * (rowIndexFrom + rowCount). * @throws SQLException * any SQLException that can be thrown in the process by the * ResultSet implementation */ @Override public VirtualTable createVirtualTable(final int rowIndexFrom, final int rowCount) throws SQLException { final VirtualTable vt = super.createVirtualTable(rowIndexFrom,rowCount); this.putCachedVirtualTable(vt,rowIndexFrom,rowCount); return vt; } /** * Returns the page with the current getRowsPerPage() rows as a * VirtualTable object.
* If a fitting VT object is found in the cache, it is returned. Otherwise a * new VirtualTable object is created. * * @return a fitting already existing or else newly created * VirtualTable object with the current * getRowsPerPage() rows. * @throws SQLException * any SQLException that can be thrown by the * ResultSet implementation in the process. */ @Override public VirtualTable currentPage() throws SQLException { final VirtualTable vt = this.getCachedVirtualTable(this.getCurrentRowIndex(), this.getRowsPerPage()); return vt != null ? vt : super.currentPage(); } /** * Returns the page with the next getRowsPerPage() rows as a * VirtualTable object.
* If a fitting VT object is found in the cache, it is returned. Otherwise a * new VirtualTable object is created. * * @return a fitting already existing or else newly created * VirtualTable object with the next * getRowsPerPage() rows or null if no next * page is available according to totalRows. * @throws SQLException * any SQLException that can be thrown by the * ResultSet implementation in the process. */ @Override public VirtualTable nextPage() throws SQLException { final Boolean b = this.hasNextPage(); if(b == null ? false : !b) return null; // if(isFalse(this.hasNextPage())) return null; final int rowsPerPage = this.getRowsPerPage(); final int nextPageIndex = this.getCurrentRowIndex() + rowsPerPage; final VirtualTable vt = this.getCachedVirtualTable(nextPageIndex,rowsPerPage); if(vt != null) { this.setCurrentRowIndex(nextPageIndex); return vt; } else { return this.nextPageNoCheck(); } } /** * Returns the page with the previous getRowsPerPage() rows as * a VirtualTable object.
* If a fitting VT object is found in the cache, it is returned. Otherwise a * new VirtualTable object is created. * * @return a fitting already existing or else newly created * VirtualTable object with the previous * getRowsPerPage() rows. * @throws SQLException * any SQLException that can be thrown by the * ResultSet implementation in the process. */ @Override public VirtualTable previousPage() throws SQLException { if(!this.hasPreviousPage()) return null; final int rowsPerPage = this.getRowsPerPage(); final int prevPageIndex = this.getCurrentRowIndex() - rowsPerPage; final VirtualTable vt = this.getCachedVirtualTable(prevPageIndex,rowsPerPage); if(vt != null) { this.setCurrentRowIndex(prevPageIndex); return vt; } else { return this.previousPageNoCheck(); } } // ///////////////////////////////////////////////////////////////////////// // declared methods // // /////////////////// /** * Puts vt into the cache with a key derived from * rowIndexFrom and rowCount. * * @param vt * the VirtualTable object to be cached. * @param rowIndexFrom * the row index in the scrollable ResultSet object * used to create vt that describes the first row of * vt. * @param rowCount * the number of rows for which vt has been created. * @return the VirtualTable object that was cached for the * equal key before. */ protected VirtualTable putCachedVirtualTable(final VirtualTable vt, final int rowIndexFrom, final int rowCount) { synchronized(this.cachedPages) { final Long hashKey = createHashKey(rowIndexFrom,rowCount); return getVTFromReference(this.cachedPages.put(hashKey,new SoftReference( vt))); } } /** * Retrieves the VirtualTable object from the cache that has * been cached for rowIndexFrom and rowCount. * * @param rowIndexFrom * the row index in the scrollable ResultSet object * used to create vt that describes the first row of * vt. * @param rowCount * the number of rows the searched vt shall contain. * @return */ protected VirtualTable getCachedVirtualTable(final int rowIndexFrom, final int rowCount) { synchronized(this.cachedPages) { return getVTFromReference(this.cachedPages.get(createHashKey(rowIndexFrom,rowCount))); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy