/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core;
import org.pentaho.reporting.engine.classic.core.metadata.DataFactoryMetaData;
import org.pentaho.reporting.libraries.base.util.ArgumentNullException;
import org.pentaho.reporting.libraries.base.util.LinkedMap;
import javax.swing.table.TableModel;
import java.util.ArrayList;
/**
* The compound data factory is a collection of data-factories. Each of the child datafactories is queried in the order
* of their addition to the collection.
*
* @author Thomas Morgner
*/
public class CompoundDataFactory extends AbstractDataFactory implements CompoundDataFactorySupport {
private ArrayList<DataFactory> dataFactories;
public CompoundDataFactory() {
dataFactories = new ArrayList<DataFactory>();
}
public void initialize( final DataFactoryContext dataFactoryContext ) throws ReportDataFactoryException {
super.initialize( dataFactoryContext );
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
dataFactory.initialize( dataFactoryContext );
}
}
/**
* Queries a datasource. The string 'query' defines the name of the query. The Parameterset given here may contain
* more data than actually needed for the query.
* <p/>
* The parameter-dataset may change between two calls, do not assume anything, and do not hold references to the
* parameter-dataset or the position of the columns in the dataset.
*
* @param query
* the query string
* @param parameters
* the parameters for the query
* @return the result of the query as table model.
* @throws ReportDataFactoryException
* if an error occured while performing the query.
*/
public final TableModel queryData( final String query, final DataRow parameters ) throws ReportDataFactoryException {
ArgumentNullException.validate( "query", query );
ArgumentNullException.validate( "parameters", parameters );
final TableModel staticResult = queryStatic( query, parameters );
if ( staticResult != null ) {
return staticResult;
}
final TableModel freeFormResult = queryFreeForm( query, parameters );
if ( freeFormResult != null ) {
return freeFormResult;
}
return handleFallThrough( query );
}
public TableModel queryDesignTimeStructureFreeForm( final String query, final DataRow parameters )
throws ReportDataFactoryException {
return postProcess( query, parameters, queryDesignTimeStructFreeFormInternal( query, parameters ) );
}
private TableModel queryDesignTimeStructFreeFormInternal( final String query, final DataRow parameters )
throws ReportDataFactoryException {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isFreeFormQueryExecutable( query, parameters ) ) {
return support.queryDesignTimeStructureFreeForm( query, parameters );
}
} else if ( isFreeFormQueryDataFactory( dataFactory ) && dataFactory.isQueryExecutable( query, parameters ) ) {
if ( dataFactory instanceof DataFactoryDesignTimeSupport ) {
DataFactoryDesignTimeSupport dts = (DataFactoryDesignTimeSupport) dataFactory;
return dts.queryDesignTimeStructure( query, parameters );
} else {
return dataFactory.queryData( query, new DataRowWrapper( parameters ) );
}
}
}
return null;
}
public TableModel queryFreeForm( final String query, final DataRow parameters ) throws ReportDataFactoryException {
return postProcess( query, parameters, queryFreeFormInternal( query, parameters ) );
}
private TableModel queryFreeFormInternal( final String query, final DataRow parameters )
throws ReportDataFactoryException {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isFreeFormQueryExecutable( query, parameters ) ) {
return support.queryFreeForm( query, parameters );
}
} else if ( isFreeFormQueryDataFactory( dataFactory ) && dataFactory.isQueryExecutable( query, parameters ) ) {
return dataFactory.queryData( query, parameters );
}
}
return null;
}
public TableModel queryDesignTimeStructureStatic( final String query, final DataRow parameters )
throws ReportDataFactoryException {
return postProcess( query, parameters, queryDesignTimeStructStaticInternal( query, parameters ) );
}
private TableModel queryDesignTimeStructStaticInternal( final String query, final DataRow parameters )
throws ReportDataFactoryException {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isStaticQueryExecutable( query, parameters ) ) {
return support.queryDesignTimeStructureStatic( query, parameters );
}
} else if ( ( isFreeFormQueryDataFactory( dataFactory ) == false )
&& dataFactory.isQueryExecutable( query, parameters ) ) {
if ( dataFactory instanceof DataFactoryDesignTimeSupport ) {
DataFactoryDesignTimeSupport dts = (DataFactoryDesignTimeSupport) dataFactory;
return dts.queryDesignTimeStructure( query, parameters );
} else {
return dataFactory.queryData( query, new DataRowWrapper( parameters ) );
}
}
}
return null;
}
public TableModel queryStatic( final String query, final DataRow parameters ) throws ReportDataFactoryException {
return postProcess( query, parameters, queryStaticInternal( query, parameters ) );
}
protected TableModel postProcess( final String query, final DataRow parameters, final TableModel tableModel ) {
return tableModel;
}
private TableModel queryStaticInternal( final String query, final DataRow parameters )
throws ReportDataFactoryException {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isStaticQueryExecutable( query, parameters ) ) {
return support.queryStatic( query, parameters );
}
} else if ( ( isFreeFormQueryDataFactory( dataFactory ) == false )
&& dataFactory.isQueryExecutable( query, parameters ) ) {
return dataFactory.queryData( query, parameters );
}
}
return null;
}
public TableModel queryDesignTimeStructure( final String query, final DataRow parameters )
throws ReportDataFactoryException {
ArgumentNullException.validate( "query", query );
ArgumentNullException.validate( "parameters", parameters );
final TableModel staticResult = queryDesignTimeStructureStatic( query, parameters );
if ( staticResult != null ) {
return staticResult;
}
final TableModel freeFormResult = queryDesignTimeStructureFreeForm( query, parameters );
if ( freeFormResult != null ) {
return freeFormResult;
}
return handleFallThrough( query );
}
protected TableModel handleFallThrough( final String query ) throws ReportDataFactoryException {
throw new ReportDataFactoryException( "None of the data-factories was able to handle this query." );
}
private boolean isFreeFormQueryDataFactory( final DataFactory dataFactory ) {
final DataFactoryMetaData metaData = dataFactory.getMetaData();
if ( metaData.isFreeFormQuery() ) {
return true;
}
return false;
}
/**
* Returns a copy of the data factory that is not affected by its anchestor and holds no connection to the anchestor
* anymore. A data-factory will be derived at the beginning of the report processing.
*
* @return a copy of the data factory.
*/
public DataFactory derive() {
final CompoundDataFactory cdf = deriveEmpty();
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
cdf.dataFactories.add( dataFactory.derive() );
}
return cdf;
}
public CompoundDataFactory deriveEmpty() {
final CompoundDataFactory cdf = (CompoundDataFactory) clone();
cdf.dataFactories = (ArrayList<DataFactory>) dataFactories.clone();
cdf.dataFactories.clear();
return cdf;
}
/**
* Closes the data factory and frees all resources held by this instance.
*/
public void close() {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
dataFactory.close();
}
}
/**
* Checks whether the query would be executable by this datafactory. This performs a rough check, not a full query.
*
* @param query
* query name.
* @param parameters
* the parameters for the query.
* @return true, if the query may be executable, false, if no datasource claims the query.
*/
public final boolean isQueryExecutable( final String query, final DataRow parameters ) {
return isStaticQueryExecutable( query, parameters ) || isFreeFormQueryExecutable( query, parameters );
}
public boolean isFreeFormQueryExecutable( final String query, final DataRow parameters ) {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isFreeFormQueryExecutable( query, parameters ) ) {
return true;
}
} else if ( ( isFreeFormQueryDataFactory( dataFactory ) ) && dataFactory.isQueryExecutable( query, parameters ) ) {
return true;
}
}
return false;
}
public boolean isStaticQueryExecutable( final String query, final DataRow parameters ) {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport support = (CompoundDataFactorySupport) dataFactory;
if ( support.isStaticQueryExecutable( query, parameters ) ) {
return true;
}
} else if ( ( isFreeFormQueryDataFactory( dataFactory ) == false )
&& dataFactory.isQueryExecutable( query, parameters ) ) {
return true;
}
}
return false;
}
protected void addRaw( final DataFactory factory ) {
if ( factory == null ) {
throw new NullPointerException();
}
dataFactories.add( factory );
}
public void add( final DataFactory factory ) {
if ( factory == null ) {
throw new NullPointerException();
}
final DataFactory derived = factory.derive();
if ( derived == null ) {
throw new IllegalStateException( "Deriving failed silently. Fix your implementation of " + factory.getClass() );
}
dataFactories.add( derived );
}
public void add( final int index, final DataFactory factory ) {
if ( factory == null ) {
throw new NullPointerException();
}
final DataFactory derived = factory.derive();
if ( derived == null ) {
throw new InvalidReportStateException( "Deriving failed silently. Fix your implementation of "
+ factory.getClass() );
}
dataFactories.add( index, derived );
}
public void set( final int index, final DataFactory factory ) {
if ( factory == null ) {
throw new NullPointerException();
}
final DataFactory derived = factory.derive();
if ( derived == null ) {
throw new InvalidReportStateException( "Deriving failed silently. Fix your implementation of "
+ factory.getClass() );
}
dataFactories.set( index, derived );
}
public void remove( final int index ) {
dataFactories.remove( index );
}
public void remove( final DataFactory dataFactory ) {
dataFactories.remove( dataFactory );
}
public int size() {
return dataFactories.size();
}
public DataFactory get( final int idx ) {
final DataFactory df = dataFactories.get( idx );
return df.derive();
}
public int indexOfByReference( final DataFactory d ) {
for ( int i = 0; i < size(); i++ ) {
final DataFactory df = getReference( i );
if ( df == d ) {
return i;
}
}
return -1;
}
public DataFactory getReference( final int idx ) {
return dataFactories.get( idx );
}
public boolean isNormalized() {
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
if ( dataFactory instanceof CompoundDataFactory ) {
return false;
}
}
return true;
}
public static CompoundDataFactory normalize( final DataFactory dataFactory ) {
return normalize( dataFactory, true );
}
protected CompoundDataFactory normalizeInternal( boolean derive ) {
final CompoundDataFactory retval = deriveEmpty();
final int size = size();
for ( int i = 0; i < size; i++ ) {
final DataFactory original = getReference( i );
if ( original instanceof CompoundDataFactory ) {
final CompoundDataFactory container = normalize( original, derive );
final int containerSize = container.size();
for ( int x = 0; x < containerSize; x++ ) {
if ( derive ) {
retval.add( container.getReference( x ) );
} else {
retval.addRaw( container.getReference( x ) );
}
}
} else {
if ( derive ) {
retval.add( original );
} else {
retval.addRaw( original );
}
}
}
return retval;
}
public static CompoundDataFactory normalize( final DataFactory dataFactory, final boolean derive ) {
if ( dataFactory == null ) {
return new CompoundDataFactory();
}
if ( dataFactory instanceof CompoundDataFactory == false ) {
final CompoundDataFactory retval = new CompoundDataFactory();
if ( derive ) {
retval.add( dataFactory );
} else {
retval.addRaw( dataFactory );
}
return retval;
}
final CompoundDataFactory cdf = (CompoundDataFactory) dataFactory;
if ( cdf.isNormalized() ) {
if ( derive ) {
return (CompoundDataFactory) cdf.derive();
}
return cdf;
}
return cdf.normalizeInternal( derive );
}
public String[] getQueryNames() {
final LinkedMap nameSet = new LinkedMap();
for ( int i = 0; i < dataFactories.size(); i++ ) {
final DataFactory dataFactory = dataFactories.get( i );
final String[] queryNames = dataFactory.getQueryNames();
for ( int j = 0; j < queryNames.length; j++ ) {
final String queryName = queryNames[j];
nameSet.put( queryName, queryName );
}
}
return (String[]) nameSet.keys( new String[nameSet.size()] );
}
public DataFactory getDataFactoryForQuery( final String queryName, final boolean freeform ) {
final DataRow dr = new StaticDataRow();
for ( int i = 0; i < size(); i++ ) {
final DataFactory df = dataFactories.get( i );
if ( df instanceof CompoundDataFactorySupport ) {
final CompoundDataFactorySupport cdf = (CompoundDataFactorySupport) df;
final DataFactory r = cdf.getDataFactoryForQuery( queryName, freeform );
if ( r != null ) {
return r;
}
}
if ( ( isFreeFormQueryDataFactory( df ) == freeform ) && df.isQueryExecutable( queryName, dr ) ) {
return df;
}
}
return null;
}
public DataFactory getDataFactoryForQuery( final String queryName ) {
final DataFactory nonFreeForm = getDataFactoryForQuery( queryName, false );
if ( nonFreeForm != null ) {
return nonFreeForm;
}
final DataFactory freeForm = getDataFactoryForQuery( queryName, true );
if ( freeForm != null ) {
return freeForm;
}
return null;
}
}