← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 1675: Impl persistence for the DataElementOperand object. This object will be used in sitations where i...

 

------------------------------------------------------------
revno: 1675
committer: Lars Helge Oeverland <larshelge@xxxxxxxxx>
branch nick: trunk
timestamp: Fri 2010-03-19 14:36:48 +0100
message:
  Impl persistence for the DataElementOperand object. This object will be used in sitations where its necessary to persist a combination of dataelement and categoryoptioncombo. An example is the compolsory dataelement operands for a dataset.
added:
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementOperand.hbm.xml
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java
  dhis-2/dhis-i18n/dhis-i18n-db/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java
  dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java
  dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/dataintegrity/DataIntegrityServiceTest.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java
  dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/GetCompulsoryDataElementsAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/SaveCompulsoryDataElementsAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/compulsoryDataElementsForm.vm


--
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/dataelement/DataElementOperand.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java	2010-03-17 16:08:03 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java	2010-03-19 13:36:48 +0000
@@ -33,6 +33,8 @@
 import java.util.List;
 
 /**
+ * This object can act both as a hydrated persisted object and as a wrapper object.
+ * 
  * @author Abyot Asalefew
  * @version $Id$
  */
@@ -40,7 +42,15 @@
     implements Serializable, Comparable<DataElementOperand>
 {
     public static final String SEPARATOR = ".";
+    
+    private static final String SPACE = "";
 
+    private int id;
+    
+    private DataElement dataElement;
+    
+    private DataElementCategoryOptionCombo categoryOptionCombo;
+    
     private int dataElementId;
 
     private int optionComboId;
@@ -58,7 +68,13 @@
     public DataElementOperand()
     {
     }
-    
+
+    public DataElementOperand( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombo )
+    {
+        this.dataElement = dataElement;
+        this.categoryOptionCombo = categoryOptionCombo;
+    }
+
     public DataElementOperand( int dataElementId, int optionComboId )
     {
         this.dataElementId = dataElementId;
@@ -82,7 +98,7 @@
         this.operandName = operandName;
         this.aggregationLevels = aggregationLevels;
     }
-
+    
     // -------------------------------------------------------------------------
     // Logic
     // -------------------------------------------------------------------------
@@ -129,12 +145,77 @@
         }
         
         return null;
+    }    
+
+    /**
+     * Generates a DataElementOperand based on the given formula. The formula needs
+     * to be on the form "[<dataelementid>,<categoryoptioncomboid>]".
+     * 
+     * @param formula the formula.
+     * @return a DataElementOperand.
+     */
+    public static DataElementOperand generateOperand( String formula )
+    {        
+        final int dataElementId = Integer.parseInt( formula.substring( 0, formula.indexOf( SEPARATOR ) ) );
+        final int categoryOptionComboId = Integer.parseInt( formula.substring( formula.indexOf( SEPARATOR ) + 1, formula.length() ) );
+        
+        return new DataElementOperand( dataElementId, categoryOptionComboId ); 
+    }
+
+    /**
+     * Returns a name based on the DataElement and the DataElementCategoryOptionCombo.
+     * 
+     * @return the name.
+     */
+    public String getPersistedName()
+    {
+        return dataElement.getName() + SPACE + categoryOptionCombo.getName();
     }
     
+    /**
+     * Returns an id based on the DataElement and the DataElementCategoryOptionCombo.
+     * 
+     * @return the id.
+     */
+    public String getPersistedId()
+    {
+        return dataElement.getId() + SEPARATOR + categoryOptionCombo.getId();
+    }
+
     // -------------------------------------------------------------------------
     // Getters & setters
     // -------------------------------------------------------------------------
 
+    public int getId()
+    {
+        return id;
+    }
+
+    public void setId( int id )
+    {
+        this.id = id;
+    }
+
+    public DataElement getDataElement()
+    {
+        return dataElement;
+    }
+
+    public void setDataElement( DataElement dataElement )
+    {
+        this.dataElement = dataElement;
+    }
+
+    public DataElementCategoryOptionCombo getCategoryOptionCombo()
+    {
+        return categoryOptionCombo;
+    }
+
+    public void setCategoryOptionCombo( DataElementCategoryOptionCombo categoryOptionCombo )
+    {
+        this.categoryOptionCombo = categoryOptionCombo;
+    }
+
     public int getDataElementId()
     {
         return dataElementId;
@@ -186,16 +267,17 @@
     }
 
     // -------------------------------------------------------------------------
