Changeset 550 for trunk


Ignore:
Timestamp:
May 28, 2010, 1:29:19 AM (14 years ago)
Author:
gav
Message:

Improvements to stockTakeByLocation report, includes heap memory protection improvements.
Tested against MySQL with 767 InventoryLocations, 3770 InventoryItems and 270MiB of images in database.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/services/InventoryReportService.groovy

    r547 r550  
    1313    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
    1414
     15    // Protect java heap memory.
     16    // Most likely want to set paramsMax and inClauseMax to the same values.
    1517    def paramsMax = 250
     18
     19    // At least with Oracle and MSSQL db limits are 1000 (in list) and 2000 (nodes) respectively.
     20    // But 255 has also been mentioned on the internet as a possible limit for some databases.
     21    def inClauseMax = 250
    1622
    1723    /**
     
    5258        def result = [:]
    5359
     60        result.inventoryItemList = []
     61        result.inventoryItemCount = 0
     62        result.locationCount = 0
     63        result.errorMessage = null
    5464        result.summaryOfCalculationMethod = 'This report should be used in conjunction with the `Stock Take (Overview)` Report.'
    5565
    56         // Sanitise the locations string and convert to a list.
     66        def fail = { Map m ->
     67            result.error = [ code: m.code, args: m.args ]
     68            result.errorMessage = g.message(result.error)
     69            result.locations = ''
     70            return result
     71        }
     72
     73        def paginateParams = [:]
     74        paginateParams.max = Math.min(params?.max?.toInteger() ?: paramsMax, paramsMax)
     75
     76        def namedParams = [:]
     77        namedParams.locationList = []
     78
     79        // Sanitise the user supplied locations string and convert to a list.
    5780        result.locations = params.locationString.trim()
    5881        if(result.locations.startsWith('e.g:'))
     
    6184        result.locations = result.locations.collect {it.trim()}
    6285
    63         def paginateParams = [:]
    64         paginateParams.max = Math.min(params?.max?.toInteger() ?: paramsMax, paramsMax)
    65 
    66         def namedParams = [:]
    67         namedParams.locationList = [null] // null protects against HQL unexpected end of subtree exception with an empty list.
    68 
    69         // Fill namedParams.locationList
    70         result.locations.each() {
    71             InventoryLocation.findAllByNameIlike(it).each() {
    72                 namedParams.locationList << it
     86        // Fill namedParams.locationList.
     87        result.locations.each() { location ->
     88            if(namedParams.locationList.size() < paramsMax) {
     89                // paramsMax+1 to ensure the too many locations check bellow is triggered.
     90                namedParams.locationList += InventoryLocation.findAllByNameIlike(location, [max: paramsMax+1])
    7391            }
     92            namedParams.locationList.unique()
    7493        }
    7594
    76         // Return the actual locations as a string.
    77         if(namedParams.locationList.size() > 1)
    78             result.locations = namedParams.locationList[1..-1].toString()[1..-2]
     95        // Return the actual locations as a string, along with a count.
     96        result.locationCount = namedParams.locationList.size()
     97        if(result.locationCount > 0) {
     98            result.locations = namedParams.locationList.toString()[1..-2]
     99        }
    79100        else
    80101            result.locations = g.message(code: 'default.none.text')
     102
     103        // Exit if empty location list.
     104        // Protects against HQL unexpected end of subtree exception with an empty list.
     105        if(namedParams.locationList.isEmpty())
     106            return fail(code:'report.error.no.locations.found')
     107
     108        // Exit if IN clause list too big.
     109        if(namedParams.locationList.size() > inClauseMax)
     110            return fail(code:'report.error.too.many.locations', args: [inClauseMax])
    81111
    82112        // Inventory List.
     
    91121
    92122        // Exit if too many results.
    93         result.countWarning = null
    94         if(result.inventoryItemCount > paramsMax) {
    95             result.countWarning = g.message(code: 'report.too.many.results.warning',
    96                                                                     args: [paramsMax],
    97                                                                     default: "Warning over ${paramsMax} results, please run report again!")
    98             result.inventoryItemList = []
    99             return result
    100         }
     123        if(result.inventoryItemCount > paramsMax)
     124            return fail(code:'report.error.too.many.results', args: [paramsMax])
    101125
    102126        result.inventoryListQuery = "select distinct inventoryItem " + result.inventoryListQuery
     
    107131        namedParams.inventoryList = inventoryList
    108132
    109         // Note: HQL docs advise not using fetch aliases in where clause (or any other clause).
     133        // Exit if empty inventory list.
     134        // Protects against HQL unexpected end of subtree exception with an empty list.
     135        if(namedParams.inventoryList.isEmpty())
     136            return fail(code:'report.error.no.inventory.items.found')
     137
     138        // Exit if inventory list too big.
     139        if(namedParams.inventoryList.size() > inClauseMax)
     140            return fail(code:'report.error.too.many.inventory.items', args: [inClauseMax])
     141
     142        // Note: HQL docs advise 'not using fetch aliases in where clause (or any other clause)'.
    110143        // Access is via the parent object, however that does not work for the order by clause in this case.
    111144        result.query = "from InventoryItem as inventoryItem \
     
    119152                                        order by inventoryStore.name, inventoryLocation.name"
    120153
    121         result.query = "select inventoryItem " + result.query
     154        result.query = "select  distinct inventoryItem " + result.query
    122155        result.inventoryItemList = InventoryItem.executeQuery(result.query, namedParams, paginateParams)
    123156
  • trunk/web-app/reports/stockTakeByLocation.jrxml

    r547 r550  
    55        <property name="ireport.zoom" value="1.0"/>
    66        <property name="ireport.x" value="0"/>
    7         <property name="ireport.y" value="0"/>
     7        <property name="ireport.y" value="144"/>
     8        <import value="java.util.*"/>
    89        <import value="net.sf.jasperreports.engine.*"/>
    9         <import value="java.util.*"/>
    1010        <import value="net.sf.jasperreports.engine.data.*"/>
    1111        <style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
     
    7373        <parameter name="currentUser" class="java.lang.String"/>
    7474        <parameter name="logoUrl" class="java.lang.String"/>
    75         <parameter name="startDateString" class="java.lang.String"/>
    76         <parameter name="endDateString" class="java.lang.String"/>
    77         <parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
    78                 <defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
    79         </parameter>
     75        <parameter name="locationString" class="java.lang.String"/>
    8076        <queryString language="SQL">
    8177                <![CDATA[]]>
     
    8581        <field name="inventoryItemCount" class="java.lang.Integer"/>
    8682        <field name="locations" class="java.lang.String"/>
    87         <field name="countWarning" class="java.lang.String"/>
     83        <field name="errorMessage" class="java.lang.String"/>
     84        <field name="locationCount" class="java.lang.Integer"/>
    8885        <background>
    8986                <band splitType="Stretch"/>
     
    105102                                <reportElement x="0" y="75" width="340" height="17"/>
    106103                                <textElement textAlignment="Center" verticalAlignment="Middle" markup="none"/>
    107                                 <textFieldExpression class="java.lang.String"><![CDATA["Inventory Items: "+$F{inventoryItemCount}+", Locations: "+$F{locations}+"."]]></textFieldExpression>
     104                                <textFieldExpression class="java.lang.String"><![CDATA["Total - Items: "+$F{inventoryItemCount}+", Locations: "+$F{locationCount}]]></textFieldExpression>
    108105                        </textField>
    109106                        <textField>
    110107                                <reportElement mode="Opaque" x="400" y="4" width="382" height="46" isPrintWhenDetailOverflows="true" forecolor="#FF0000" backcolor="#FFCCCC">
    111                                         <printWhenExpression><![CDATA[$F{countWarning} != null ? true:false]]></printWhenExpression>
     108                                        <printWhenExpression><![CDATA[$F{errorMessage} != null ? true:false]]></printWhenExpression>
    112109                                </reportElement>
    113110                                <textElement textAlignment="Center" verticalAlignment="Middle">
    114111                                        <font size="12" isBold="true"/>
    115112                                </textElement>
    116                                 <textFieldExpression class="java.lang.String"><![CDATA[$F{countWarning}]]></textFieldExpression>
     113                                <textFieldExpression class="java.lang.String"><![CDATA[$F{errorMessage}]]></textFieldExpression>
    117114                        </textField>
    118115                </band>
     
    132129                                                <jr:groupHeader groupName="group1">
    133130                                                        <jr:cell height="20" rowSpan="1">
    134                                                                 <textField>
    135                                                                         <reportElement x="0" y="0" width="127" height="20"/>
     131                                                                <textField isStretchWithOverflow="true">
     132                                                                        <reportElement x="0" y="0" width="117" height="20"/>
    136133                                                                        <textElement verticalAlignment="Middle">
    137134                                                                                <font size="12" isBold="true"/>
     
    141138                                                        </jr:cell>
    142139                                                </jr:groupHeader>
    143                                                 <jr:columnHeader style="table_CH" height="20" rowSpan="1"/>
    144                                                 <jr:detailCell style="table_TD" height="51" rowSpan="1">
    145                                                         <image>
    146                                                                 <reportElement x="39" y="0" width="88" height="51"/>
     140                                                <jr:columnHeader style="table_CH" height="20" rowSpan="1">
     141                                                        <textField isStretchWithOverflow="true">
     142                                                                <reportElement x="0" y="0" width="117" height="20"/>
     143                                                                <textElement verticalAlignment="Middle">
     144                                                                        <font isBold="true"/>
     145                                                                </textElement>
     146                                                                <textFieldExpression class="java.lang.String"><![CDATA[$F{inventoryLocation}.name]]></textFieldExpression>
     147                                                        </textField>
     148                                                </jr:columnHeader>
     149                                                <jr:detailCell style="table_TD" height="51" rowSpan="1">
     150                                                        <image hAlign="Center" vAlign="Middle">
     151                                                                <reportElement x="29" y="0" width="88" height="51"/>
    147152                                                                <imageExpression class="java.awt.Image"><![CDATA[net.sf.jasperreports.engine.util.JRImageLoader.loadImage($F{picture}.images.first().data)]]></imageExpression>
    148153                                                        </image>
     
    151156                                        <jr:column width="237">
    152157                                                <jr:columnHeader style="table_CH" height="20" rowSpan="1">
    153                                                         <textField>
     158                                                        <textField isStretchWithOverflow="true">
    154159                                                                <reportElement x="0" y="0" width="237" height="20"/>
    155160                                                                <textElement verticalAlignment="Middle">
     
    174179                                        <jr:column width="104">
    175180                                                <jr:columnHeader style="table_CH" height="20" rowSpan="1">
    176                                                         <textField>
     181                                                        <textField isStretchWithOverflow="true">
    177182                                                                <reportElement x="0" y="0" width="104" height="20"/>
    178183                                                                <textElement textAlignment="Center" verticalAlignment="Middle">
     
    196201                                        <jr:column width="90">
    197202                                                <jr:columnHeader style="table_CH" height="20" rowSpan="1">
    198                                                         <textField>
     203                                                        <textField isStretchWithOverflow="true">
    199204                                                                <reportElement x="0" y="0" width="90" height="20"/>
    200205                                                                <textElement textAlignment="Center" verticalAlignment="Middle">
     
    206211                                                <jr:detailCell style="table_TD" height="51" rowSpan="1">
    207212                                                        <rectangle>
    208                                                                 <reportElement x="5" y="8" width="80" height="35"/>
     213                                                                <reportElement x="5" y="11" width="80" height="30"/>
    209214                                                        </rectangle>
    210215                                                </jr:detailCell>
     
    232237                                        <jr:column width="139">
    233238                                                <jr:columnHeader style="table_CH" height="20" rowSpan="1">
    234                                                         <textField>
     239                                                        <textField isStretchWithOverflow="true">
    235240                                                                <reportElement x="0" y="0" width="139" height="20"/>
    236241                                                                <textElement verticalAlignment="Middle">
     
    326331                                <textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
    327332                        </textField>
    328                         <textField>
    329                                 <reportElement x="0" y="60" width="782" height="309"/>
     333                        <textField isStretchWithOverflow="true">
     334                                <reportElement x="0" y="60" width="782" height="18"/>
    330335                                <textElement/>
    331336                                <textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
     337                        </textField>
     338                        <textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
     339                                <reportElement x="0" y="125" width="782" height="17"/>
     340                                <textElement verticalAlignment="Middle" markup="none"/>
     341                                <textFieldExpression class="java.lang.String"><![CDATA["Locations found: "]]></textFieldExpression>
     342                        </textField>
     343                        <textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
     344                                <reportElement x="14" y="143" width="768" height="17"/>
     345                                <textElement verticalAlignment="Middle" markup="none"/>
     346                                <textFieldExpression class="java.lang.String"><![CDATA[$F{locations}+"."]]></textFieldExpression>
     347                        </textField>
     348                        <textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
     349                                <reportElement x="14" y="101" width="768" height="17"/>
     350                                <textElement verticalAlignment="Middle" markup="none"/>
     351                                <textFieldExpression class="java.lang.String"><![CDATA[$P{locationString}]]></textFieldExpression>
     352                        </textField>
     353                        <textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
     354                                <reportElement x="0" y="84" width="782" height="17"/>
     355                                <textElement verticalAlignment="Middle" markup="none"/>
     356                                <textFieldExpression class="java.lang.String"><![CDATA["Locations requested ('e.g:' is ignored and '%' is a wild card): "]]></textFieldExpression>
    332357                        </textField>
    333358                </band>
Note: See TracChangeset for help on using the changeset viewer.