groups[i] = new ArrayList( );
groups[i] = new CachedList( GroupInfo.getCreator( ) );
	public void doGrouping( ) throws DataException	{		assert this.groupCalculationUtil.getResultSetCache( ) != null;		// Pass through sorted data set to process group indexes		groups = new ArrayList[this.groupCalculationUtil.getGroupDefn( ).length];		if ( groups.length == 0 )			return;		for ( int i = 0; i < this.groupCalculationUtil.getGroupDefn( ).length; i++ )		{			groups[i] = new ArrayList( );		}		IResultObject prevRow = null;		for ( int rowID = 0; rowID < this.groupCalculationUtil.getResultSetCache( )				.getCount( ); rowID++ )		{			IResultObject currRow = this.groupCalculationUtil.getResultSetCache( )					.fetch( );			// breakLevel is the outermost group number to differentiate row			// data			int breakLevel;			if ( rowID == 0 )				breakLevel = 0; // Special case for first row			else				breakLevel = getBreakLevel( currRow, prevRow, rowID );			// Create a new group in each group level between			// [ breakLevel ... groupDefs.length - 1]			for ( int level = breakLevel; level < groups.length; level++ )			{				GroupInfo group = new GroupInfo( );				if ( level != 0 )					group.parent = groups[level - 1].size( ) - 1;				if ( level == groups.length - 1 )				{					// at leaf group level, first child is the first row, which					// is current row					group.firstChild = rowID;				}				else				{					// Our first child is the group to be created at the next					// level					// in the next loop					group.firstChild = groups[level + 1].size( );				}				groups[level].add( group );			}			prevRow = currRow;		}		// this method must be called, since after doing group,		// the current row index needs to adjusted the start value of data.		this.groupCalculationUtil.getResultSetCache( ).reset( );		this.setLeaveGroupIndex( 0 );	}