-    // hashCode and equals
+    // hashCode, equals, toString, compareTo 
     // -------------------------------------------------------------------------
 
     @Override
     public int hashCode()
     {
         final int prime = 31;
-        
         int result = 1;
         
+        result = prime * result + ( ( categoryOptionCombo == null ) ? 0 : categoryOptionCombo.hashCode() );
+        result = prime * result + ( ( dataElement == null ) ? 0 : dataElement.hashCode() );
         result = prime * result + dataElementId;
         result = prime * result + optionComboId;
         
@@ -222,22 +304,48 @@
         
         final DataElementOperand other = (DataElementOperand) object;
         
-        return dataElementId == other.dataElementId && optionComboId == other.optionComboId;
+        if ( categoryOptionCombo == null )
+        {
+            if ( other.categoryOptionCombo != null )
+            {
+                return false;
+            }
+        }
+        else if ( !categoryOptionCombo.equals( other.categoryOptionCombo ) )
+        {
+            return false;
+        }
+        
+        if ( dataElement == null )
+        {
+            if ( other.dataElement != null )
+            {
+                return false;
+            }
+        }
+        else if ( !dataElement.equals( other.dataElement ) )
+        {
+            return false;
+        }
+        
+        if ( dataElementId != other.dataElementId )
+        {
+            return false;
+        }
+        
+        if ( optionComboId != other.optionComboId )
+        {
+            return false;
+        }
+        
+        return true;
     }
-
-    // -------------------------------------------------------------------------
-    // toString
-    // -------------------------------------------------------------------------
-
+    
     @Override
     public String toString()
     {
         return "[DataElementId: " + dataElementId + ", CategoryOptionComboId: " + optionComboId + "]";
     }
-    
-    // -------------------------------------------------------------------------
-    // compareTo
-    // -------------------------------------------------------------------------
 
     public int compareTo( DataElementOperand other )
     {
@@ -247,5 +355,5 @@
         }
         
         return this.getOptionComboId() - other.getOptionComboId();
-    }
+    }    
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java	2010-03-18 13:47:29 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementService.java	2010-03-19 13:36:48 +0000
@@ -480,7 +480,7 @@
     Collection<DataElementGroupSet> getDataElementGroupSets( Collection<Integer> identifiers );
 
     // -------------------------------------------------------------------------
-    // Operand
+    // DataElementOperand
     // -------------------------------------------------------------------------
 
     /**
@@ -490,4 +490,38 @@
      * @return a collection of all Operands.
      */
     Collection<DataElementOperand> getAllGeneratedOperands();
+
+    /**
+     * Returns all generated permutations of Operands for the given collection of
+     * DataElements. Requires the categoryoptioncomboname resource table to be populated.
+     * 
+     * @param dataElements the DataElements.
+     * @return a collection of all Operands.
+     */
+    Collection<DataElementOperand> getAllGeneratedOperands( Collection<DataElement> dataElements );
+    
+    /**
+     * Adds a DataElementOperand.
+     * 
+     * @param operand the DataElementOperand.
+     * @return the generated identifier.
+     */
+    int addDataElementOperand( DataElementOperand operand );
+    
+    /**
+     * Returns the DataElementOperand representing the given DataElement and
+     * DataElementCategoryOptionCombo.
+     * 
+     * @param element the DataElement.
+     * @param categoryOptionCombo the DataElementCategoryOptionCombo.
+     * @return the DataElementOperand.
+     */
+    DataElementOperand getDataElementOperand( DataElement element, DataElementCategoryOptionCombo categoryOptionCombo );
+    
+    /**
+     * Deletes the given DataElementOperand.
+     * 
+     * @param operand the DataElementOperand.
+     */
+    void deleteDataElementOperand( DataElementOperand operand );
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java	2010-03-18 13:47:29 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementStore.java	2010-03-19 13:36:48 +0000
@@ -262,7 +262,7 @@
     Collection<CalculatedDataElement> getAllCalculatedDataElements();
 
     // -------------------------------------------------------------------------
-    // Operand
+    // DataElementOperand
     // -------------------------------------------------------------------------
 
     /**
@@ -272,4 +272,38 @@
      * @return a collection of all Operands.
      */
     Collection<DataElementOperand> getAllGeneratedOperands();
