← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 10794: Chart, added persisted list of DataElementOperands. Added support for data element operands as a ...

 

------------------------------------------------------------
revno: 10794
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2013-05-10 14:07:51 +0200
message:
  Chart, added persisted list of DataElementOperands. Added support for data element operands as a data dimension for chart.
added:
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementOperandServiceTest.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/chart/Chart.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalObject.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperandService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementOperandService.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ChartController.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/chart/Chart.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/chart/Chart.java	2013-05-09 20:31:34 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/chart/Chart.java	2013-05-10 12:07:51 +0000
@@ -28,6 +28,7 @@
  */
 
 import static org.hisp.dhis.common.DimensionalObject.DATAELEMENT_DIM_ID;
+import static org.hisp.dhis.common.DimensionalObject.DATAELEMENT_OPERAND_ID;
 import static org.hisp.dhis.common.DimensionalObject.DATASET_DIM_ID;
 import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID;
 import static org.hisp.dhis.common.DimensionalObject.INDICATOR_DIM_ID;
@@ -57,6 +58,7 @@
 import org.hisp.dhis.common.view.ExportView;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementGroup;
+import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.i18n.I18nFormat;
 import org.hisp.dhis.indicator.Indicator;
@@ -137,6 +139,9 @@
     private List<DataElement> dataElements = new ArrayList<DataElement>();
 
     @Scanned
+    private List<DataElementOperand> dataElementOperands = new ArrayList<DataElementOperand>();
+    
+    @Scanned
     private List<DataSet> dataSets = new ArrayList<DataSet>();
 
     @Scanned
@@ -249,11 +254,16 @@
                 objects.add( new BaseDimensionalObject( DATAELEMENT_DIM_ID, dataElements ) );
             }
             
+            if ( !dataElementOperands.isEmpty() )
+            {
+                objects.add( new BaseDimensionalObject( DATAELEMENT_OPERAND_ID, dataElementOperands ) );
+            }
+            
             if ( !dataSets.isEmpty() )
             {
                 objects.add( new BaseDimensionalObject( DATASET_DIM_ID, dataSets ) );
             }
