/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * 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 Lesser General Public License * for more details. * * Last commit: $Rev: 1549 $ by $Author: glycoslave $ on $Date:: 2009-07-19 #$ */ package org.eurocarbdb.action; // stdlib imports import java.util.Date; import java.util.List; import java.util.Vector; import java.util.Collections; // 3rd party imports import org.apache.log4j.Logger; import org.apache.commons.lang.ArrayUtils; // eurocarb imports import org.eurocarbdb.dataaccess.EntityManager; import org.eurocarbdb.dataaccess.EurocarbObject; import org.eurocarbdb.dataaccess.EntityDoesntExistException; import org.eurocarbdb.dataaccess.indexes.Index; import org.eurocarbdb.dataaccess.indexes.Indexable; // static imports import static org.eurocarbdb.dataaccess.Eurocarb.getEntityManager; /** * Base class for various browsing-oriented actions that retrieve a {@link List} of * data objects given an offset and max list size, potentially also ordered by a * settable {@link Index} type. */ @ParameterChecking( whitelist={"resultsPerPage","page","indexedBy"} ) public abstract class BrowseAction<T> extends EurocarbAction implements PageableAction, Indexable<T> { /** logging handle */ static Logger log = Logger.getLogger( BrowseAction.class ); // /// object variables /** The {@link List} of results to be browsed by this {@link Action}. */ protected List<T> results = null; /** Total number of objects of type 'T' that are browseable by this {@link Action}. * Initially set to -1, indicating "not yet set or initialised". */ protected int totalResults = -1; private int resultsPerPage = 20; private int currentPageNumber = 1; /** String version of input sequence. */ private String sequence; // output message private String message = ""; /** * Override the parameters whitelist method, so that we can inject the * whitelist for parameters that this class adds */ @Override protected String[] parametersWhitelist() { String[] superWhitelist = super.parametersWhitelist(); ParameterChecking security = BrowseAction.class.getAnnotation(ParameterChecking.class); if (security != null) { return (String[]) ArrayUtils.addAll(superWhitelist,security.whitelist()); } return null; } /** * Override the parameters blacklist method, so that we can inject the * blacklist for parameters that this class adds */ @Override protected String[] parametersBlacklist() { String[] superBlacklist = super.parametersBlacklist(); ParameterChecking security = BrowseAction.class.getAnnotation(ParameterChecking.class); if (security != null) { return (String[]) ArrayUtils.addAll(superBlacklist,security.blacklist()); } return null; } // /// object methods public int getResultsPerPage() { return resultsPerPage; } public void setResultsPerPage( int i ) { if ( i > 100 ) { log.warn( "resultsPerPage = " + i + " > max (100), setting to 100..." ); i = 100; } log.debug("resultsPerPage set to " + i ); resultsPerPage = i; } public int getPage() { return currentPageNumber; } public void setPage( int n ) { log.debug("page set to " + n ); currentPageNumber = n; } /** * Calculates what would be the last page of results, given the * values returned from {@link #getTotalResults} and {@link #getResultsPerPage}. */ public int getLastPage() { return (int)Math.ceil((double)getTotalResults()/(double)getResultsPerPage()); } public int getFirstShowing(int page) { return Math.min(getTotalResults(),(page-1)*getResultsPerPage()); } /** * Returns the index of the last entry that would be shown on the * given page number, from the current values of {@link #getResultsPerPage} * and {@link #getTotalResults}. */ public int getLastShowing( int page ) { return Math.max( 0, Math.min( getTotalResults(), page * getResultsPerPage() ) - 1 ); } public int getFirstShowing() { return getFirstShowing(getPage()); } public int getLastShowing() { return getLastShowing(getPage()); } public int getOffset() { return Math.min( (getPage() - 1) * getResultsPerPage(), getTotalResults() ); } public int getMaxResults() { return Math.max( Math.min( getOffset() + getResultsPerPage(), getTotalResults() ) - getOffset(), 0 ); } public List<T> getResults() { return results; } public void setResults( List<T> list ) { if( list == null ) results = Collections.emptyList(); //new java.util.ArrayList<T>(); else results = list; } public void setAllResults(List<T> list) { if( list == null ) { setResults( Collections.EMPTY_LIST ); setTotalResults(0); } else { setTotalResults( list.size() ); // setResults( list.subList( getOffset(), getOffset() + getMaxResults()) ); int first_index = getOffset(); if ( first_index < 0 ) first_index = 0; int last_index = first_index + getMaxResults(); setResults( list.subList( first_index, last_index ) ); } } public String getMessage() { return message; } public void setMessage(String strMessage) { message = strMessage; } /** * Returns the total number of objects of generic type 'T'. */ public int getTotalResults() { if ( totalResults < 0 ) { log.warn( "totalResults has not been calculated/set, " + "which means that other properties that rely on this value " + "are probably going to be wrong. Please override this method " + "in subclasses or otherwise call setTotalResults(int) to avoid " + "this messsage." ); } return totalResults; } /** Explicitly sets the total number of results browseable by this {@link Action}. */ protected void setTotalResults( int count ) { log.debug("totalResults set to " + count ); this.totalResults = count; } /*~~~~~ implementation of Indexable ~~~~~*/ /** The index with which to order results, initially null. * If equal to Index.NONE, results are returned in default * order (arbitrary, but stable order). */ protected Index<T> index = null; public abstract Class<T> getIndexableType() ; public Index<T> getDefaultIndex() { return (Index<T>) Index.NONE; } public Index<T> getIndex() { if ( this.index == null ) return getDefaultIndex(); return this.index; } public List<Index<T>> getIndexes() { return Collections.emptyList(); } public void setIndexedBy( String name ) { if ( name == null || name.length() == 0 ) { this.index = getDefaultIndex(); } for ( Index i : getIndexes() ) { if ( name.equals( i.getName() ) ) { this.index = i; return; } } } } // end class