+
+    /**
+     * Returns all generated permutations of Operands for the given collection of
+     * DataElements. Requires the categoryoptioncomboname resource table to be populated.
+     * 
+     * @param dataElements the DataElements.
+     * @return a collection of all Operands.
+     */
+    Collection<DataElementOperand> getAllGeneratedOperands( Collection<DataElement> dataElements );
+    
+    /**
+     * Adds a DataElementOperand.
+     * 
+     * @param operand the DataElementOperand.
+     * @return the generated identifier.
+     */
+    int addDataElementOperand( DataElementOperand operand );
+    
+    /**
+     * Returns the DataElementOperand representing the given DataElement and
+     * DataElementCategoryOptionCombo.
+     * 
+     * @param element the DataElement.
+     * @param categoryOptionCombo the DataElementCategoryOptionCombo.
+     * @return the DataElementOperand.
+     */
+    DataElementOperand getDataElementOperand( DataElement element, DataElementCategoryOptionCombo categoryOptionCombo );
+    
+    /**
+     * Deletes the given DataElementOperand.
+     * 
+     * @param operand the DataElementOperand.
+     */
+    void deleteDataElementOperand( DataElementOperand operand );
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java	2010-02-02 13:21:02 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java	2010-03-19 13:36:48 +0000
@@ -33,6 +33,7 @@
 
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.PeriodType;
 import org.hisp.dhis.source.Source;
@@ -58,10 +59,10 @@
     private Collection<DataElement> dataElements = new HashSet<DataElement>();
     
     /**
-     * The DataElements for which data must be entered in order for the DataSet to
+     * The DataElementOperands for which data must be entered in order for the DataSet to
      * be considered as complete.
      */