-        }        
+        }
         else if ( PERIOD_DIM_ID.equals( dimension ) && ( !periods.isEmpty() || hasRelativePeriods() ) )
         {
             List<IdentifiableObject> periodList = new ArrayList<IdentifiableObject>( periods );
@@ -701,6 +711,21 @@
     @JsonProperty
     @JsonSerialize( contentAs = BaseNameableObject.class )
     @JsonView( {DetailedView.class, ExportView.class} )
+    @JacksonXmlElementWrapper( localName = "dataElementOperands", namespace = DxfNamespaces.DXF_2_0)
+    @JacksonXmlProperty( localName = "dataElementOperand", namespace = DxfNamespaces.DXF_2_0)
+    public List<DataElementOperand> getDataElementOperands()
+    {
+        return dataElementOperands;
+    }
+
+    public void setDataElementOperands( List<DataElementOperand> dataElementOperands )
+    {
+        this.dataElementOperands = dataElementOperands;
+    }
+
+    @JsonProperty
+    @JsonSerialize( contentAs = BaseNameableObject.class )
+    @JsonView( {DetailedView.class, ExportView.class} )
     @JacksonXmlElementWrapper( localName = "dataSets", namespace = DxfNamespaces.DXF_2_0)
     @JacksonXmlProperty( localName = "dataSet", namespace = DxfNamespaces.DXF_2_0)
     public List<DataSet> getDataSets()

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalObject.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalObject.java	2013-05-10 08:28:01 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/DimensionalObject.java	2013-05-10 12:07:51 +0000
@@ -39,7 +39,7 @@
     final String INDICATOR_DIM_ID = "in";
     final String DATAELEMENT_DIM_ID = "de";
     final String DATASET_DIM_ID = "ds";
-    final String DATAELEMENT_OPERAND_ID = "do";
+    final String DATAELEMENT_OPERAND_ID = "dc";
     final String CATEGORYOPTIONCOMBO_DIM_ID = "co";
     final String PERIOD_DIM_ID = "pe";
     final String ORGUNIT_DIM_ID = "ou";

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java	2013-04-19 09:20:59 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java	2013-05-10 12:07:51 +0000
@@ -27,39 +27,38 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonView;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
 
 import org.apache.commons.lang.StringUtils;
 import org.hisp.dhis.common.BaseIdentifiableObject;
 import org.hisp.dhis.common.DxfNamespaces;
+import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.common.view.DetailedView;
 import org.hisp.dhis.common.view.ExportView;
 import org.hisp.dhis.expression.ExpressionService;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonView;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 
 /**
  * This object can act both as a hydrated persisted object and as a wrapper
  * object (but not both at the same time).
+ * 
+ * This object implements IdentifiableObject but does not have any UID. Instead
+ * the UID is generated based on the data element and category option combo which
+ * this object is based on.
  *
  * @author Abyot Asalefew
  */
 @JacksonXmlRootElement( localName = "dataElementOperand", namespace = DxfNamespaces.DXF_2_0)
 public class DataElementOperand
-    implements Serializable, Comparable<DataElementOperand>
+    extends BaseIdentifiableObject
 {
-    /**
-     * Determines if a de-serialized file is compatible with this class.
-     */
-    private static final long serialVersionUID = 2490172100580528479L;
-
     public static final String SEPARATOR = ".";
     public static final String NAME_TOTAL = "(Total)";
 
@@ -74,8 +73,6 @@
     // Persisted properties
     // -------------------------------------------------------------------------
 
-    private int id;
-
     private DataElement dataElement;
 
     private DataElementCategoryOptionCombo categoryOptionCombo;
@@ -150,6 +147,24 @@
     // Logic
     // -------------------------------------------------------------------------
 
+    @Override
+    public String getUid()
+    {
+        String uid = null;
+        
+        if ( dataElement != null )
+        {
+            uid = dataElement.getUid();
+        }
+        
+        if ( categoryOptionCombo != null )
+        {
+            uid += SEPARATOR + categoryOptionCombo.getUid();
+        }
+        
+        return uid;
+    }
+    
     /**
      * Tests whether the operand has any aggregation levels.
      */
@@ -211,7 +226,7 @@
      * @return the id.
      */
     @Deprecated
-    public String getPersistedId()
+    public String getPersistedId() //TODO remove
     {
         return dataElement.getId() + SEPARATOR + categoryOptionCombo.getId();
     }
@@ -353,16 +368,6 @@
     // Getters & setters
     // -------------------------------------------------------------------------
 
-    public int getId()
-    {
-        return id;
-    }
-
-    public void setId( int id )
-    {
-        this.id = id;
-    }
-
     @JsonProperty
     @JsonSerialize( as = BaseIdentifiableObject.class )
     @JsonView( {DetailedView.class, ExportView.class} )
@@ -597,8 +602,11 @@
         return true;
     }
 
-    public int compareTo( DataElementOperand other )
+    @Override
+    public int compareTo( IdentifiableObject object )
     {
+        DataElementOperand other = (DataElementOperand) object;
+        
         if ( this.dataElementId.compareTo( other.dataElementId ) != 0 )
         {
             return this.dataElementId.compareTo( other.dataElementId );

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperandService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperandService.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperandService.java	2013-05-10 12:07:51 +0000
@@ -28,6 +28,7 @@
  */
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * @author Abyot Asalefew
@@ -42,6 +43,10 @@
     void deleteDataElementOperand( DataElementOperand dataElementOperand );
 
     DataElementOperand getDataElementOperand( int id );
+    
+    DataElementOperand getDataElementOperandByUid( String uid );
+    
+    List<DataElementOperand> getDataElementOperandsByUid( Collection<String> uids );
 
     DataElementOperand getDataElementOperand( DataElementOperand dataElementOperand );
 
@@ -50,5 +55,4 @@
     Collection<DataElementOperand> getDataElementOperandByDataElements( Collection<DataElement> dataElements );
 
     Collection<DataElementOperand> getDataElementOperandByOptionCombos( Collection<DataElementCategoryOptionCombo> optionCombos );
-
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2013-01-15 11:43:12 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java	2013-05-10 12:07:51 +0000
@@ -67,10 +67,12 @@
     final String SPACE = " ";
 
     final String OPERAND_EXPRESSION = "#\\{(\\w+)\\.?(\\w*)\\}";
+    final String OPERAND_UID_EXPRESSION = "(\\w+)\\.?(\\w*)";
     final String CONSTANT_EXPRESSION = "C\\{(\\w+)\\}";
     final String DAYS_EXPRESSION = "\\[days\\]";
 
     final Pattern OPERAND_PATTERN = Pattern.compile( OPERAND_EXPRESSION );
+    final Pattern OPERAND_UID_PATTERN = Pattern.compile( OPERAND_UID_EXPRESSION );
     final Pattern CONSTANT_PATTERN = Pattern.compile( CONSTANT_EXPRESSION );
     final Pattern DAYS_PATTERN = Pattern.compile( DAYS_EXPRESSION );
 

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java	2013-04-26 07:12:45 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/ExchangeClasses.java	2013-05-10 12:07:51 +0000
@@ -40,6 +40,7 @@
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementGroup;
 import org.hisp.dhis.dataelement.DataElementGroupSet;
+import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.Section;
 import org.hisp.dhis.document.Document;
@@ -117,6 +118,8 @@
         allExportClasses.put( DataElement.class, "dataElements" );
         allExportClasses.put( DataElementGroup.class, "dataElementGroups" );
         allExportClasses.put( DataElementGroupSet.class, "dataElementGroupSets" );
+        
+        allExportClasses.put( DataElementOperand.class, "dataElementOperands" );
 
         allExportClasses.put( IndicatorType.class, "indicatorTypes" );
         allExportClasses.put( Indicator.class, "indicators" );
@@ -165,6 +168,10 @@
         exportClasses.remove( ProgramStage.class );
         importClasses.remove( Program.class );
         importClasses.remove( ProgramStage.class );
+        
+        // special class which is created on demand in association with other objects
+        exportClasses.remove( DataElementOperand.class );
+        importClasses.remove( DataElementOperand.class );
     }
 
     public static Map<Class<? extends IdentifiableObject>, String> getAllExportMap()

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementOperandService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementOperandService.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementOperandService.java	2013-05-10 12:07:51 +0000
@@ -29,13 +29,16 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
 
 import org.hisp.dhis.common.GenericStore;
+import org.hisp.dhis.expression.ExpressionService;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 
 /**
  * @author Abyot Asalefew
- * @version $Id$
  */
 @Transactional
 public class DefaultDataElementOperandService
@@ -51,6 +54,20 @@
     {
         this.dataElementOperandStore = dataElementOperandStore;
     }
+    
+    private DataElementService dataElementService;
+
+    public void setDataElementService( DataElementService dataElementService )
+    {
+        this.dataElementService = dataElementService;
+    }
+
+    private DataElementCategoryService categoryService;
+
+    public void setCategoryService( DataElementCategoryService categoryService )
+    {
+        this.categoryService = categoryService;
+    }
 
     // -------------------------------------------------------------------------
     // Operand
@@ -70,7 +87,50 @@
     {
         return dataElementOperandStore.get( id );
     }
+    
+    public DataElementOperand getDataElementOperandByUid( String uid )
+    {
+        if ( StringUtils.isEmpty( uid ) )
+        {
+            return null;
+        }
+        
+        Matcher matcher = ExpressionService.OPERAND_UID_PATTERN.matcher( uid );
+        
+        matcher.find();
+        
+        String deUid = matcher.group( 1 );
+        String cocUid = matcher.group( 2 );
+                
+        DataElement dataElement = dataElementService.getDataElement( deUid );
+        
+        if ( dataElement == null )
+        {
+            return null;
+        }
+        
+        DataElementCategoryOptionCombo categoryOptionCombo = null;
+        
+        if ( cocUid != null )
+        {
+            categoryOptionCombo = categoryService.getDataElementCategoryOptionCombo( cocUid );
+        }
+        
+        return new DataElementOperand( dataElement, categoryOptionCombo );
+    }
 
+    public List<DataElementOperand> getDataElementOperandsByUid( Collection<String> uids )
+    {
+        List<DataElementOperand> list = new ArrayList<DataElementOperand>();
+        
+        for ( String uid : uids )
+        {
+            list.add( getDataElementOperandByUid( uid ) );
+        }
+        
+        return list;
+    }
+    
     public DataElementOperand getDataElementOperand( DataElementOperand dataElementOperand )
     {
         for ( DataElementOperand operand : getAllDataElementOperands() )

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2013-04-29 08:41:55 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2013-05-10 12:07:51 +0000
@@ -336,6 +336,8 @@
 
   <bean id="org.hisp.dhis.dataelement.DataElementOperandService" class="org.hisp.dhis.dataelement.DefaultDataElementOperandService">
     <property name="dataElementOperandStore" ref="org.hisp.dhis.dataelement.DataElementOperandStore" />
+    <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
+    <property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
   </bean>
 
   <bean id="org.hisp.dhis.datavalue.DataValueService" class="org.hisp.dhis.datavalue.DefaultDataValueService">

=== added file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementOperandServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementOperandServiceTest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementOperandServiceTest.java	2013-05-10 12:07:51 +0000
@@ -0,0 +1,133 @@
+package org.hisp.dhis.dataelement;
+
+/*
+ * Copyright (c) 2004-2012, 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.DhisSpringTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class DataElementOperandServiceTest
+    extends DhisSpringTest
+{
+    @Autowired
+    private DataElementOperandService operandService;
+    
+    @Autowired
+    private DataElementService dataElementService;
+    
+    @Autowired
+    private DataElementCategoryService categoryService;
+    
+    private DataElement deA;
+    private DataElement deB;
+    private DataElement deC;
+    
+    private DataElementCategoryOptionCombo coc;
+    
+    @Override
+    public void setUpTest()
+    {
+        deA = createDataElement( 'A' );
+        deB = createDataElement( 'B' );
+        deC = createDataElement( 'C' );
+        
+        dataElementService.addDataElement( deA );
+        dataElementService.addDataElement( deB );
+        dataElementService.addDataElement( deC );
+        
+        coc = categoryService.getDefaultDataElementCategoryOptionCombo();
+    }
+    
+    @Test
+    public void testAddGet()
+    {
+        DataElementOperand opA = new DataElementOperand( deA, coc );
+        DataElementOperand opB = new DataElementOperand( deB, coc );
+        DataElementOperand opC = new DataElementOperand( deC, coc );
+        
+        int idA = operandService.addDataElementOperand( opA );
+        int idB = operandService.addDataElementOperand( opB );
+        int idC = operandService.addDataElementOperand( opC );
+        
+        assertEquals( opA, operandService.getDataElementOperand( idA ) );
+        assertEquals( opB, operandService.getDataElementOperand( idB ) );
+        assertEquals( opC, operandService.getDataElementOperand( idC ) );
+    }
+
+    @Test
+    public void testDelete()
+    {
+        DataElementOperand opA = new DataElementOperand( deA, coc );
+        DataElementOperand opB = new DataElementOperand( deB, coc );
+        DataElementOperand opC = new DataElementOperand( deC, coc );
+        
+        int idA = operandService.addDataElementOperand( opA );
+        int idB = operandService.addDataElementOperand( opB );
+        int idC = operandService.addDataElementOperand( opC );
+        
+        assertNotNull( operandService.getDataElementOperand( idA ) );
+        assertNotNull( operandService.getDataElementOperand( idB ) );
+        assertNotNull( operandService.getDataElementOperand( idC ) );
+        
+        operandService.deleteDataElementOperand( opA );
+        operandService.deleteDataElementOperand( opB );
+
+        assertNull( operandService.getDataElementOperand( idA ) );
+        assertNull( operandService.getDataElementOperand( idB ) );
+        assertNotNull( operandService.getDataElementOperand( idC ) );
+
+        operandService.deleteDataElementOperand( opC );
+        
+        assertNull( operandService.getDataElementOperand( idA ) );
+        assertNull( operandService.getDataElementOperand( idB ) );
+        assertNull( operandService.getDataElementOperand( idC ) );
+    }
+    
+    public void testGetByUid()
+    {
+        DataElementOperand opA = new DataElementOperand( deA, coc );
+        DataElementOperand opB = new DataElementOperand( deB, coc );
+        
+        operandService.addDataElementOperand( opA );
+        operandService.addDataElementOperand( opB );
+        
+        String uidA = deA.getUid() + DataElementOperand.SEPARATOR + coc.getUid();
+        String uidB = deB.getUid() + DataElementOperand.SEPARATOR + coc.getUid();
+        
+        assertEquals( opA, operandService.getDataElementOperandByUid( uidA ) );
+        assertEquals( opB, operandService.getDataElementOperandByUid( uidB ) );
+        
+        assertNull( operandService.getDataElementOperandByUid( null ) );
+        assertNull( operandService.getDataElementOperandByUid( "SomeFunnyUid" ) );
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java	2012-11-20 17:04:08 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementServiceTest.java	2013-05-10 12:07:51 +0000
@@ -27,7 +27,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -42,7 +41,6 @@
 
 /**
  * @author Kristian Nordal
- * @version $Id: DataElementServiceTest.java 5742 2008-09-26 11:37:35Z larshelg $
  */
 public class DataElementServiceTest
     extends DhisSpringTest

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml	2013-05-09 20:31:34 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/chart/hibernate/Chart.hbm.xml	2013-05-10 12:07:51 +0000
@@ -71,6 +71,14 @@
         foreign-key="fk_chart_dataelements_dataelementid" />
     </list>
 
+    <list name="dataElementOperands" table="chart_dataelementoperands" cascade="all-delete-orphan">
+      <cache usage="read-write" />
+      <key column="chartid" foreign-key="fk_chart_dataelementoperandid_chartid" />
+      <list-index column="sort_order" base="0" />
+      <many-to-many column="dataelementoperandid" class="org.hisp.dhis.dataelement.DataElementOperand"
+        foreign-key="fk_chart_dataelementoperands_dataelementoperandid" />
+    </list>
+
     <list name="dataSets" table="chart_datasets">
       <cache usage="read-write" />
       <key column="chartid" foreign-key="fk_chart_datasets_chartid" />

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ChartController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ChartController.java	2013-05-08 22:56:40 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ChartController.java	2013-05-10 12:07:51 +0000
@@ -29,16 +29,17 @@
 
 import static org.hisp.dhis.common.DimensionType.DATAELEMENT;
 import static org.hisp.dhis.common.DimensionType.DATAELEMENT_GROUPSET;
+import static org.hisp.dhis.common.DimensionType.DATAELEMENT_OPERAND;
 import static org.hisp.dhis.common.DimensionType.DATASET;
 import static org.hisp.dhis.common.DimensionType.INDICATOR;
 import static org.hisp.dhis.common.DimensionType.ORGANISATIONUNIT;
 import static org.hisp.dhis.common.DimensionType.ORGANISATIONUNIT_GROUPSET;
 import static org.hisp.dhis.common.DimensionType.PERIOD;
+import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIMS;
+import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID;
 import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids;
 import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_USER_ORGUNIT;
 import static org.hisp.dhis.organisationunit.OrganisationUnit.KEY_USER_ORGUNIT_CHILDREN;
-import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIMS;
-import static org.hisp.dhis.common.DimensionalObject.DATA_X_DIM_ID;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -58,6 +59,7 @@
 import org.hisp.dhis.common.DimensionService;
 import org.hisp.dhis.common.DimensionType;
 import org.hisp.dhis.common.DimensionalObject;
+import org.hisp.dhis.dataelement.DataElementOperandService;
 import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.dxf2.utils.JacksonUtils;
@@ -104,6 +106,9 @@
 
     @Autowired
     private DataElementService dataElementService;
+    
+    @Autowired
+    private DataElementOperandService operandService;
 
     @Autowired
     private DataSetService dataSetService;
@@ -306,6 +311,10 @@
             {
                 chart.getDataElements().addAll( dataElementService.getDataElementsByUid( uids ) );
             }
+            else if ( DATAELEMENT_OPERAND.equals( type ) )
+            {
+                chart.getDataElementOperands().addAll( operandService.getDataElementOperandsByUid( uids ) );
+            }
             else if ( DATASET.equals( type ) )
             {
                 chart.getDataSets().addAll( dataSetService.getDataSetsByUid( uids ) );