0001: /*
0002: * ============================================================================
0003: * GNU Lesser General Public License
0004: * ============================================================================
0005: *
0006: * JasperReports - Free Java report-generating library.
0007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
0008: *
0009: * This library is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU Lesser General Public
0011: * License as published by the Free Software Foundation; either
0012: * version 2.1 of the License, or (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: * Lesser General Public License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
0022: *
0023: * JasperSoft Corporation
0024: * 303 Second Street, Suite 450 North
0025: * San Francisco, CA 94107
0026: * http://www.jaspersoft.com
0027: */
0028: package net.sf.jasperreports.engine.fill;
0029:
0030: import java.sql.Connection;
0031: import java.util.ArrayList;
0032: import java.util.HashMap;
0033: import java.util.HashSet;
0034: import java.util.List;
0035: import java.util.Locale;
0036: import java.util.Map;
0037: import java.util.MissingResourceException;
0038: import java.util.ResourceBundle;
0039: import java.util.Set;
0040: import java.util.TimeZone;
0041:
0042: import net.sf.jasperreports.engine.JRAbstractScriptlet;
0043: import net.sf.jasperreports.engine.JRDataSource;
0044: import net.sf.jasperreports.engine.JRDataset;
0045: import net.sf.jasperreports.engine.JRDefaultScriptlet;
0046: import net.sf.jasperreports.engine.JRException;
0047: import net.sf.jasperreports.engine.JRExpression;
0048: import net.sf.jasperreports.engine.JRField;
0049: import net.sf.jasperreports.engine.JRGroup;
0050: import net.sf.jasperreports.engine.JRParameter;
0051: import net.sf.jasperreports.engine.JRPropertiesMap;
0052: import net.sf.jasperreports.engine.JRQuery;
0053: import net.sf.jasperreports.engine.JRRuntimeException;
0054: import net.sf.jasperreports.engine.JRSortField;
0055: import net.sf.jasperreports.engine.JRVariable;
0056: import net.sf.jasperreports.engine.JasperCompileManager;
0057: import net.sf.jasperreports.engine.JasperReport;
0058: import net.sf.jasperreports.engine.data.JRSortableDataSource;
0059: import net.sf.jasperreports.engine.design.JRDesignVariable;
0060: import net.sf.jasperreports.engine.query.JRQueryExecuter;
0061: import net.sf.jasperreports.engine.query.JRQueryExecuterFactory;
0062: import net.sf.jasperreports.engine.util.JRClassLoader;
0063: import net.sf.jasperreports.engine.util.JRQueryExecuterUtils;
0064:
0065: import org.apache.commons.logging.Log;
0066: import org.apache.commons.logging.LogFactory;
0067:
0068: /**
0069: * @author Lucian Chirita (lucianc@users.sourceforge.net)
0070: * @version $Id: JRFillDataset.java 1828 2007-08-24 13:58:43Z teodord $
0071: */
0072: public class JRFillDataset implements JRDataset {
0073:
0074: private static final Log log = LogFactory
0075: .getLog(JRFillDataset.class);
0076:
0077: /**
0078: * The filler that created this object.
0079: */
0080: private final JRBaseFiller filler;
0081:
0082: /**
0083: * The template dataset.
0084: */
0085: private final JRDataset parent;
0086:
0087: /**
0088: * Whether this is the main dataset of the report.
0089: */
0090: private final boolean isMain;
0091:
0092: /**
0093: * The dataset query.
0094: */
0095: protected JRQuery query = null;
0096:
0097: private boolean useDatasourceParamValue = false;
0098: private boolean useConnectionParamValue = false;
0099:
0100: /**
0101: * The dataset parameter.
0102: */
0103: protected JRFillParameter[] parameters = null;
0104:
0105: /**
0106: * The dataset parameters indexed by name.
0107: */
0108: protected Map parametersMap = null;
0109:
0110: /**
0111: * The dataset fields.
0112: */
0113: protected JRFillField[] fields = null;
0114:
0115: /**
0116: * The dataset fields indexed by name.
0117: */
0118: protected Map fieldsMap = null;
0119:
0120: /**
0121: * The dataset variables.
0122: */
0123: protected JRFillVariable[] variables = null;
0124:
0125: /**
0126: * The dataset variables indexed by name.
0127: */
0128: protected Map variablesMap = null;
0129:
0130: /**
0131: * Set of {@link VariableCalculationReq VariableCalculationReq} objects.
0132: */
0133: protected Set variableCalculationReqs;
0134:
0135: /**
0136: * The element datasets.
0137: */
0138: protected JRFillElementDataset[] elementDatasets;
0139:
0140: /**
0141: * Used to save the original element datasets when
0142: * {@link #filterElementDatasets(JRFillElementDataset) filterElementDatasets} is called.
0143: */
0144: protected JRFillElementDataset[] origElementDatasets;
0145:
0146: /**
0147: * The dataset groups.
0148: */
0149: protected JRFillGroup[] groups = null;
0150:
0151: /**
0152: * The resource bundle base name.
0153: */
0154: protected String resourceBundleBaseName = null;
0155:
0156: /**
0157: * The resource missing handle type.
0158: */
0159: protected byte whenResourceMissingType;
0160:
0161: /**
0162: * The scriptlet class name.
0163: */
0164: protected String scriptletClassName = null;
0165:
0166: /**
0167: * The data source.
0168: */
0169: protected JRDataSource dataSource = null;
0170:
0171: /**
0172: * The {@link Locale Locale} to be used by the dataset.
0173: */
0174: protected Locale locale = null;
0175:
0176: /**
0177: * The loaded resource bundle.
0178: */
0179: protected ResourceBundle resourceBundle = null;
0180:
0181: /**
0182: * The {@link TimeZone TimeZone} to be used by the dataset.
0183: */
0184: protected TimeZone timeZone = null;
0185:
0186: /**
0187: * The cursor used when iterating the data source.
0188: */
0189: protected int reportCount = 0;
0190:
0191: /**
0192: * The calculator used by the dataset.
0193: */
0194: protected JRCalculator calculator = null;
0195:
0196: /**
0197: * The scriptlet used by the dataset.
0198: */
0199: protected JRAbstractScriptlet scriptlet = null;
0200:
0201: /**
0202: * The value of the {@link JRParameter#REPORT_MAX_COUNT max count} parameter.
0203: */
0204: protected Integer reportMaxCount = null;
0205:
0206: private JRQueryExecuter queryExecuter;
0207:
0208: /**
0209: * Creates a fill dataset object.
0210: * @param filler the filelr
0211: * @param dataset the template dataset
0212: * @param factory the fill object factory
0213: */
0214: protected JRFillDataset(JRBaseFiller filler, JRDataset dataset,
0215: JRFillObjectFactory factory) {
0216: factory.put(dataset, this );
0217:
0218: this .filler = filler;
0219: this .parent = dataset;
0220: this .isMain = dataset.isMainDataset();
0221:
0222: scriptletClassName = dataset.getScriptletClass();
0223: resourceBundleBaseName = dataset.getResourceBundle();
0224: whenResourceMissingType = dataset.getWhenResourceMissingType();
0225:
0226: query = dataset.getQuery();
0227:
0228: setParameters(dataset, factory);
0229:
0230: setFields(dataset, factory);
0231:
0232: setVariables(dataset, factory);
0233:
0234: setGroups(dataset, factory);
0235: }
0236:
0237: private void setParameters(JRDataset dataset,
0238: JRFillObjectFactory factory) {
0239: JRParameter[] jrParameters = dataset.getParameters();
0240: if (jrParameters != null && jrParameters.length > 0) {
0241: parameters = new JRFillParameter[jrParameters.length];
0242: parametersMap = new HashMap();
0243: for (int i = 0; i < parameters.length; i++) {
0244: parameters[i] = factory.getParameter(jrParameters[i]);
0245: parametersMap.put(parameters[i].getName(),
0246: parameters[i]);
0247: }
0248: }
0249: }
0250:
0251: private void setGroups(JRDataset dataset,
0252: JRFillObjectFactory factory) {
0253: JRGroup[] jrGroups = dataset.getGroups();
0254: if (jrGroups != null && jrGroups.length > 0) {
0255: groups = new JRFillGroup[jrGroups.length];
0256: for (int i = 0; i < groups.length; i++) {
0257: groups[i] = factory.getGroup(jrGroups[i]);
0258: }
0259: }
0260: }
0261:
0262: private void setVariables(JRDataset dataset,
0263: JRFillObjectFactory factory) {
0264: JRVariable[] jrVariables = dataset.getVariables();
0265: if (jrVariables != null && jrVariables.length > 0) {
0266: List variableList = new ArrayList(jrVariables.length * 3);
0267:
0268: variablesMap = new HashMap();
0269: for (int i = 0; i < jrVariables.length; i++) {
0270: addVariable(jrVariables[i], variableList, factory);
0271: }
0272:
0273: setVariables(variableList);
0274: }
0275: }
0276:
0277: private JRFillVariable addVariable(JRVariable parentVariable,
0278: List variableList, JRFillObjectFactory factory) {
0279: JRFillVariable variable = factory.getVariable(parentVariable);
0280:
0281: byte calculation = variable.getCalculation();
0282: switch (calculation) {
0283: case JRVariable.CALCULATION_AVERAGE:
0284: case JRVariable.CALCULATION_VARIANCE: {
0285: JRVariable countVar = createHelperVariable(parentVariable,
0286: "_COUNT", JRVariable.CALCULATION_COUNT);
0287: JRFillVariable fillCountVar = addVariable(countVar,
0288: variableList, factory);
0289: variable.setHelperVariable(fillCountVar,
0290: JRCalculable.HELPER_COUNT);
0291:
0292: JRVariable sumVar = createHelperVariable(parentVariable,
0293: "_SUM", JRVariable.CALCULATION_SUM);
0294: JRFillVariable fillSumVar = addVariable(sumVar,
0295: variableList, factory);
0296: variable.setHelperVariable(fillSumVar,
0297: JRCalculable.HELPER_SUM);
0298:
0299: break;
0300: }
0301: case JRVariable.CALCULATION_STANDARD_DEVIATION: {
0302: JRVariable varianceVar = createHelperVariable(
0303: parentVariable, "_VARIANCE",
0304: JRVariable.CALCULATION_VARIANCE);
0305: JRFillVariable fillVarianceVar = addVariable(varianceVar,
0306: variableList, factory);
0307: variable.setHelperVariable(fillVarianceVar,
0308: JRCalculable.HELPER_VARIANCE);
0309:
0310: break;
0311: }
0312: case JRVariable.CALCULATION_DISTINCT_COUNT: {
0313: JRVariable countVar = createDistinctCountHelperVariable(parentVariable);
0314: JRFillVariable fillCountVar = addVariable(countVar,
0315: variableList, factory);
0316: variable.setHelperVariable(fillCountVar,
0317: JRCalculable.HELPER_COUNT);
0318:
0319: break;
0320: }
0321: }
0322:
0323: variableList.add(variable);
0324: return variable;
0325: }
0326:
0327: private JRVariable createHelperVariable(JRVariable variable,
0328: String nameSuffix, byte calculation) {
0329: JRDesignVariable helper = new JRDesignVariable();
0330: helper.setName(variable.getName() + nameSuffix);
0331: helper.setValueClassName(variable.getValueClassName());
0332: helper.setIncrementerFactoryClassName(variable
0333: .getIncrementerFactoryClassName());
0334: helper.setResetType(variable.getResetType());
0335: helper.setResetGroup(variable.getResetGroup());
0336: helper.setIncrementType(variable.getIncrementType());
0337: helper.setIncrementGroup(variable.getIncrementGroup());
0338: helper.setCalculation(calculation);
0339: helper.setSystemDefined(true);
0340: helper.setExpression(variable.getExpression());
0341:
0342: return helper;
0343: }
0344:
0345: private JRVariable createDistinctCountHelperVariable(
0346: JRVariable variable) {
0347: JRDesignVariable helper = new JRDesignVariable();
0348: helper.setName(variable.getName() + "_DISTINCT_COUNT");
0349: helper.setValueClassName(variable.getValueClassName());
0350: helper
0351: .setIncrementerFactoryClassName(JRDistinctCountIncrementerFactory.class
0352: .getName());
0353: helper.setResetType(JRVariable.RESET_TYPE_REPORT);
0354:
0355: if (variable.getIncrementType() != JRVariable.RESET_TYPE_NONE)
0356: helper.setResetType(variable.getIncrementType());
0357:
0358: helper.setResetGroup(variable.getIncrementGroup());
0359: helper.setCalculation(JRVariable.CALCULATION_NOTHING);
0360: helper.setSystemDefined(true);
0361: helper.setExpression(variable.getExpression());
0362:
0363: return helper;
0364: }
0365:
0366: private void setVariables(List variableList) {
0367: variables = new JRFillVariable[variableList.size()];
0368: variables = (JRFillVariable[]) variableList.toArray(variables);
0369:
0370: for (int i = 0; i < variables.length; i++) {
0371: variablesMap.put(variables[i].getName(), variables[i]);
0372: }
0373: }
0374:
0375: private void setFields(JRDataset dataset,
0376: JRFillObjectFactory factory) {
0377: JRField[] jrFields = dataset.getFields();
0378: if (jrFields != null && jrFields.length > 0) {
0379: fields = new JRFillField[jrFields.length];
0380: fieldsMap = new HashMap();
0381: for (int i = 0; i < fields.length; i++) {
0382: fields[i] = factory.getField(jrFields[i]);
0383: fieldsMap.put(fields[i].getName(), fields[i]);
0384: }
0385: }
0386: }
0387:
0388: /**
0389: * Creates the calculator
0390: * @param jasperReport the report
0391: * @throws JRException
0392: */
0393: protected void createCalculator(JasperReport jasperReport)
0394: throws JRException {
0395: setCalculator(createCalculator(jasperReport, this ));
0396: }
0397:
0398: protected void setCalculator(JRCalculator calculator) {
0399: this .calculator = calculator;
0400: }
0401:
0402: protected static JRCalculator createCalculator(
0403: JasperReport jasperReport, JRDataset dataset)
0404: throws JRException {
0405: JREvaluator evaluator = JasperCompileManager.loadEvaluator(
0406: jasperReport, dataset);
0407: return new JRCalculator(evaluator);
0408: }
0409:
0410: /**
0411: * Initializes the calculator.
0412: *
0413: * @throws JRException
0414: */
0415: protected void initCalculator() throws JRException {
0416: calculator.init(this );
0417: }
0418:
0419: /**
0420: * Inherits properties from the report.
0421: */
0422: protected void inheritFromMain() {
0423: if (resourceBundleBaseName == null && !isMain) {
0424: resourceBundleBaseName = filler.mainDataset.resourceBundleBaseName;
0425: whenResourceMissingType = filler.mainDataset.whenResourceMissingType;
0426: }
0427: }
0428:
0429: /**
0430: * Creates the scriptlet.
0431: *
0432: * @return the scriptlet
0433: * @throws JRException
0434: */
0435: protected JRAbstractScriptlet createScriptlet() throws JRException {
0436: JRAbstractScriptlet tmpScriptlet = null;
0437:
0438: if (scriptletClassName != null) {
0439: try {
0440: Class scriptletClass = JRClassLoader
0441: .loadClassForName(scriptletClassName);
0442: tmpScriptlet = (JRAbstractScriptlet) scriptletClass
0443: .newInstance();
0444: } catch (ClassNotFoundException e) {
0445: throw new JRException(
0446: "Error loading scriptlet class : "
0447: + scriptletClassName, e);
0448: } catch (Exception e) {
0449: throw new JRException(
0450: "Error creating scriptlet class instance : "
0451: + scriptletClassName, e);
0452: }
0453: } else {
0454: tmpScriptlet = new JRDefaultScriptlet();
0455: }
0456:
0457: return tmpScriptlet;
0458: }
0459:
0460: /**
0461: * Initializes the element datasets.
0462: *
0463: * @param factory the fill object factory used by the filler
0464: */
0465: protected void initElementDatasets(JRFillObjectFactory factory) {
0466: elementDatasets = factory.getElementDatasets(this );
0467: }
0468:
0469: /**
0470: * Filters the element datasets, leaving only one.
0471: * <p>
0472: * This method is used when a dataset is instantiated by a chart or crosstab.
0473: *
0474: * @param elementDataset the element dataset that should remain
0475: */
0476: protected void filterElementDatasets(
0477: JRFillElementDataset elementDataset) {
0478: origElementDatasets = elementDatasets;
0479: elementDatasets = new JRFillElementDataset[] { elementDataset };
0480: }
0481:
0482: /**
0483: * Restores the original element datasets.
0484: * <p>
0485: * This method should be called after {@link #filterElementDatasets(JRFillElementDataset) filterElementDatasets}.
0486: */
0487: protected void restoreElementDatasets() {
0488: if (origElementDatasets != null) {
0489: elementDatasets = origElementDatasets;
0490: origElementDatasets = null;
0491: }
0492: }
0493:
0494: /**
0495: * Loads the resource bundle corresponding to the resource bundle base name and locale.
0496: */
0497: protected ResourceBundle loadResourceBundle() {
0498: ResourceBundle tmpResourceBundle = null;
0499:
0500: if (resourceBundleBaseName != null) {
0501: ClassLoader classLoader = Thread.currentThread()
0502: .getContextClassLoader();
0503: if (classLoader != null) {
0504: try {
0505: tmpResourceBundle = ResourceBundle
0506: .getBundle(resourceBundleBaseName, locale,
0507: classLoader);
0508: } catch (MissingResourceException e) {
0509: // if (log.isWarnEnabled())
0510: // log.warn("Failure using
0511: // Thread.currentThread().getContextClassLoader() in
0512: // JRClassLoader class. Using
0513: // JRClassLoader.class.getClassLoader() instead.");
0514: }
0515: }
0516:
0517: if (tmpResourceBundle == null) {
0518: classLoader = JRClassLoader.class.getClassLoader();
0519:
0520: if (classLoader == null) {
0521: tmpResourceBundle = ResourceBundle.getBundle(
0522: resourceBundleBaseName, locale);
0523: } else {
0524: tmpResourceBundle = ResourceBundle
0525: .getBundle(resourceBundleBaseName, locale,
0526: classLoader);
0527: }
0528: }
0529: }
0530:
0531: return tmpResourceBundle;
0532: }
0533:
0534: /**
0535: * Reads built-in parameter values from the value map.
0536: *
0537: * @param parameterValues the parameter values
0538: * @throws JRException
0539: */
0540: protected void setParameterValues(Map parameterValues)
0541: throws JRException {
0542: parameterValues.put(JRParameter.REPORT_PARAMETERS_MAP,
0543: parameterValues);
0544:
0545: reportMaxCount = (Integer) parameterValues
0546: .get(JRParameter.REPORT_MAX_COUNT);
0547:
0548: locale = (Locale) parameterValues
0549: .get(JRParameter.REPORT_LOCALE);
0550: if (locale == null) {
0551: locale = Locale.getDefault();
0552: parameterValues.put(JRParameter.REPORT_LOCALE, locale);
0553: }
0554:
0555: resourceBundle = (ResourceBundle) parameterValues
0556: .get(JRParameter.REPORT_RESOURCE_BUNDLE);
0557: if (resourceBundle == null) {
0558: resourceBundle = loadResourceBundle();
0559: if (resourceBundle != null) {
0560: parameterValues.put(JRParameter.REPORT_RESOURCE_BUNDLE,
0561: resourceBundle);
0562: }
0563: }
0564:
0565: timeZone = (TimeZone) parameterValues
0566: .get(JRParameter.REPORT_TIME_ZONE);
0567: if (timeZone == null) {
0568: timeZone = TimeZone.getDefault();
0569: parameterValues.put(JRParameter.REPORT_TIME_ZONE, timeZone);
0570: }
0571:
0572: scriptlet = (JRAbstractScriptlet) parameterValues
0573: .get(JRParameter.REPORT_SCRIPTLET);
0574: if (scriptlet == null) {
0575: scriptlet = createScriptlet();
0576: parameterValues
0577: .put(JRParameter.REPORT_SCRIPTLET, scriptlet);
0578: }
0579: scriptlet.setData(parametersMap, fieldsMap, variablesMap,
0580: groups);
0581:
0582: setFillParameterValues(parameterValues);
0583: }
0584:
0585: protected void initDatasource() throws JRException {
0586: queryExecuter = null;
0587:
0588: dataSource = (JRDataSource) getParameterValue(JRParameter.REPORT_DATA_SOURCE);
0589: if (!useDatasourceParamValue
0590: && (useConnectionParamValue || dataSource == null)) {
0591: dataSource = createQueryDatasource();
0592: setParameter(JRParameter.REPORT_DATA_SOURCE, dataSource);
0593: }
0594:
0595: JRSortField[] sortFields = getSortFields();
0596: if (sortFields != null && sortFields.length > 0) {
0597: dataSource = new JRSortableDataSource(dataSource, fields,
0598: sortFields, locale);
0599: setParameter(JRParameter.REPORT_DATA_SOURCE, dataSource);
0600: }
0601: }
0602:
0603: /**
0604: * Sets the parameter values from the values map.
0605: *
0606: * @param parameterValues the values map
0607: * @throws JRException
0608: */
0609: private void setFillParameterValues(Map parameterValues)
0610: throws JRException {
0611: if (parameters != null && parameters.length > 0) {
0612: for (int i = 0; i < parameters.length; i++) {
0613: Object value = null;
0614: if (parameterValues
0615: .containsKey(parameters[i].getName())) {
0616: value = parameterValues
0617: .get(parameters[i].getName());
0618: } else if (!parameters[i].isSystemDefined()) {
0619: value = calculator.evaluate(parameters[i]
0620: .getDefaultValueExpression(),
0621: JRExpression.EVALUATION_DEFAULT);
0622: if (value != null) {
0623: parameterValues.put(parameters[i].getName(),
0624: value);
0625: }
0626: }
0627: setParameter(parameters[i], value);
0628: }
0629: }
0630: }
0631:
0632: /**
0633: * Creates the data source from a connection.
0634: *
0635: * @return the data source to be used
0636: * @throws JRException
0637: */
0638: private JRDataSource createQueryDatasource() throws JRException {
0639: if (query == null) {
0640: return null;
0641: }
0642:
0643: try {
0644: if (log.isDebugEnabled()) {
0645: log.debug("Fill " + filler.fillerId + ": Creating "
0646: + query.getLanguage() + " query executer");
0647: }
0648:
0649: JRQueryExecuterFactory queryExecuterFactory = JRQueryExecuterUtils
0650: .getQueryExecuterFactory(query.getLanguage());
0651: queryExecuter = queryExecuterFactory.createQueryExecuter(
0652: parent, parametersMap);
0653: filler.fillContext.setRunningQueryExecuter(queryExecuter);
0654:
0655: return queryExecuter.createDatasource();
0656: } finally {
0657: filler.fillContext.clearRunningQueryExecuter();
0658: }
0659: }
0660:
0661: protected void reset() {
0662: useDatasourceParamValue = false;
0663: useConnectionParamValue = false;
0664: }
0665:
0666: /**
0667: * Sets the data source to be used.
0668: *
0669: * @param parameterValues the parameter values
0670: * @param ds the data source
0671: */
0672: protected void setDatasourceParameterValue(Map parameterValues,
0673: JRDataSource ds) {
0674: useDatasourceParamValue = true;
0675:
0676: if (ds != null) {
0677: parameterValues.put(JRParameter.REPORT_DATA_SOURCE, ds);
0678: }
0679: }
0680:
0681: /**
0682: * Sets the JDBC connection to be used.
0683: *
0684: * @param parameterValues the parameter values
0685: * @param conn the connection
0686: */
0687: protected void setConnectionParameterValue(Map parameterValues,
0688: Connection conn) {
0689: useConnectionParamValue = true;
0690:
0691: if (conn != null) {
0692: parameterValues.put(JRParameter.REPORT_CONNECTION, conn);
0693: }
0694: }
0695:
0696: protected void closeDatasource() {
0697: if (queryExecuter != null) {
0698: if (log.isDebugEnabled()) {
0699: log.debug("Fill " + filler.fillerId
0700: + ": closing query executer");
0701: }
0702:
0703: queryExecuter.close();
0704: queryExecuter = null;
0705: }
0706:
0707: reset();
0708: }
0709:
0710: /**
0711: * Starts the iteration on the data source.
0712: */
0713: protected void start() {
0714: reportCount = 0;
0715: }
0716:
0717: /**
0718: * Moves to the next record in the data source.
0719: *
0720: * @return <code>true</code> if the data source was not exhausted
0721: * @throws JRException
0722: */
0723: protected boolean next() throws JRException {
0724: boolean hasNext = false;
0725:
0726: if (dataSource != null) {
0727: boolean includeRow = true;
0728: JRExpression filterExpression = getFilterExpression();
0729: do {
0730: hasNext = advanceDataSource();
0731: if (hasNext) {
0732: setOldValues();
0733:
0734: calculator.estimateVariables();
0735: if (filterExpression != null) {
0736: Boolean filterExprResult = (Boolean) calculator
0737: .evaluate(
0738: filterExpression,
0739: JRExpression.EVALUATION_ESTIMATED);
0740: includeRow = filterExprResult != null
0741: && filterExprResult.booleanValue();
0742: }
0743:
0744: if (!includeRow) {
0745: revertToOldValues();
0746: }
0747: }
0748: } while (hasNext && !includeRow);
0749:
0750: if (hasNext) {
0751: ++reportCount;
0752: }
0753: }
0754:
0755: return hasNext;
0756: }
0757:
0758: protected void setOldValues() throws JRException {
0759: if (fields != null && fields.length > 0) {
0760: for (int i = 0; i < fields.length; i++) {
0761: JRFillField field = fields[i];
0762: field.setPreviousOldValue(field.getOldValue());
0763: field.setOldValue(field.getValue());
0764: field.setValue(dataSource.getFieldValue(field));
0765: }
0766: }
0767:
0768: if (variables != null && variables.length > 0) {
0769: for (int i = 0; i < variables.length; i++) {
0770: JRFillVariable variable = variables[i];
0771: variable.setPreviousOldValue(variable.getOldValue());
0772: variable.setOldValue(variable.getValue());
0773: }
0774: }
0775: }
0776:
0777: protected void revertToOldValues() {
0778: if (fields != null && fields.length > 0) {
0779: for (int i = 0; i < fields.length; i++) {
0780: JRFillField field = fields[i];
0781: field.setValue(field.getOldValue());
0782: field.setOldValue(field.getPreviousOldValue());
0783: }
0784: }
0785:
0786: if (variables != null && variables.length > 0) {
0787: for (int i = 0; i < variables.length; i++) {
0788: JRFillVariable variable = variables[i];
0789: variable.setValue(variable.getOldValue());
0790: variable.setOldValue(variable.getPreviousOldValue());
0791: }
0792: }
0793: }
0794:
0795: protected boolean advanceDataSource() throws JRException {
0796: boolean hasNext;
0797: hasNext = (reportMaxCount == null || reportMaxCount.intValue() > reportCount)
0798: && dataSource.next();
0799: return hasNext;
0800: }
0801:
0802: /**
0803: * Sets the value of a parameter.
0804: *
0805: * @param parameterName the parameter name
0806: * @param value the value
0807: * @throws JRException
0808: */
0809: protected void setParameter(String parameterName, Object value)
0810: throws JRException {
0811: JRFillParameter parameter = (JRFillParameter) parametersMap
0812: .get(parameterName);
0813: if (parameter != null) {
0814: setParameter(parameter, value);
0815: }
0816: }
0817:
0818: /**
0819: * Sets the value of the parameter.
0820: *
0821: * @param parameter the parameter
0822: * @param value the value
0823: * @throws JRException
0824: */
0825: protected void setParameter(JRFillParameter parameter, Object value)
0826: throws JRException {
0827: if (value != null) {
0828: if (parameter.getValueClass().isInstance(value)) {
0829: parameter.setValue(value);
0830: } else {
0831: throw new JRException("Incompatible "
0832: + value.getClass().getName()
0833: + " value assigned to parameter "
0834: + parameter.getName() + " in the " + getName()
0835: + " dataset.");
0836: }
0837: } else {
0838: parameter.setValue(value);
0839: }
0840: }
0841:
0842: /**
0843: * Returns the value of a variable.
0844: *
0845: * @param variableName the variable name
0846: * @return the variable value
0847: */
0848: public Object getVariableValue(String variableName) {
0849: JRFillVariable var = (JRFillVariable) variablesMap
0850: .get(variableName);
0851: if (var == null) {
0852: throw new JRRuntimeException("No such variable "
0853: + variableName);
0854: }
0855: return var.getValue();
0856: }
0857:
0858: /**
0859: * Returns the value of a parameter.
0860: *
0861: * @param parameterName the parameter name
0862: * @return the parameter value
0863: */
0864: public Object getParameterValue(String parameterName) {
0865: return getParameterValue(parameterName, false);
0866: }
0867:
0868: /**
0869: * Returns the value of a parameter.
0870: *
0871: * @param parameterName the parameter name
0872: * @param ignoreMissing if set, <code>null</code> will be returned for inexisting parameters
0873: * @return the parameter value
0874: */
0875: public Object getParameterValue(String parameterName,
0876: boolean ignoreMissing) {
0877: JRFillParameter param = (JRFillParameter) parametersMap
0878: .get(parameterName);
0879: Object value;
0880: if (param == null) {
0881: if (!ignoreMissing) {
0882: throw new JRRuntimeException("No such parameter "
0883: + parameterName);
0884: }
0885:
0886: value = null;//FIXME look into REPORT_PARAMETERS_MAP? not yet required.
0887: } else {
0888: value = param.getValue();
0889: }
0890: return value;
0891: }
0892:
0893: /**
0894: * Returns the value of a field.
0895: *
0896: * @param fieldName the field name
0897: * @return the field value
0898: */
0899: public Object getFieldValue(String fieldName) {
0900: JRFillField var = (JRFillField) fieldsMap.get(fieldName);
0901: if (var == null) {
0902: throw new JRRuntimeException("No such field " + fieldName);
0903: }
0904: return var.getValue();
0905: }
0906:
0907: /**
0908: * Class used to hold expression calculation requirements.
0909: */
0910: protected static class VariableCalculationReq {
0911: String variableName;
0912:
0913: byte calculation;
0914:
0915: VariableCalculationReq(String variableName, byte calculation) {
0916: this .variableName = variableName;
0917: this .calculation = calculation;
0918: }
0919:
0920: public boolean equals(Object o) {
0921: if (o == null || !(o instanceof VariableCalculationReq)) {
0922: return false;
0923: }
0924:
0925: VariableCalculationReq r = (VariableCalculationReq) o;
0926:
0927: return variableName.equals(r.variableName)
0928: && calculation == r.calculation;
0929: }
0930:
0931: public int hashCode() {
0932: return 31 * calculation + variableName.hashCode();
0933: }
0934: }
0935:
0936: /**
0937: * Adds a variable calculation requirement.
0938: *
0939: * @param variableName the variable name
0940: * @param calculation the required calculation
0941: */
0942: protected void addVariableCalculationReq(String variableName,
0943: byte calculation) {
0944: if (variableCalculationReqs == null) {
0945: variableCalculationReqs = new HashSet();
0946: }
0947:
0948: variableCalculationReqs.add(new VariableCalculationReq(
0949: variableName, calculation));
0950: }
0951:
0952: /**
0953: * Checks if there are variable calculation requirements and creates the required variables.
0954: *
0955: * @param factory the fill object factory
0956: */
0957: protected void checkVariableCalculationReqs(
0958: JRFillObjectFactory factory) {
0959: if (variableCalculationReqs != null
0960: && !variableCalculationReqs.isEmpty()) {
0961: List variableList = new ArrayList(variables.length * 2);
0962:
0963: for (int i = 0; i < variables.length; i++) {
0964: JRFillVariable variable = variables[i];
0965: checkVariableCalculationReq(variable, variableList,
0966: factory);
0967: }
0968:
0969: setVariables(variableList);
0970: }
0971: }
0972:
0973: private void checkVariableCalculationReq(JRFillVariable variable,
0974: List variableList, JRFillObjectFactory factory) {
0975: if (hasVariableCalculationReq(variable,
0976: JRVariable.CALCULATION_AVERAGE)
0977: || hasVariableCalculationReq(variable,
0978: JRVariable.CALCULATION_VARIANCE)) {
0979: if (variable.getHelperVariable(JRCalculable.HELPER_COUNT) == null) {
0980: JRVariable countVar = createHelperVariable(variable,
0981: "_COUNT", JRVariable.CALCULATION_COUNT);
0982: JRFillVariable fillCountVar = factory
0983: .getVariable(countVar);
0984: checkVariableCalculationReq(fillCountVar, variableList,
0985: factory);
0986: variable.setHelperVariable(fillCountVar,
0987: JRCalculable.HELPER_COUNT);
0988: }
0989:
0990: if (variable.getHelperVariable(JRCalculable.HELPER_SUM) == null) {
0991: JRVariable sumVar = createHelperVariable(variable,
0992: "_SUM", JRVariable.CALCULATION_SUM);
0993: JRFillVariable fillSumVar = factory.getVariable(sumVar);
0994: checkVariableCalculationReq(fillSumVar, variableList,
0995: factory);
0996: variable.setHelperVariable(fillSumVar,
0997: JRCalculable.HELPER_SUM);
0998: }
0999: }
1000:
1001: if (hasVariableCalculationReq(variable,
1002: JRVariable.CALCULATION_STANDARD_DEVIATION)) {
1003: if (variable
1004: .getHelperVariable(JRCalculable.HELPER_VARIANCE) == null) {
1005: JRVariable varianceVar = createHelperVariable(variable,
1006: "_VARIANCE", JRVariable.CALCULATION_VARIANCE);
1007: JRFillVariable fillVarianceVar = factory
1008: .getVariable(varianceVar);
1009: checkVariableCalculationReq(fillVarianceVar,
1010: variableList, factory);
1011: variable.setHelperVariable(fillVarianceVar,
1012: JRCalculable.HELPER_VARIANCE);
1013: }
1014: }
1015:
1016: if (hasVariableCalculationReq(variable,
1017: JRVariable.CALCULATION_DISTINCT_COUNT)) {
1018: if (variable.getHelperVariable(JRCalculable.HELPER_COUNT) == null) {
1019: JRVariable countVar = createDistinctCountHelperVariable(variable);
1020: JRFillVariable fillCountVar = factory
1021: .getVariable(countVar);
1022: checkVariableCalculationReq(fillCountVar, variableList,
1023: factory);
1024: variable.setHelperVariable(fillCountVar,
1025: JRCalculable.HELPER_COUNT);
1026: }
1027: }
1028:
1029: variableList.add(variable);
1030: }
1031:
1032: private boolean hasVariableCalculationReq(JRVariable var,
1033: byte calculation) {
1034: return variableCalculationReqs
1035: .contains(new VariableCalculationReq(var.getName(),
1036: calculation));
1037: }
1038:
1039: public String getName() {
1040: return parent.getName();
1041: }
1042:
1043: public String getScriptletClass() {
1044: return parent.getScriptletClass();
1045: }
1046:
1047: public JRParameter[] getParameters() {
1048: return parameters;
1049: }
1050:
1051: public Map getParametersMap() {
1052: return parametersMap;
1053: }
1054:
1055: public JRQuery getQuery() {
1056: return query;
1057: }
1058:
1059: public JRField[] getFields() {
1060: return fields;
1061: }
1062:
1063: public JRSortField[] getSortFields() {
1064: return parent.getSortFields();
1065: }
1066:
1067: public JRVariable[] getVariables() {
1068: return variables;
1069: }
1070:
1071: public JRGroup[] getGroups() {
1072: return groups;
1073: }
1074:
1075: public boolean isMainDataset() {
1076: return isMain;
1077: }
1078:
1079: public String getResourceBundle() {
1080: return parent.getResourceBundle();
1081: }
1082:
1083: public byte getWhenResourceMissingType() {
1084: return whenResourceMissingType;
1085: }
1086:
1087: public void setWhenResourceMissingType(byte whenResourceMissingType) {
1088: this .whenResourceMissingType = whenResourceMissingType;
1089: }
1090:
1091: public JRPropertiesMap getPropertiesMap() {
1092: return parent.getPropertiesMap();
1093: }
1094:
1095: public JRExpression getFilterExpression() {
1096: return parent.getFilterExpression();
1097: }
1098: }
|