/**
* Copyright (c) 2009--2014 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.common.db.datasource;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Replacement for DataResult.
* Used for displayed lists for which the data comes from database queries.
* Main functionality: elaborates the data right before it is requested so
* that only the subset of data needed is elaborated and nobody needs to
* remember to elaborate the list.
*
* Differences from DataResult:
* DataList elaborates on its own, DataResult had to be told.
* DataList contains no pagination data, expecting the UI to handle that
* whereas DataResult contained start, end, and total size data expecting UI
* to deal directly with these methods rather than just those of a list.
* @param <E> the type of the objects to be used in this list.
* @version $Rev$
*/
public class DataList<E> extends ArrayList<E> {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = -4742688110496214350L;
private static final Logger LOG = Logger.getLogger(DataList.class);
//used for elaborating only
private SelectMode mode;
private Map elaboratorParams;
//switch to turn on or off automatic elaboration
private boolean autoElab = true;
/**
* Helper method so that one can get a dataresult through the usual way
* of querying database with a driving query from a datasource select mode.
* @param m Datasource's SelectMode
* @param params Driving query parameters.
* @param elabParams Elaborator parameters.
* @return A new DataList object containing the results of the driving query.
*/
public static DataList getDataList(SelectMode m, Map params, Map elabParams) {
if (m == null || params == null || elabParams == null) {
throw new NullPointerException("Parameters for getDataList cannot " +
"be null. Maps may be empty if necessary.");
}
//get driving query results
DataList retval = new DataList(m.execute(params));
//prepare to elaborate
retval.setMode(m);
retval.setElaboratorParams(elabParams);
return retval;
}
/**
* Collection constructor for special cases. Also used internally.
* @param c The collection.
*/
public DataList(Collection c) {
super(c);
}
/**
* Elaborates this DataList. This is private because you should
* never have to call it explicitly.
*/
private void elaborate() {
if (mode != null && elaboratorParams != null) {
if (autoElab) {
/*
* If we were to simply send this object to elaborate, it
* would eventually ask for an iterator on this object which
* would in turn call this function creating a large loop.
* To avoid this, turn off automatic elaboration.
*/
autoElab = false;
mode.elaborate(this, elaboratorParams);
//we are done, turn automatic elaboration back to what it was.
}
}
else {
LOG.warn("mode or elaborator params is null. When these are null, " +
"DataList functions exactly the same as ArrayList.");
}
}
/**
* {@inheritDoc}
*/
public List subList(int start, int end) {
//The act of asking for a subList will access the list,
//which would normally cause the list to elaborate. This
//would violate the 'elaborate as late as possible' idea.
boolean temp = autoElab;
autoElab = false;
//create a sublist
DataList retval = new DataList(super.subList(start, end));
//set autoElab back to what it was.
autoElab = temp;
//copy non-list attributes to new sublist.
retval.setMode(mode);
retval.setElaboratorParams(elaboratorParams);
//don't want to elaborate again.
retval.setAutoElab(autoElab);
return retval;
}
/**
* {@inheritDoc}
*/
public E get(int arg0In) {
elaborate();
return super.get(arg0In);
}
/**
* {@inheritDoc}
*/
public Iterator<E> iterator() {
//they will be dealing with anything in this list, so elaborate
//everything. Hopefully they are dealing with a sublist.
elaborate();
return super.iterator();
}
/**
* {@inheritDoc}
*/
public ListIterator<E> listIterator() {
//they will be dealing with anything in this list, so elaborate
//everything. Hopefully they are dealing with a sublist.
elaborate();
return super.listIterator();
}
/**
* {@inheritDoc}
*/
public ListIterator<E> listIterator(int arg) {
//they will be dealing with anything in this list, so elaborate
//everything. Hopefully they are dealing with a sublist.
elaborate();
return super.listIterator(arg);
}
/**
* {@inheritDoc}
*/
public Object[] toArray() {
//they will be dealing with anything in this list, so elaborate
//everything. Hopefully they are dealing with a sublist.
elaborate();
return super.toArray();
}
/**
* {@inheritDoc}
*/
public Object[] toArray(Object[] arg) {
//they will be dealing with anything in this list, so elaborate
//everything. Hopefully they are dealing with a sublist.
elaborate();
return super.toArray(arg);
}
/**
* @return Returns the elaboratorParams.
*/
public Map getElaboratorParams() {
return elaboratorParams;
}
/**
* @param elaboratorParamsIn The elaboratorParams to set.
*/
public void setElaboratorParams(Map elaboratorParamsIn) {
elaboratorParams = elaboratorParamsIn;
}
/**
* @return Returns the mode.
*/
public SelectMode getMode() {
return mode;
}
/**
* @param modeIn The mode to set.
*/
public void setMode(SelectMode modeIn) {
mode = modeIn;
}
private void setAutoElab(boolean b) {
autoElab = b;
}
/**
* {@inheritDoc}
*
* Prints meta-data about the list instead of the list itself.
* Prevents a database call to elaborate by not accessing the
* data of the list.
*/
public String toString() {
StringBuilder buffy = new StringBuilder();
buffy.append("DataList(");
buffy.append("mode:");
buffy.append(mode.toString());
buffy.append(" ");
buffy.append("elabParams:");
buffy.append(elaboratorParams.toString());
buffy.append(" ");
buffy.append("elaborated:");
buffy.append(!autoElab);
buffy.append(")");
return buffy.toString();
}
}