/*
* Copyright (C) 2000 - 2012 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://openbd.org/
* $Id: cfOUTPUT.java 2217 2012-07-27 12:38:10Z alan $
*/
package com.naryx.tagfusion.cfm.tag;
import java.io.Serializable;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfQueryInterface;
import com.naryx.tagfusion.cfm.engine.cfQueryResultData;
import com.naryx.tagfusion.cfm.engine.cfSession;
import com.naryx.tagfusion.cfm.engine.cfStructData;
import com.naryx.tagfusion.cfm.engine.cfmBadFileException;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
import com.naryx.tagfusion.cfm.parser.runTime;
public class cfOUTPUT extends cfTag implements Serializable {
static final long serialVersionUID = 1;
public java.util.Map getInfo(){
return createInfo("output", "Inside a CFOUTPUT tag, all CFML variables will be processed for output to the browser, and can also be used to loop a query for output of each row.");
}
public java.util.Map[] getAttInfo(){
return new java.util.Map[] {
createAttInfo("ATTRIBUTECOLLECTION", "A structure containing the tag attributes", "", false ),
createAttInfo("QUERY", "Providing a query to this tag will allow it to act like a CFLOOP and iterate over the query for outputting its values.", "", false ),
createAttInfo("GROUP", "The column name to be used for grouping the records of a query. This attribute is only used if a 'QUERY' has been provided.", "", false ),
createAttInfo("STARTROW", "The first row of a query to be output. This attribute is only used if a 'QUERY' has been provided.", "1", false ),
createAttInfo("MAXROWS", "The maximum number of query rows to output. This attribute is only used if a 'QUERY' has been provided.", "-1", false ),
createAttInfo("GROUPCASESENSITIVE", "If set to 'YES' then the case will be considered when grouping records of a query. This attribute is only used if the 'GROUP' attribute has been provided.", "YES", false )
};
}
public boolean doesTagHaveEmbeddedPoundSigns() {
return true;
}
protected void defaultParameters( String _tag ) throws cfmBadFileException {
parseTagHeader( _tag );
}
public String getEndMarker(){ return "</CFOUTPUT>"; }
public cfTagReturnType render(cfSession _Session) throws cfmRunTimeException {
cfStructData attributes = setAttributeCollection(_Session);
boolean processingCfOutput = _Session.setProcessingCfOutput(true);
try {
// This may be a CFOUTPUT for a query
cfQueryInterface queryData = null;
cfData queryDataTmp = null; // used till we can determine the query data is the right type
String QUERY = null;
if ( containsAttribute(attributes,"QUERY") ) { // INVARIANT : on exiting this if, queryData != null
QUERY = getDynamic(attributes,_Session, "QUERY").getString();
try {
queryDataTmp = runTime.runExpression(_Session, QUERY);
} catch (cfmRunTimeException ignored) {
} // queryDataTmp doesn't exist
// throw exceptions if the query doesn't exist or is not the right type. Cast it if it is.
if (queryDataTmp == null) {
throw newRunTimeException("The specified QUERY " + QUERY + " does not exist.");
} else if (queryDataTmp instanceof cfQueryInterface) {
queryData = (cfQueryInterface) queryDataTmp;
} else {
throw newRunTimeException("The specified QUERY " + QUERY + " is not a valid query type.");
}
}
if (queryData != null) {
int resetRow = queryData.getCurrentRow();
int startRow = containsAttribute("STARTROW") ? getDynamic(attributes,_Session, "STARTROW").getInt() : 1;
int maxRows = containsAttribute("MAXROWS") ? getDynamic(attributes,_Session, "MAXROWS").getInt() : -1;
int rowCount = 0;
queryData.reset();
_Session.pushQuery((cfQueryResultData) queryData);
boolean isGroupBy = containsAttribute(attributes,"GROUP");
// Check for the GROUPBY stuff
if (isGroupBy) {
boolean groupSensitive = containsAttribute(attributes, "GROUPCASESENSITIVE") ? getDynamic(attributes,_Session, "GROUPCASESENSITIVE").getBoolean() : true;
queryData.setGroupBy(getDynamic(attributes,_Session, "GROUP").getString(), groupSensitive );
}
while (queryData.nextRow()) {
rowCount++;
// Get ourselves up to the start
if (rowCount < startRow)
continue;
// Send the data out
cfTagReturnType rt = super.render( _Session );
if ( rt.isBreak() || rt.isReturn() ) {
cleanupQueryData(_Session, queryData, resetRow, isGroupBy);
return rt;
}
// Determine if the maximum rows have been reached
if ( maxRows != -1 && rowCount == (startRow + maxRows - 1) )
break;
}
cleanupQueryData(_Session, queryData, resetRow, isGroupBy);
} else { // queryData == null (i.e. QUERY attribute not specified)
queryData = _Session.peekQuery();
if (queryData != null && queryData.isGrouped()) {
if (containsAttribute("GROUP")) {
int resetRow = queryData.getCurrentRow();
boolean groupSensitive = containsAttribute(attributes, "GROUPCASESENSITIVE") ? getDynamic(attributes,_Session, "GROUPCASESENSITIVE").getBoolean() : true;
queryData.setGroupBy(getDynamic(attributes,_Session, "GROUP").getString(), groupSensitive );
do {
cfTagReturnType rt = super.render( _Session );
if ( rt.isBreak() || rt.isReturn() ) {
queryData.removeGroupBy();
queryData.setCurrentRow( resetRow == 0 ? 1 : resetRow );
return rt;
}
} while (queryData.nextRow());
queryData.removeGroupBy();
queryData.setCurrentRow( resetRow == 0 ? 1 : resetRow );
} else {
return renderQueryGrouped(_Session, queryData);
}
} else {
return super.render(_Session);
}
}
} finally {
_Session.setProcessingCfOutput(processingCfOutput);
}
return cfTagReturnType.NORMAL;
}
public static void cleanupQueryData(cfSession _Session, cfQueryInterface queryData, int resetRow, boolean _isGroupBy) {
queryData.finishQuery();
_Session.popQuery();
if ( _isGroupBy )
queryData.removeGroupBy();
queryData.setCurrentRow( resetRow == 0 ? 1 : resetRow );
}
private cfTagReturnType renderQueryGrouped( cfSession _Session, cfQueryInterface queryData ) throws cfmRunTimeException {
queryData.startGroupOutput();
while ( queryData.nextRowInGroup() ) {
cfTagReturnType rt = super.render( _Session );
if ( rt.isBreak() || rt.isReturn() ) {
queryData.endGroupOutput();
return rt;
}
}
queryData.endGroupOutput();
return cfTagReturnType.NORMAL;
}
}