package net.sf.jasperreports.engine.fill; import java.sql.Connection; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.TimeZone; import net.sf.jasperreports.engine.JRAbstractScriptlet; import net.sf.jasperreports.engine.JRDataSource; import net.sf.jasperreports.engine.JRDataset; import net.sf.jasperreports.engine.JRDefaultScriptlet; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRField; import net.sf.jasperreports.engine.JRGroup; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRPropertiesHolder; import net.sf.jasperreports.engine.JRPropertiesMap; import net.sf.jasperreports.engine.JRQuery; import net.sf.jasperreports.engine.JRRuntimeException; import net.sf.jasperreports.engine.JRSortField; import net.sf.jasperreports.engine.JRVariable; import net.sf.jasperreports.engine.JasperCompileManager; import net.sf.jasperreports.engine.JasperReport; import net.sf.jasperreports.engine.data.JRSortableDataSource; import net.sf.jasperreports.engine.design.JRDesignVariable; import net.sf.jasperreports.engine.query.JRQueryExecuter; import net.sf.jasperreports.engine.query.JRQueryExecuterFactory; import net.sf.jasperreports.engine.util.JRClassLoader; import net.sf.jasperreports.engine.util.JRQueryExecuterUtils; import net.sf.jasperreports.engine.util.JRResourcesUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class JRFillDataset implements JRDataset { private static final Log log = LogFactory.getLog(JRFillDataset.class); private final JRBaseFiller filler; private final JRDataset parent; private final boolean isMain; protected JRQuery query = null; private boolean useDatasourceParamValue = false; private boolean useConnectionParamValue = false; protected JRFillParameter[] parameters = null; protected Map parametersMap = null; protected JRFillField[] fields = null; protected Map fieldsMap = null; protected JRFillVariable[] variables = null; protected Map variablesMap = null; protected Set variableCalculationReqs; protected JRFillElementDataset[] elementDatasets; protected JRFillElementDataset[] origElementDatasets; protected JRFillGroup[] groups = null; protected String resourceBundleBaseName = null; protected byte whenResourceMissingType; protected String scriptletClassName = null; protected JRDataSource dataSource = null; protected Locale locale = null; protected ResourceBundle resourceBundle = null; protected TimeZone timeZone = null; protected int reportCount = 0; protected JRCalculator calculator = null; protected JRAbstractScriptlet scriptlet = null; protected Integer reportMaxCount = null; private JRQueryExecuter queryExecuter; protected JRFillDataset(JRBaseFiller filler, JRDataset dataset, JRFillObjectFactory factory) { factory.put(dataset, this); this.filler = filler; this.parent = dataset; this.isMain = dataset.isMainDataset(); this.scriptletClassName = dataset.getScriptletClass(); this.resourceBundleBaseName = dataset.getResourceBundle(); this.whenResourceMissingType = dataset.getWhenResourceMissingType(); this.query = dataset.getQuery(); setParameters(dataset, factory); setFields(dataset, factory); setVariables(dataset, factory); setGroups(dataset, factory); } private void setParameters(JRDataset dataset, JRFillObjectFactory factory) { JRParameter[] jrParameters = dataset.getParameters(); if (jrParameters != null && jrParameters.length > 0) { this.parameters = new JRFillParameter[jrParameters.length]; this.parametersMap = new HashMap(); for (int i = 0; i < this.parameters.length; i++) { this.parameters[i] = factory.getParameter(jrParameters[i]); this.parametersMap.put(this.parameters[i].getName(), this.parameters[i]); } } } private void setGroups(JRDataset dataset, JRFillObjectFactory factory) { JRGroup[] jrGroups = dataset.getGroups(); if (jrGroups != null && jrGroups.length > 0) { this.groups = new JRFillGroup[jrGroups.length]; for (int i = 0; i < this.groups.length; i++) this.groups[i] = factory.getGroup(jrGroups[i]); } } private void setVariables(JRDataset dataset, JRFillObjectFactory factory) { JRVariable[] jrVariables = dataset.getVariables(); if (jrVariables != null && jrVariables.length > 0) { List variableList = new ArrayList(jrVariables.length * 3); this.variablesMap = new HashMap(); for (int i = 0; i < jrVariables.length; i++) addVariable(jrVariables[i], variableList, factory); setVariables(variableList); } } private JRFillVariable addVariable(JRVariable parentVariable, List variableList, JRFillObjectFactory factory) { JRVariable jRVariable1, varianceVar, countVar; JRFillVariable jRFillVariable1, fillVarianceVar, fillCountVar; JRVariable sumVar; JRFillVariable fillSumVar, variable = factory.getVariable(parentVariable); byte calculation = variable.getCalculation(); switch (calculation) { case 3: case 7: jRVariable1 = createHelperVariable(parentVariable, "_COUNT", (byte)1); jRFillVariable1 = addVariable(jRVariable1, variableList, factory); variable.setHelperVariable(jRFillVariable1, (byte)0); sumVar = createHelperVariable(parentVariable, "_SUM", (byte)2); fillSumVar = addVariable(sumVar, variableList, factory); variable.setHelperVariable(fillSumVar, (byte)1); break; case 6: varianceVar = createHelperVariable(parentVariable, "_VARIANCE", (byte)7); fillVarianceVar = addVariable(varianceVar, variableList, factory); variable.setHelperVariable(fillVarianceVar, (byte)2); break; case 10: countVar = createDistinctCountHelperVariable(parentVariable); fillCountVar = addVariable(countVar, variableList, factory); variable.setHelperVariable(fillCountVar, (byte)0); break; } variableList.add(variable); return variable; } private JRVariable createHelperVariable(JRVariable variable, String nameSuffix, byte calculation) { JRDesignVariable helper = new JRDesignVariable(); helper.setName(variable.getName() + nameSuffix); helper.setValueClassName(variable.getValueClassName()); helper.setIncrementerFactoryClassName(variable.getIncrementerFactoryClassName()); helper.setResetType(variable.getResetType()); helper.setResetGroup(variable.getResetGroup()); helper.setIncrementType(variable.getIncrementType()); helper.setIncrementGroup(variable.getIncrementGroup()); helper.setCalculation(calculation); helper.setSystemDefined(true); helper.setExpression(variable.getExpression()); return (JRVariable)helper; } private JRVariable createDistinctCountHelperVariable(JRVariable variable) { JRDesignVariable helper = new JRDesignVariable(); helper.setName(variable.getName() + "_DISTINCT_COUNT"); helper.setValueClassName(variable.getValueClassName()); helper.setIncrementerFactoryClassName(JRDistinctCountIncrementerFactory.class.getName()); helper.setResetType((byte)1); if (variable.getIncrementType() != 5) helper.setResetType(variable.getIncrementType()); helper.setResetGroup(variable.getIncrementGroup()); helper.setCalculation((byte)0); helper.setSystemDefined(true); helper.setExpression(variable.getExpression()); return (JRVariable)helper; } private void setVariables(List variableList) { this.variables = new JRFillVariable[variableList.size()]; this.variables = (JRFillVariable[])variableList.toArray((Object[])this.variables); for (int i = 0; i < this.variables.length; i++) this.variablesMap.put(this.variables[i].getName(), this.variables[i]); } private void setFields(JRDataset dataset, JRFillObjectFactory factory) { JRField[] jrFields = dataset.getFields(); if (jrFields != null && jrFields.length > 0) { this.fields = new JRFillField[jrFields.length]; this.fieldsMap = new HashMap(); for (int i = 0; i < this.fields.length; i++) { this.fields[i] = factory.getField(jrFields[i]); this.fieldsMap.put(this.fields[i].getName(), this.fields[i]); } } } protected void createCalculator(JasperReport jasperReport) throws JRException { setCalculator(createCalculator(jasperReport, this)); } protected void setCalculator(JRCalculator calculator) { this.calculator = calculator; } protected static JRCalculator createCalculator(JasperReport jasperReport, JRDataset dataset) throws JRException { JREvaluator evaluator = JasperCompileManager.loadEvaluator(jasperReport, dataset); return new JRCalculator(evaluator); } protected void initCalculator() throws JRException { this.calculator.init(this); } protected void inheritFromMain() { if (this.resourceBundleBaseName == null && !this.isMain) { this.resourceBundleBaseName = this.filler.mainDataset.resourceBundleBaseName; this.whenResourceMissingType = this.filler.mainDataset.whenResourceMissingType; } } protected JRAbstractScriptlet createScriptlet() throws JRException { JRDefaultScriptlet jRDefaultScriptlet; JRAbstractScriptlet tmpScriptlet = null; if (this.scriptletClassName != null) { try { Class scriptletClass = JRClassLoader.loadClassForName(this.scriptletClassName); tmpScriptlet = scriptletClass.newInstance(); } catch (ClassNotFoundException e) { throw new JRException("Error loading scriptlet class : " + this.scriptletClassName, e); } catch (Exception e) { throw new JRException("Error creating scriptlet class instance : " + this.scriptletClassName, e); } } else { jRDefaultScriptlet = new JRDefaultScriptlet(); } return (JRAbstractScriptlet)jRDefaultScriptlet; } protected void initElementDatasets(JRFillObjectFactory factory) { this.elementDatasets = factory.getElementDatasets(this); } protected void filterElementDatasets(JRFillElementDataset elementDataset) { this.origElementDatasets = this.elementDatasets; this.elementDatasets = new JRFillElementDataset[] { elementDataset }; } protected void restoreElementDatasets() { if (this.origElementDatasets != null) { this.elementDatasets = this.origElementDatasets; this.origElementDatasets = null; } } protected ResourceBundle loadResourceBundle() { ResourceBundle loadedBundle; if (this.resourceBundleBaseName == null) { loadedBundle = null; } else { loadedBundle = JRResourcesUtil.loadResourceBundle(this.resourceBundleBaseName, this.locale); } return loadedBundle; } protected void setParameterValues(Map parameterValues) throws JRException { parameterValues.put("REPORT_PARAMETERS_MAP", parameterValues); this.reportMaxCount = (Integer)parameterValues.get("REPORT_MAX_COUNT"); this.locale = (Locale)parameterValues.get("REPORT_LOCALE"); if (this.locale == null) { this.locale = Locale.getDefault(); parameterValues.put("REPORT_LOCALE", this.locale); } this.resourceBundle = (ResourceBundle)parameterValues.get("REPORT_RESOURCE_BUNDLE"); if (this.resourceBundle == null) { this.resourceBundle = loadResourceBundle(); if (this.resourceBundle != null) parameterValues.put("REPORT_RESOURCE_BUNDLE", this.resourceBundle); } this.timeZone = (TimeZone)parameterValues.get("REPORT_TIME_ZONE"); if (this.timeZone == null) { this.timeZone = TimeZone.getDefault(); parameterValues.put("REPORT_TIME_ZONE", this.timeZone); } this.scriptlet = (JRAbstractScriptlet)parameterValues.get("REPORT_SCRIPTLET"); if (this.scriptlet == null) { this.scriptlet = createScriptlet(); parameterValues.put("REPORT_SCRIPTLET", this.scriptlet); } this.scriptlet.setData(this.parametersMap, this.fieldsMap, this.variablesMap, this.groups); setFillParameterValues(parameterValues); } protected void initDatasource() throws JRException { this.queryExecuter = null; this.dataSource = (JRDataSource)getParameterValue("REPORT_DATA_SOURCE"); if (!this.useDatasourceParamValue && (this.useConnectionParamValue || this.dataSource == null)) { this.dataSource = createQueryDatasource(); setParameter("REPORT_DATA_SOURCE", this.dataSource); } JRSortField[] sortFields = getSortFields(); if (sortFields != null && sortFields.length > 0) { this.dataSource = (JRDataSource)new JRSortableDataSource(this.dataSource, (JRField[])this.fields, sortFields, this.locale); setParameter("REPORT_DATA_SOURCE", this.dataSource); } } private void setFillParameterValues(Map parameterValues) throws JRException { if (this.parameters != null && this.parameters.length > 0) for (int i = 0; i < this.parameters.length; i++) { Object value = null; if (parameterValues.containsKey(this.parameters[i].getName())) { value = parameterValues.get(this.parameters[i].getName()); } else if (!this.parameters[i].isSystemDefined()) { value = this.calculator.evaluate(this.parameters[i].getDefaultValueExpression(), (byte)3); if (value != null) parameterValues.put(this.parameters[i].getName(), value); } setParameter(this.parameters[i], value); } } private JRDataSource createQueryDatasource() throws JRException { if (this.query == null) return null; try { if (log.isDebugEnabled()) log.debug("Fill " + this.filler.fillerId + ": Creating " + this.query.getLanguage() + " query executer"); JRQueryExecuterFactory queryExecuterFactory = JRQueryExecuterUtils.getQueryExecuterFactory(this.query.getLanguage()); this.queryExecuter = queryExecuterFactory.createQueryExecuter(this.parent, this.parametersMap); this.filler.fillContext.setRunningQueryExecuter(this.queryExecuter); return this.queryExecuter.createDatasource(); } finally { this.filler.fillContext.clearRunningQueryExecuter(); } } protected void reset() { this.useDatasourceParamValue = false; this.useConnectionParamValue = false; } protected void setDatasourceParameterValue(Map parameterValues, JRDataSource ds) { this.useDatasourceParamValue = true; if (ds != null) parameterValues.put("REPORT_DATA_SOURCE", ds); } protected void setConnectionParameterValue(Map parameterValues, Connection conn) { this.useConnectionParamValue = true; if (conn != null) parameterValues.put("REPORT_CONNECTION", conn); } protected void closeDatasource() { if (this.queryExecuter != null) { if (log.isDebugEnabled()) log.debug("Fill " + this.filler.fillerId + ": closing query executer"); this.queryExecuter.close(); this.queryExecuter = null; } reset(); } protected void start() { this.reportCount = 0; } protected boolean next() throws JRException { boolean hasNext = false; if (this.dataSource != null) { boolean includeRow = true; JRExpression filterExpression = getFilterExpression(); do { hasNext = advanceDataSource(); if (!hasNext) continue; setOldValues(); this.calculator.estimateVariables(); if (filterExpression != null) { Boolean filterExprResult = (Boolean)this.calculator.evaluate(filterExpression, (byte)2); includeRow = (filterExprResult != null && filterExprResult.booleanValue()); } if (includeRow) continue; revertToOldValues(); } while (hasNext && !includeRow); if (hasNext) this.reportCount++; } return hasNext; } protected void setOldValues() throws JRException { if (this.fields != null && this.fields.length > 0) for (int i = 0; i < this.fields.length; i++) { JRFillField field = this.fields[i]; field.setPreviousOldValue(field.getOldValue()); field.setOldValue(field.getValue()); field.setValue(this.dataSource.getFieldValue(field)); } if (this.variables != null && this.variables.length > 0) for (int i = 0; i < this.variables.length; i++) { JRFillVariable variable = this.variables[i]; variable.setPreviousOldValue(variable.getOldValue()); variable.setOldValue(variable.getValue()); } } protected void revertToOldValues() { if (this.fields != null && this.fields.length > 0) for (int i = 0; i < this.fields.length; i++) { JRFillField field = this.fields[i]; field.setValue(field.getOldValue()); field.setOldValue(field.getPreviousOldValue()); } if (this.variables != null && this.variables.length > 0) for (int i = 0; i < this.variables.length; i++) { JRFillVariable variable = this.variables[i]; variable.setValue(variable.getOldValue()); variable.setOldValue(variable.getPreviousOldValue()); } } protected boolean advanceDataSource() throws JRException { boolean hasNext = ((this.reportMaxCount == null || this.reportMaxCount.intValue() > this.reportCount) && this.dataSource.next()); return hasNext; } protected void setParameter(String parameterName, Object value) throws JRException { JRFillParameter parameter = (JRFillParameter)this.parametersMap.get(parameterName); if (parameter != null) setParameter(parameter, value); } protected void setParameter(JRFillParameter parameter, Object value) throws JRException { if (value != null) { if (parameter.getValueClass().isInstance(value)) { parameter.setValue(value); } else { throw new JRException("Incompatible " + value.getClass().getName() + " value assigned to parameter " + parameter.getName() + " in the " + getName() + " dataset."); } } else { parameter.setValue(value); } } public Object getVariableValue(String variableName) { JRFillVariable var = (JRFillVariable)this.variablesMap.get(variableName); if (var == null) throw new JRRuntimeException("No such variable " + variableName); return var.getValue(); } public Object getParameterValue(String parameterName) { return getParameterValue(parameterName, false); } public Object getParameterValue(String parameterName, boolean ignoreMissing) { Object value; JRFillParameter param = (JRFillParameter)this.parametersMap.get(parameterName); if (param == null) { if (!ignoreMissing) throw new JRRuntimeException("No such parameter " + parameterName); value = null; } else { value = param.getValue(); } return value; } public Object getFieldValue(String fieldName) { JRFillField var = (JRFillField)this.fieldsMap.get(fieldName); if (var == null) throw new JRRuntimeException("No such field " + fieldName); return var.getValue(); } protected static class VariableCalculationReq { String variableName; byte calculation; VariableCalculationReq(String variableName, byte calculation) { this.variableName = variableName; this.calculation = calculation; } public boolean equals(Object o) { if (o == null || !(o instanceof VariableCalculationReq)) return false; VariableCalculationReq r = (VariableCalculationReq)o; return (this.variableName.equals(r.variableName) && this.calculation == r.calculation); } public int hashCode() { return 31 * this.calculation + this.variableName.hashCode(); } } protected void addVariableCalculationReq(String variableName, byte calculation) { if (this.variableCalculationReqs == null) this.variableCalculationReqs = new HashSet(); this.variableCalculationReqs.add(new VariableCalculationReq(variableName, calculation)); } protected void checkVariableCalculationReqs(JRFillObjectFactory factory) { if (this.variableCalculationReqs != null && !this.variableCalculationReqs.isEmpty()) { List variableList = new ArrayList(this.variables.length * 2); for (int i = 0; i < this.variables.length; i++) { JRFillVariable variable = this.variables[i]; checkVariableCalculationReq(variable, variableList, factory); } setVariables(variableList); } } private void checkVariableCalculationReq(JRFillVariable variable, List variableList, JRFillObjectFactory factory) { if (hasVariableCalculationReq(variable, (byte)3) || hasVariableCalculationReq(variable, (byte)7)) { if (variable.getHelperVariable((byte)0) == null) { JRVariable countVar = createHelperVariable(variable, "_COUNT", (byte)1); JRFillVariable fillCountVar = factory.getVariable(countVar); checkVariableCalculationReq(fillCountVar, variableList, factory); variable.setHelperVariable(fillCountVar, (byte)0); } if (variable.getHelperVariable((byte)1) == null) { JRVariable sumVar = createHelperVariable(variable, "_SUM", (byte)2); JRFillVariable fillSumVar = factory.getVariable(sumVar); checkVariableCalculationReq(fillSumVar, variableList, factory); variable.setHelperVariable(fillSumVar, (byte)1); } } if (hasVariableCalculationReq(variable, (byte)6)) if (variable.getHelperVariable((byte)2) == null) { JRVariable varianceVar = createHelperVariable(variable, "_VARIANCE", (byte)7); JRFillVariable fillVarianceVar = factory.getVariable(varianceVar); checkVariableCalculationReq(fillVarianceVar, variableList, factory); variable.setHelperVariable(fillVarianceVar, (byte)2); } if (hasVariableCalculationReq(variable, (byte)10)) if (variable.getHelperVariable((byte)0) == null) { JRVariable countVar = createDistinctCountHelperVariable(variable); JRFillVariable fillCountVar = factory.getVariable(countVar); checkVariableCalculationReq(fillCountVar, variableList, factory); variable.setHelperVariable(fillCountVar, (byte)0); } variableList.add(variable); } private boolean hasVariableCalculationReq(JRVariable var, byte calculation) { return this.variableCalculationReqs.contains(new VariableCalculationReq(var.getName(), calculation)); } public String getName() { return this.parent.getName(); } public String getScriptletClass() { return this.parent.getScriptletClass(); } public JRParameter[] getParameters() { return (JRParameter[])this.parameters; } public Map getParametersMap() { return this.parametersMap; } public JRQuery getQuery() { return this.query; } public JRField[] getFields() { return (JRField[])this.fields; } public JRSortField[] getSortFields() { return this.parent.getSortFields(); } public JRVariable[] getVariables() { return (JRVariable[])this.variables; } public JRGroup[] getGroups() { return (JRGroup[])this.groups; } public boolean isMainDataset() { return this.isMain; } public String getResourceBundle() { return this.parent.getResourceBundle(); } public byte getWhenResourceMissingType() { return this.whenResourceMissingType; } public void setWhenResourceMissingType(byte whenResourceMissingType) { this.whenResourceMissingType = whenResourceMissingType; } public boolean hasProperties() { return this.parent.hasProperties(); } public JRPropertiesMap getPropertiesMap() { return this.parent.getPropertiesMap(); } public JRPropertiesHolder getParentProperties() { return null; } public JRExpression getFilterExpression() { return this.parent.getFilterExpression(); } public Object clone() { return null; } }