/*
* 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 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core;
import java.util.ArrayList;
import javax.swing.table.TableModel;
import org.pentaho.reporting.engine.classic.core.metadata.DataFactoryMetaData;
import org.pentaho.reporting.engine.classic.core.metadata.DataFactoryRegistry;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.base.util.LinkedMap;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
/**
* 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 implements Cloneable, DataFactory
{
private ArrayList<DataFactory> dataFactories;
public CompoundDataFactory()
{
dataFactories = new ArrayList<DataFactory>();
}
public void initialize(final Configuration configuration,
final ResourceManager resourceManager,
final ResourceKey contextKey,
final ResourceBundleFactory resourceBundleFactory)
{
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
dataFactory.initialize(configuration, resourceManager, contextKey, resourceBundleFactory);
}
}
public void open() throws ReportDataFactoryException
{
}
/**
* 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 TableModel queryData(final String query, final DataRow parameters) throws ReportDataFactoryException
{
if (parameters == null)
{
throw new NullPointerException();
}
if (query == null)
{
throw new NullPointerException();
}
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
if ((isFreeFormQueryDataFactory(dataFactory) == false) && dataFactory.isQueryExecutable(query, parameters))
{
return dataFactory.queryData(query, parameters);
}
}
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
if (isFreeFormQueryDataFactory(dataFactory) && dataFactory.isQueryExecutable(query, parameters))
{
return dataFactory.queryData(query, parameters);
}
}
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 DataFactoryRegistry registry = DataFactoryRegistry.getInstance();
final String metaDataKey = dataFactory.getClass().getName();
if (registry.isRegistered(metaDataKey) == false)
{
// assume the worst ..
return true;
}
final DataFactoryMetaData metaData = registry.getMetaData(metaDataKey);
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 = (CompoundDataFactory) clone();
cdf.dataFactories = (ArrayList<DataFactory>) dataFactories.clone();
cdf.dataFactories.clear();
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
cdf.dataFactories.add(dataFactory.derive());
}
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 boolean isQueryExecutable(final String query, final DataRow parameters)
{
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
if ((isFreeFormQueryDataFactory(dataFactory) == false) && dataFactory.isQueryExecutable(query, parameters))
{
return true;
}
}
for (int i = 0; i < dataFactories.size(); i++)
{
final DataFactory dataFactory = dataFactories.get(i);
if ((isFreeFormQueryDataFactory(dataFactory)) && dataFactory.isQueryExecutable(query, parameters))
{
return true;
}
}
return false;
}
/**
* Creates and returns a copy of this object.
*
* @return a clone.
*/
public Object clone()
{
try
{
return super.clone();
}
catch (CloneNotSupportedException e)
{
throw new IllegalStateException(e);
}
}
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) throws ReportDataFactoryException
{
if (factory == null)
{
throw new NullPointerException();
}
final DataFactory derived = factory.derive();
if (derived == null)
{
throw new ReportDataFactoryException(
"Deriving failed silently. Fix your implementation of " + factory.getClass());
}
dataFactories.add(index, derived);
}
public void set(final int index, final DataFactory factory) throws ReportDataFactoryException
{
if (factory == null)
{
throw new NullPointerException();
}
final DataFactory derived = factory.derive();
if (derived == null)
{
throw new ReportDataFactoryException(
"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 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);
}
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;
}
final CompoundDataFactory retval = new CompoundDataFactory();
final int size = cdf.size();
for (int i = 0; i < size; i++)
{
final DataFactory original = cdf.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 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 void cancelRunningQuery()
{
// TODO implement
}
protected 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 CompoundDataFactory)
{
final CompoundDataFactory cdf = (CompoundDataFactory) 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, false);
if (freeForm != null)
{
return freeForm;
}
return null;
}
}