-    private Set<DataElement> compulsoryDataElements = new HashSet<DataElement>();
+    private Set<DataElementOperand> compulsoryDataElementOperands = new HashSet<DataElementOperand>();
     
     /**
      * All Sources that register data with this DataSet.
@@ -183,14 +184,14 @@
         this.dataElements = dataElements;
     }
 
-    public Set<DataElement> getCompulsoryDataElements()
+    public Set<DataElementOperand> getCompulsoryDataElementOperands()
     {
-        return compulsoryDataElements;
+        return compulsoryDataElementOperands;
     }
 
-    public void setCompulsoryDataElements( Set<DataElement> compulsoryDataElements )
+    public void setCompulsoryDataElementOperands( Set<DataElementOperand> compulsoryDataElementOperands )
     {
-        this.compulsoryDataElements = compulsoryDataElements;
+        this.compulsoryDataElementOperands = compulsoryDataElementOperands;
     }
 
     public Set<Source> getSources()

=== modified file 'dhis-2/dhis-i18n/dhis-i18n-db/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java'
--- dhis-2/dhis-i18n/dhis-i18n-db/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java	2010-03-11 06:27:12 +0000
+++ dhis-2/dhis-i18n/dhis-i18n-db/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java	2010-03-19 13:36:48 +0000
@@ -145,8 +145,7 @@
         }
        
         I18nObject i18nObject = isI18nObject( intObjects.iterator().next() );
-        
-        
+                
         Locale locale = localeManager.getCurrentLocale();
 
         if ( i18nObject != null && locale != null )

=== modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java'
--- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java	2010-03-19 04:15:47 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java	2010-03-19 13:36:48 +0000
@@ -204,19 +204,21 @@
         for ( Indicator indicator : indicators )
         {
             final String formula = indicator.getNumerator() + FORMULA_SEPARATOR + indicator.getDenominator();
-            
-            if(formulas.containsKey( formula ))
-            {  
-                if(targets.containsKey( formula )){
+
+            if ( formulas.containsKey( formula ) )
+            {
+                if ( targets.containsKey( formula ) )
+                {
                     targets.get( formula ).add( indicator );
                 }
-                else{
+                else
+                {
                     Set<Indicator> elements = new HashSet<Indicator>();
-                    
+
                     elements.add( indicator );
-                    elements.add (formulas.get( formula ));
-                    
-                    targets.put( formula,  elements);
+                    elements.add( formulas.get( formula ) );
+
+                    targets.put( formula, elements );
                     targets.get( formula ).add( indicator );
                 }
             }

=== modified file 'dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/dataintegrity/DataIntegrityServiceTest.java'
--- dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/dataintegrity/DataIntegrityServiceTest.java	2010-03-19 04:15:47 +0000
+++ dhis-2/dhis-services/dhis-service-administration/src/test/java/org/hisp/dhis/dataintegrity/DataIntegrityServiceTest.java	2010-03-19 13:36:48 +0000
@@ -30,6 +30,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
 
@@ -281,8 +282,13 @@
     public void testGetIndicatorsWithIdenticalFormulas()
     {
         Collection<Collection<Indicator>> expected = dataIntegrityService.getIndicatorsWithIdenticalFormulas();
+
+        Collection<Indicator> violation = expected.iterator().next();
         
-        assertTrue( message( expected ), equals( expected, indicatorC ) );
+        assertEquals( 1, expected.size());        
+        assertEquals( 2, violation.size() );
+        assertTrue( violation.contains( indicatorB ) );
+        assertTrue( violation.contains( indicatorC ) );
     }
 
     @Test

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java	2010-03-18 13:47:29 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementService.java	2010-03-19 13:36:48 +0000
@@ -610,11 +610,31 @@
     }
 
     // -------------------------------------------------------------------------
-    // Operand
+    // DataElementOperand
     // -------------------------------------------------------------------------
-    
+
     public Collection<DataElementOperand> getAllGeneratedOperands()
     {
         return dataElementStore.getAllGeneratedOperands();
     }
+    
+    public Collection<DataElementOperand> getAllGeneratedOperands( Collection<DataElement> dataElements )
+    {
+        return dataElementStore.getAllGeneratedOperands( dataElements );
+    }
+    
+    public int addDataElementOperand( DataElementOperand operand )
+    {
+        return dataElementStore.addDataElementOperand( operand );
+    }
+    
+    public DataElementOperand getDataElementOperand( DataElement element, DataElementCategoryOptionCombo categoryOptionCombo )
+    {
+        return dataElementStore.getDataElementOperand( element, categoryOptionCombo );
+    }
+    
+    public void deleteDataElementOperand( DataElementOperand operand )
+    {
+        dataElementStore.deleteDataElementOperand( operand );
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java	2010-03-18 13:47:29 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateDataElementStore.java	2010-03-19 13:36:48 +0000
@@ -43,11 +43,14 @@
 import org.hisp.dhis.dataelement.CalculatedDataElement;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementGroup;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataelement.DataElementStore;
 import org.hisp.dhis.hierarchy.HierarchyViolationException;
 import org.hisp.dhis.system.objectmapper.DataElementOperandMapper;
+import org.hisp.dhis.system.util.ConversionUtils;
+import org.hisp.dhis.system.util.TextUtils;
 
 /**
  * @author Torgeir Lorange Ostby
@@ -415,7 +418,7 @@
     }
 
     // -------------------------------------------------------------------------
-    // Operand
+    // DataElementOperand
     // -------------------------------------------------------------------------
     
     public Collection<DataElementOperand> getAllGeneratedOperands()
@@ -440,4 +443,50 @@
             throw new RuntimeException( "Failed to get all operands", ex );
         }   
     }
+    
+    public Collection<DataElementOperand> getAllGeneratedOperands( Collection<DataElement> dataElements )
+    {
+        final String dataElementString = TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElement.class, dataElements ) );
+        
+        final ObjectMapper<DataElementOperand> mapper = new ObjectMapper<DataElementOperand>();
+        
+        final String sql =
+            "SELECT de.dataelementid, de.name, cocn.categoryoptioncomboid, cocn.categoryoptioncomboname " +
+            "FROM dataelement as de " +
+            "JOIN categorycombo as cc on de.categorycomboid=cc.categorycomboid " +
+            "JOIN categorycombos_optioncombos as ccoc on cc.categorycomboid=ccoc.categorycomboid " +
+            "JOIN categoryoptioncomboname as cocn on ccoc.categoryoptioncomboid=cocn.categoryoptioncomboid " +
+            "WHERE de.dataelementid IN (" + dataElementString + ");";
+        
+        try
+        {
+            ResultSet resultSet = statementManager.getHolder().getStatement().executeQuery( sql );
+            
+            return mapper.getCollection( resultSet, new DataElementOperandMapper() );
+        }
+        catch ( SQLException ex )
+        {
+            throw new RuntimeException( "Failed to get all operands", ex );
+        }   
+    }
+    
+    public int addDataElementOperand( DataElementOperand operand )
+    {
+        return (Integer) sessionFactory.getCurrentSession().save( operand );
+    }
+    
+    public DataElementOperand getDataElementOperand( DataElement element, DataElementCategoryOptionCombo categoryOptionCombo )
+    {
+        Criteria criteria = sessionFactory.getCurrentSession().createCriteria( DataElementOperand.class );
+        
+        criteria.add( Restrictions.eq( "dataElement", element ) );
+        criteria.add( Restrictions.eq( "categoryOptionCombo", categoryOptionCombo ) );
+        
+        return (DataElementOperand) criteria.uniqueResult();
+    }
+    
+    public void deleteDataElementOperand( DataElementOperand operand )
+    {
+        sessionFactory.getCurrentSession().delete( operand );
+    }
 }

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementOperand.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementOperand.hbm.xml	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementOperand.hbm.xml	2010-03-19 13:36:48 +0000
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd";>
+
+<hibernate-mapping>
+  <class name="org.hisp.dhis.dataelement.DataElementOperand" table="dataelementoperand">
+    
+    <id name="id" column="categoryid">
+      <generator class="native"/>
+    </id>
+	
+	<many-to-one name="dataElement" class="org.hisp.dhis.dataelement.DataElement"
+		column="dataelementid" foreign-key="fk_dataelementoperand_dataelement"/>
+	
+	<many-to-one name="categoryOptionCombo" class="org.hisp.dhis.dataelement.DataElementCategoryOptionCombo"
+		column="categoryoptioncomboid" foreign-key="fk_dataelementoperand_dataelementcategoryoptioncombo"/>
+ 
+  </class>
+</hibernate-mapping>
\ No newline at end of file

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml	2010-02-02 13:21:02 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml	2010-03-19 13:36:48 +0000
@@ -21,15 +21,15 @@
     <set name="dataElements" table="datasetmembers">
       <key column="datasetid"/>
       <many-to-many class="org.hisp.dhis.dataelement.DataElement" 
-          column="dataelementid" foreign-key="fk_dataset_dataelementid"/>
-    </set>
-    
-    <set name="compulsoryDataElements" table="compulsorydatasetmembers">
-      <key column="datasetid"/>
-      <many-to-many class="org.hisp.dhis.dataelement.DataElement" 
-          column="dataelementid" foreign-key="fk_dataset_compulsorydataelementid"/>
-    </set>
-    
+        column="dataelementid" foreign-key="fk_dataset_dataelementid"/>
+    </set>
+        
+	<set name="compulsoryDataElementOperands" table="datasetoperands" cascade="all-delete-orphan">
+	  <key column="datasetid"/>
+	  <many-to-many class="org.hisp.dhis.dataelement.DataElementOperand"
+		column="dataelementoperandid" foreign-key="fk_dataset_dataelementoperandid"/>
+	</set>
+		
     <set name="sources" table="datasetsource">
       <key column="datasetid"/>
       <many-to-many column="sourceid" 

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java	2010-03-08 17:41:13 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java	2010-03-19 13:36:48 +0000
@@ -100,7 +100,7 @@
     
     public int getRegistrations( DataSet dataSet, Collection<? extends Source> children, Period period, Date deadline )
     {           
-        final int compulsoryElements = dataSet.getCompulsoryDataElements().size();
+        final int compulsoryElements = dataSet.getCompulsoryDataElementOperands().size();
         final int periodId = period.getId();
         final int dataSetId = dataSet.getId();                
         

=== modified file 'dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java'
--- dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2010-03-02 09:10:46 +0000
+++ dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/DhisConvenienceTest.java	2010-03-19 13:36:48 +0000
@@ -243,9 +243,14 @@
         return true;
     }
     
-    public static String message( Object object )
-    {
-        return "Expected was: " + ( ( object != null ) ? "[" + object.toString() + "]" : "[null]" );
+    public static String message( Object expected )
+    {
+        return "Expected was: " + ( ( expected != null ) ? "[" + expected.toString() + "]" : "[null]" );
+    }
+
+    public static String message( Object expected, Object actual )
+    {
+        return message( expected ) + " Actual was: " + ( ( actual != null ) ? "[" + actual.toString() + "]" : "[null]" );
     }
 
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/GetCompulsoryDataElementsAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/GetCompulsoryDataElementsAction.java	2010-03-08 17:41:13 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/GetCompulsoryDataElementsAction.java	2010-03-19 13:36:48 +0000
@@ -29,10 +29,11 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
-import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementOperand;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dataelement.comparator.DataElementOperandNameComparator;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
 
@@ -55,11 +56,11 @@
         this.dataSetService = dataSetService;
     }
     
-    private Comparator<DataElement> dataElementComparator;
+    private DataElementService dataElementService;
 
-    public void setDataElementComparator( Comparator<DataElement> dataElementComparator )
+    public void setDataElementService( DataElementService dataElementService )
     {
-        this.dataElementComparator = dataElementComparator;
+        this.dataElementService = dataElementService;
     }
 
     // -------------------------------------------------------------------------
@@ -82,18 +83,18 @@
     // Output
     // -------------------------------------------------------------------------
     
-    private List<DataElement> availableDataElements;
-    
-    public List<DataElement> getAvailableDataElements()
+    private List<DataElementOperand> availableOperands;
+
+    public List<DataElementOperand> getAvailableOperands()
     {
-        return availableDataElements;
+        return availableOperands;
     }
 
-    private List<DataElement> selectedDataElements;
+    private List<DataElementOperand> selectedOperands;
 
-    public List<DataElement> getSelectedDataElements()
+    public List<DataElementOperand> getSelectedOperands()
     {
-        return selectedDataElements;
+        return selectedOperands;
     }
 
     // -------------------------------------------------------------------------
@@ -104,13 +105,12 @@
     {
         DataSet dataSet = dataSetService.getDataSet( id );
 
-        selectedDataElements = new ArrayList<DataElement>( dataSet.getCompulsoryDataElements() );
-        
-        availableDataElements = new ArrayList<DataElement>( dataSet.getDataElements() );
-        availableDataElements.removeAll( selectedDataElements );
-        
-        Collections.sort( availableDataElements, dataElementComparator );
-        Collections.sort( selectedDataElements, dataElementComparator );        
+        selectedOperands = new ArrayList<DataElementOperand>( dataSet.getCompulsoryDataElementOperands() );
+        
+        availableOperands = new ArrayList<DataElementOperand>( dataElementService.getAllGeneratedOperands( dataSet.getDataElements() ) );
+        availableOperands.removeAll( selectedOperands );
+        
+        Collections.sort( availableOperands, new DataElementOperandNameComparator() );        
         
         return SUCCESS;
     }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/SaveCompulsoryDataElementsAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/SaveCompulsoryDataElementsAction.java	2010-02-02 13:21:02 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/compulsory/SaveCompulsoryDataElementsAction.java	2010-03-19 13:36:48 +0000
@@ -30,6 +30,8 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
+import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
@@ -60,6 +62,13 @@
         this.dataElementService = dataElementService;
     }
     
+    private DataElementCategoryService categoryService;
+
+    public void setCategoryService( DataElementCategoryService categoryService )
+    {
+        this.categoryService = categoryService;
+    }
+
     // -------------------------------------------------------------------------
     // Input
     // -------------------------------------------------------------------------
@@ -71,11 +80,11 @@
         this.id = id;
     }
 
-    private Collection<String> selectedDataElements = new ArrayList<String>();
+    private Collection<String> selectedOperands = new ArrayList<String>();
 
-    public void setSelectedDataElements( Collection<String> selectedDataElements )
+    public void setSelectedOperands( Collection<String> selectedOperands )
     {
-        this.selectedDataElements = selectedDataElements;
+        this.selectedOperands = selectedOperands;
     }
 
     // -------------------------------------------------------------------------
@@ -85,11 +94,18 @@
     public String execute()
     {
         DataSet dataSet = dataSetService.getDataSet( id );
-        dataSet.getCompulsoryDataElements().clear();
-        
-        for ( String id : selectedDataElements )
-        {
-            dataSet.getCompulsoryDataElements().add( dataElementService.getDataElement( Integer.parseInt( id ) ) );
+        
+        dataSet.getCompulsoryDataElementOperands().clear();
+        
+        for ( String id : selectedOperands )
+        {        
+            DataElementOperand temp = DataElementOperand.generateOperand( id );
+            
+            DataElementOperand operand = new DataElementOperand( 
+                dataElementService.getDataElement( temp.getDataElementId() ),
+                categoryService.getDataElementCategoryOptionCombo( temp.getOptionComboId() ) ); 
+        
+            dataSet.getCompulsoryDataElementOperands().add( operand );
         }
         
         dataSetService.updateDataSet( dataSet );

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/META-INF/dhis/beans.xml	2010-03-08 17:41:13 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/META-INF/dhis/beans.xml	2010-03-19 13:36:48 +0000
@@ -377,7 +377,10 @@
 	scope="prototype">
 	<property name="dataSetService">
       <ref bean="org.hisp.dhis.dataset.DataSetService"/>
-    </property> 
+    </property>  
+    <property name="dataElementService">
+      <ref bean="org.hisp.dhis.dataelement.DataElementService"/>
+    </property>
   </bean>
   
   <bean id="org.hisp.dhis.dataset.action.compulsory.SaveCompulsoryDataElementsAction"
@@ -388,7 +391,10 @@
     </property> 
     <property name="dataElementService">
       <ref bean="org.hisp.dhis.dataelement.DataElementService"/>
-    </property>    
+    </property>
+	<property name="categoryService">
+	  <ref bean="org.hisp.dhis.dataelement.DataElementCategoryService"/>
+	</property>
   </bean>
   
   <bean id="org.hisp.dhis.dataset.action.editor.ShowAssignMultiDataSetForOrgunitAction"

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/compulsoryDataElementsForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/compulsoryDataElementsForm.vm	2010-02-02 13:21:02 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/compulsoryDataElementsForm.vm	2010-03-19 13:36:48 +0000
@@ -3,7 +3,7 @@
 	
 function saveCompulsoryDataElements()
 {
-    selectAllById( "selectedDataElements" );
+    selectAllById( "selectedOperands" );
     document.getElementById( "compulsoryDataElementsForm" ).submit();
 }
 
@@ -21,21 +21,21 @@
     </tr>
     <tr>
         <td>
-    	    <select id="availableDataElements" name="availableDataElements" size="15" style="width:325px" multiple="multiple">
-    	    #foreach( $element in $availableDataElements )
-    	    	<option value="${element.id}">$encoder.htmlEncode( $element.name )</option>
+    	    <select id="availableOperands" name="availableOperands" size="15" style="width:325px" multiple="multiple" ondblclick="moveSelectedById( 'availableOperands', 'selectedOperands' )">
+    	    #foreach( $operand in $availableOperands )
+    	    	<option value="${operand.operandId}">$encoder.htmlEncode( $!operand.operandName )</option>
     	    #end
    	        </select>
     	</td>
     	<td>    	
-    		<input type="button" value="&gt;" title="$i18n.getString( 'move_selected' )" style="width:40px" onclick="moveSelectedById( 'availableDataElements', 'selectedDataElements' )">
+    		<input type="button" value="&gt;" title="$i18n.getString( 'move_selected' )" style="width:40px" onclick="moveSelectedById( 'availableOperands', 'selectedOperands' )">
             <br>
-            <input type="button" value="&lt;" title="$i18n.getString( 'remove_selected' )" style="width:40px" onclick="moveSelectedById( 'selectedDataElements', 'availableDataElements' )">
+            <input type="button" value="&lt;" title="$i18n.getString( 'remove_selected' )" style="width:40px" onclick="moveSelectedById( 'selectedOperands', 'availableOperands' )">
         </td>
         <td>
-            <select id="selectedDataElements" name="selectedDataElements" size="15" style="width:325px" multiple="multiple">
-            #foreach( $element in $selectedDataElements )
-                <option value="${element.id}">$encoder.htmlEncode( $element.name )</option>
+            <select id="selectedOperands" name="selectedOperands" size="15" style="width:325px" multiple="multiple" ondblclick="moveSelectedById( 'selectedOperands', 'availableOperands' )">
+            #foreach( $operand in $selectedOperands )
+                <option value="${operand.persistedId}">$encoder.htmlEncode( $!operand.persistedName )</option>
             #end
             </select>
         </td>