=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java 2011-02-28 15:46:58 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java 2011-12-14 12:52:07 +0000 @@ -1,5 +1,11 @@ package org.hisp.dhis.common; +import org.codehaus.jackson.annotate.JsonProperty; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; import java.util.Arrays; import java.util.List; @@ -33,30 +39,32 @@ /** * @author Lars Helge Overland */ +@XmlRootElement( name = "header", namespace = Dxf2Namespace.NAMESPACE ) +@XmlAccessorType( value = XmlAccessType.NONE ) public class GridHeader { private static final List NUMERIC_TYPES = Arrays.asList( Float.class.getName(), Double.class.getName(), Long.class.getName(), Integer.class.getName() ); - + private String name; - + private String column; - + private String type; - + private boolean hidden; - + private boolean meta; - + public GridHeader() { } /** * Sets the column property to the name value. Sets the type property to String. - * - * @param name name + * + * @param name name * @param hidden hidden - * @param meta meta + * @param meta meta */ public GridHeader( String name, boolean hidden, boolean meta ) { @@ -68,11 +76,11 @@ } /** - * @param name name + * @param name name * @param column column - * @param type type + * @param type type * @param hidden hidden - * @param meta meta + * @param meta meta */ public GridHeader( String name, String column, String type, boolean hidden, boolean meta ) { @@ -83,11 +91,15 @@ this.meta = meta; } + @XmlElement + @JsonProperty public boolean isNumeric() { return type != null && NUMERIC_TYPES.contains( type ); } - + + @XmlElement + @JsonProperty public String getName() { return name; @@ -98,6 +110,8 @@ this.name = name; } + @XmlElement + @JsonProperty public String getColumn() { return column; @@ -108,6 +122,8 @@ this.column = column; } + @XmlElement + @JsonProperty public String getType() { return type; @@ -118,6 +134,8 @@ this.type = type; } + @XmlElement + @JsonProperty public boolean isHidden() { return hidden; @@ -128,6 +146,8 @@ this.hidden = hidden; } + @XmlElement + @JsonProperty public boolean isMeta() { return meta; @@ -151,19 +171,19 @@ { return true; } - + if ( object == null ) { return false; } - + if ( getClass() != object.getClass() ) { return false; } - + final GridHeader other = (GridHeader) object; - + return name.equals( other.name ); } } === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java 2011-12-14 12:52:07 +0000 @@ -0,0 +1,32 @@ +package org.hisp.dhis.common; + +import org.codehaus.jackson.annotate.JsonProperty; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +@XmlRootElement( name = "row", namespace = Dxf2Namespace.NAMESPACE ) +@XmlAccessorType( value = XmlAccessType.NONE ) +public class GridRow +{ + private List row = new ArrayList(); + + @XmlElement + @JsonProperty + public List getRow() + { + return row; + } + + public void setRow( List row ) + { + this.row = row; + } +} === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java 2011-12-14 12:52:07 +0000 @@ -0,0 +1,32 @@ +package org.hisp.dhis.common; + +import org.codehaus.jackson.annotate.JsonProperty; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +@XmlRootElement( name = "rows", namespace = Dxf2Namespace.NAMESPACE ) +@XmlAccessorType( value = XmlAccessType.NONE ) +public class GridRows +{ + private List rows = new ArrayList(); + + @XmlElement + @JsonProperty + public List getRows() + { + return rows; + } + + public void setRows( List rows ) + { + this.rows = rows; + } +} === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java 2011-12-14 12:52:07 +0000 @@ -0,0 +1,61 @@ +package org.hisp.dhis.common.adapter; + +/* + * Copyright (c) 2004-2011, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.common.GridRow; +import org.hisp.dhis.common.GridRows; + +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +public class GridRowsXmlAdapter extends XmlAdapter>> +{ + @Override + public List> unmarshal( GridRows rows ) throws Exception + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public GridRows marshal( List> rows ) throws Exception + { + GridRows gridRows = new GridRows(); + + for ( List row : rows ) + { + GridRow gridRow = new GridRow(); + gridRow.setRow( row ); + gridRows.getRows().add( gridRow ); + } + + return gridRows; + } +} === modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java' --- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java 2011-06-14 16:41:32 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java 2011-12-14 12:52:07 +0000 @@ -27,72 +27,73 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import static org.hisp.dhis.system.util.MathUtils.getRounded; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRField; - import org.apache.commons.math.stat.regression.SimpleRegression; +import org.codehaus.jackson.annotate.JsonProperty; +import org.hisp.dhis.common.Dxf2Namespace; import org.hisp.dhis.common.Grid; import org.hisp.dhis.common.GridHeader; +import org.hisp.dhis.common.adapter.GridRowsXmlAdapter; + +import javax.xml.bind.annotation.*; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import java.util.*; + +import static org.hisp.dhis.system.util.MathUtils.getRounded; /** * @author Lars Helge Overland * @version $Id$ */ +@XmlRootElement( name = "grid", namespace = Dxf2Namespace.NAMESPACE ) +@XmlAccessorType( value = XmlAccessType.NONE ) public class ListGrid implements Grid { private static final String REGRESSION_SUFFIX = "_regression"; - + /** * The title of the grid. */ private String title; - + /** * The subtitle of the grid. */ private String subtitle; - + /** * The name of a potential corresponding table. */ private String table; - + /** * A List which represents the column headers of the grid. */ private List headers; - + /** * A two dimensional List which simulates a grid where the first list * represents rows and the second represents columns. */ private List> grid; - + /** * Indicating the current row in the grid for writing data. */ private int currentRowWriteIndex = -1; - + /** * Indicating the current row in the grid for reading data. */ private int currentRowReadIndex = -1; - + /** * Represents a mapping between column names and the index of the column in the grid. */ private Map columnIndexMap = new HashMap(); - + /** * Default constructor. */ @@ -101,11 +102,13 @@ headers = new ArrayList(); grid = new ArrayList>(); } - + // --------------------------------------------------------------------- // Public methods // --------------------------------------------------------------------- + @XmlElement + @JsonProperty public String getTitle() { return title; @@ -114,10 +117,12 @@ public Grid setTitle( String title ) { this.title = title; - + return this; } + @XmlElement + @JsonProperty public String getSubtitle() { return subtitle; @@ -126,31 +131,36 @@ public Grid setSubtitle( String subtitle ) { this.subtitle = subtitle; - + return this; } - + + @XmlElement + @JsonProperty public String getTable() { return table; } - + public Grid setTable( String table ) { this.table = table; - + return this; } public Grid addHeader( GridHeader header ) { headers.add( header ); - + updateColumnIndexMap(); - + return this; } - + + @XmlElementWrapper( name = "headers" ) + @XmlElement( name = "header" ) + @JsonProperty( value = "headers" ) public List getHeaders() { return headers; @@ -159,7 +169,7 @@ public List getVisibleHeaders() { List tempHeaders = new ArrayList(); - + for ( GridHeader header : headers ) { if ( !header.isHidden() ) @@ -167,67 +177,74 @@ tempHeaders.add( header ); } } - + return tempHeaders; } - + + @XmlElement + @JsonProperty public int getHeight() - { - return ( grid != null && grid.size() > 0 ) ? grid.size() : 0; + { + return (grid != null && grid.size() > 0) ? grid.size() : 0; } - + + @XmlElement + @JsonProperty public int getWidth() { verifyGridState(); - - return ( grid != null && grid.size() > 0 ) ? grid.get( 0 ).size() : 0; + + return (grid != null && grid.size() > 0) ? grid.get( 0 ).size() : 0; } - + public int getVisibleWidth() { verifyGridState(); - - return ( grid != null && grid.size() > 0 ) ? getVisibleRows().get( 0 ).size() : 0; + + return (grid != null && grid.size() > 0) ? getVisibleRows().get( 0 ).size() : 0; } - + public Grid addRow() { grid.add( new ArrayList() ); - + currentRowWriteIndex++; - + return this; } - + public Grid addValue( Object value ) { grid.get( currentRowWriteIndex ).add( value ); - + return this; } - + public List getRow( int rowIndex ) { return grid.get( rowIndex ); } - + + @XmlElement + @XmlJavaTypeAdapter( GridRowsXmlAdapter.class ) + @JsonProperty public List> getRows() { return grid; } - + public List> getVisibleRows() { verifyGridState(); - + List> tempGrid = new ArrayList>(); - + if ( headers != null && headers.size() > 0 ) { for ( List row : grid ) { List tempRow = new ArrayList(); - + for ( int i = 0; i < row.size(); i++ ) { if ( !headers.get( i ).isHidden() ) @@ -235,102 +252,102 @@ tempRow.add( row.get( i ) ); } } - + tempGrid.add( tempRow ); } } - + return tempGrid; } - + public List getColumn( int columnIndex ) { List column = new ArrayList(); - + for ( List row : grid ) { column.add( row.get( columnIndex ) ); } - + return column; } - + public Object getValue( int rowIndex, int columnIndex ) { if ( grid.size() < rowIndex || grid.get( rowIndex ) == null || grid.get( rowIndex ).size() < columnIndex ) { throw new IllegalArgumentException( "Grid does not contain the requested row / column" ); } - + return grid.get( rowIndex ).get( columnIndex ); } - + public Grid addColumn( List columnValues ) { verifyGridState(); - + int rowIndex = 0; int columnIndex = 0; - + if ( grid.size() != columnValues.size() ) { throw new IllegalStateException( "Number of column values (" + columnValues.size() + ") is not equal to number of rows (" + grid.size() + ")" ); } - + for ( int i = 0; i < grid.size(); i++ ) { grid.get( rowIndex++ ).add( columnValues.get( columnIndex++ ) ); } - + return this; } - + public Grid removeColumn( int columnIndex ) { verifyGridState(); - + if ( headers.size() > 0 ) { headers.remove( columnIndex ); } - + for ( List row : grid ) { row.remove( columnIndex ); } - + updateColumnIndexMap(); - + return this; } - + public Grid removeColumn( GridHeader header ) { int index = headers.indexOf( header ); - + if ( index != -1 ) { removeColumn( index ); } - + return this; } - + public Grid limitGrid( int limit ) { if ( limit < 0 ) { throw new IllegalStateException( "Illegal limit: " + limit ); } - + if ( limit > 0 && limit <= getHeight() ) { grid = grid.subList( 0, limit ); } - + return this; } - + public Grid limitGrid( int startPos, int endPos ) { if ( startPos < 0 || endPos < startPos || endPos > getHeight() ) @@ -342,45 +359,45 @@ return this; } - + public Grid sortGrid( int columnIndex, int order ) { columnIndex = columnIndex - 1; - + if ( columnIndex < 0 || columnIndex >= getWidth() ) { throw new IllegalArgumentException( "Column index out of bounds: " + columnIndex ); } - + Collections.sort( grid, new GridRowComparator( columnIndex, order ) ); - + return this; } - + public Grid addRegressionColumn( int columnIndex, boolean addHeader ) { verifyGridState(); - + SimpleRegression regression = new SimpleRegression(); - + List column = getColumn( columnIndex ); - + int index = 0; - + for ( Object value : column ) { if ( Double.parseDouble( String.valueOf( value ) ) != 0.0 ) // 0 omitted from regression { - regression.addData( index++, Double.parseDouble( String.valueOf( value ) ) ); + regression.addData( index++, Double.parseDouble( String.valueOf( value ) ) ); } } - + List regressionColumn = new ArrayList(); - + for ( int i = 0; i < column.size(); i++ ) { final double predicted = regression.predict( i ); - + if ( !Double.isNaN( predicted ) ) // Enough values must exist for regression { regressionColumn.add( getRounded( predicted, 1 ) ); @@ -392,20 +409,20 @@ } addColumn( regressionColumn ); - + if ( addHeader && columnIndex < headers.size() ) { GridHeader header = headers.get( columnIndex ); - + if ( header != null ) { - GridHeader regressionHeader = new GridHeader( header.getName() + REGRESSION_SUFFIX, + GridHeader regressionHeader = new GridHeader( header.getName() + REGRESSION_SUFFIX, header.getColumn() + REGRESSION_SUFFIX, header.getType(), header.isHidden(), header.isMeta() ); - + addHeader( regressionHeader ); } - } - + } + return this; } @@ -417,20 +434,20 @@ throws JRException { boolean next = ++currentRowReadIndex < getHeight(); - + if ( !next ) { currentRowReadIndex = -1; // Reset and return false } - + return next; } - + public Object getFieldValue( JRField field ) throws JRException { Integer index = columnIndexMap.get( field.getName() ); - + return index != null ? getRow( currentRowReadIndex ).get( index ) : null; } @@ -444,19 +461,19 @@ */ private void verifyGridState() { - Integer rowLength = null; - + Integer rowLength = null; + for ( List row : grid ) { if ( rowLength != null && rowLength != row.size() ) { throw new IllegalStateException( "Grid rows do not have the same number of cells, previous: " + rowLength + ", this: " + row.size() ); } - + rowLength = row.size(); } } - + /** * Updates the mapping between header columns and grid indexes. This method * should be invoked whenever the columns are manipulated. @@ -464,13 +481,13 @@ private void updateColumnIndexMap() { columnIndexMap.clear(); - + for ( int i = 0; i < headers.size(); i++ ) { columnIndexMap.put( headers.get( i ).getColumn(), i ); } } - + // ------------------------------------------------------------------------- // toString // ------------------------------------------------------------------------- @@ -479,24 +496,24 @@ public String toString() { StringBuffer buffer = new StringBuffer( "[\n" ); - + if ( headers != null && headers.size() > 0 ) { List headerNames = new ArrayList(); - + for ( GridHeader header : headers ) { headerNames.add( header.getName() ); } - - buffer.append( headerNames ).append( "\n" ); + + buffer.append( headerNames ).append( "\n" ); } - + for ( List row : grid ) { buffer.append( row ).append( "\n" ); } - + return buffer.append( "]" ).toString(); } @@ -515,29 +532,29 @@ this.columnIndex = columnIndex; this.order = order; } - + @Override - @SuppressWarnings("unchecked") + @SuppressWarnings( "unchecked" ) public int compare( List list1, List list2 ) { if ( order == 0 ) { return 0; } - - if ( list1 == null || list1.get( columnIndex ) == null || !( list1.get( columnIndex ) instanceof Comparable ) ) + + if ( list1 == null || list1.get( columnIndex ) == null || !(list1.get( columnIndex ) instanceof Comparable) ) { return 1; // Null comes last } - - if ( list2 == null || list2.get( columnIndex ) == null || !( list2.get( columnIndex ) instanceof Comparable ) ) + + if ( list2 == null || list2.get( columnIndex ) == null || !(list2.get( columnIndex ) instanceof Comparable) ) { return -1; // Null comes last } - + final Comparable value1 = (Comparable) list1.get( columnIndex ); final Comparable value2 = (Comparable) list2.get( columnIndex ); - + return order > 0 ? value2.compareTo( value1 ) : value1.compareTo( value2 ); } } === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java 2011-12-14 11:54:43 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java 2011-12-14 12:52:07 +0000 @@ -121,6 +121,33 @@ return "reportTable"; } + @RequestMapping( value = "/{uid}/data", method = RequestMethod.GET ) + public String getReportTableDATA( @PathVariable( "uid" ) String uid, Model model, + @RequestParam( value = "organisationUnit", required = false ) String organisationUnitUid, + @RequestParam( value = "period", required = false ) String period, + HttpServletResponse response ) throws I18nManagerException, IOException + { + if ( organisationUnitUid == null && period == null ) + { + response.setStatus( HttpServletResponse.SC_BAD_REQUEST ); + response.setContentType( "text/plain" ); + + PrintWriter writer = new PrintWriter( response.getOutputStream() ); + writer.println( "GRID needs either organisationUnit or period parameter." ); + writer.flush(); + + return "grid"; + } + + Date date = period != null ? DateUtils.getMediumDate( period ) : new Date(); + + Grid grid = reportTableService.getReportTableGrid( uid, i18nManager.getI18nFormat(), date, organisationUnitUid ); + + model.addAttribute( "model", grid ); + + return "grid"; + } + @RequestMapping( value = "/{uid}/data.pdf", method = RequestMethod.GET ) public void getReportTablePDF( @PathVariable( "uid" ) String uid, @RequestParam( value = "organisationUnit", required = false ) String organisationUnitUid,