← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13335: Impl support for saving single data values with attribute option combo in web api. Re-arranaged m...

 

------------------------------------------------------------
revno: 13335
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2013-12-20 00:00:15 +0100
message:
  Impl support for saving single data values with attribute option combo in web api. Re-arranaged methods in category service a bit.
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/CategoryOptionComboStore.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateCategoryOptionComboStore.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GenericDimensionalObjectStore.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementCategoryService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.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/DataElementCategoryOptionComboStoreTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.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/common/GenericDimensionalObjectStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GenericDimensionalObjectStore.java	2013-08-23 15:56:19 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GenericDimensionalObjectStore.java	2013-12-19 23:00:15 +0000
@@ -39,5 +39,5 @@
 public interface GenericDimensionalObjectStore<T> 
     extends GenericIdentifiableObjectStore<T>
 {
-    Collection<T> getByConcept(Concept concept);    
+    Collection<T> getByConcept( Concept concept );    
 }

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/CategoryOptionComboStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/CategoryOptionComboStore.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/CategoryOptionComboStore.java	2013-12-19 23:00:15 +0000
@@ -0,0 +1,42 @@
+package org.hisp.dhis.dataelement;
+
+/*
+ * Copyright (c) 2004-2013, 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 java.util.Set;
+
+import org.hisp.dhis.common.GenericIdentifiableObjectStore;
+
+/**
+ * @author Lars Helge Overland
+ */
+public interface CategoryOptionComboStore
+    extends GenericIdentifiableObjectStore<DataElementCategoryOptionCombo>
+{
+    DataElementCategoryOptionCombo getCategoryOptionCombo( DataElementCategoryCombo categoryCombo, Set<DataElementCategoryOption> categoryOptions );
+}

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryService.java	2013-08-23 15:56:19 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementCategoryService.java	2013-12-19 23:00:15 +0000
@@ -30,6 +30,7 @@
 
 import java.util.Collection;
 import java.util.Map;
+import java.util.Set;
 
 import org.hisp.dhis.concept.Concept;
 import org.hisp.dhis.hierarchy.HierarchyViolationException;
@@ -353,6 +354,8 @@
      * @return a DataElementCategoryOptionCombo.
      */
     DataElementCategoryOptionCombo getDataElementCategoryOptionCombo( DataElementCategoryOptionCombo categoryOptionCombo );
+    
+    DataElementCategoryOptionCombo getDataElementCategoryOptionCombo( DataElementCategoryCombo categoryCombo, Set<DataElementCategoryOption> categoryOptions );
 
     /**
      * Retrieves all DataElementCategoryOptionCombos.

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java	2013-12-19 18:12:57 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java	2013-12-19 23:00:15 +0000
@@ -106,12 +106,25 @@
      * @param period the Period of the DataValue.
      * @param source the Source of the DataValue.
      * @param categoryOptionCombo the category option combo.
+     * @return the DataValue which corresponds to the given parameters, or null
+     *         if no match.
+     */
+    DataValue getDataValue( DataElement dataElement, Period period, OrganisationUnit source, DataElementCategoryOptionCombo optionCombo );
+
+    /**
+     * Returns a DataValue.
+     * 
+     * @param dataElement the DataElement of the DataValue.
+     * @param period the Period of the DataValue.
+     * @param source the Source of the DataValue.
+     * @param categoryOptionCombo the category option combo.
      * @param attributeOptionCombo the attribute option combo.
      * @return the DataValue which corresponds to the given parameters, or null
      *         if no match.
      */
-    DataValue getDataValue( DataElement dataElement, Period period, OrganisationUnit source, DataElementCategoryOptionCombo optionCombo );
-
+    DataValue getDataValue( DataElement dataElement, Period period, OrganisationUnit source, 
+        DataElementCategoryOptionCombo categoryOptionCombo, DataElementCategoryOptionCombo attributeOptionCombo );
+    
     /**
      * Returns a non-persisted DataValue.
      * 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementCategoryService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementCategoryService.java	2013-08-23 16:05:01 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/DefaultDataElementCategoryService.java	2013-12-19 23:00:15 +0000
@@ -62,35 +62,32 @@
     // Dependencies
     // -------------------------------------------------------------------------
 
-    private GenericDimensionalObjectStore<DataElementCategory> dataElementCategoryStore;
-
-    public void setDataElementCategoryStore( GenericDimensionalObjectStore<DataElementCategory> dataElementCategoryStore )
-    {
-        this.dataElementCategoryStore = dataElementCategoryStore;
-    }
-
-    private GenericDimensionalObjectStore<DataElementCategoryOption> dataElementCategoryOptionStore;
-
-    public void setDataElementCategoryOptionStore(
-        GenericDimensionalObjectStore<DataElementCategoryOption> dataElementCategoryOptionStore )
-    {
-        this.dataElementCategoryOptionStore = dataElementCategoryOptionStore;
-    }
-
-    private GenericIdentifiableObjectStore<DataElementCategoryCombo> dataElementCategoryComboStore;
-
-    public void setDataElementCategoryComboStore(
-        GenericIdentifiableObjectStore<DataElementCategoryCombo> dataElementCategoryComboStore )
-    {
-        this.dataElementCategoryComboStore = dataElementCategoryComboStore;
-    }
-
-    private GenericIdentifiableObjectStore<DataElementCategoryOptionCombo> dataElementCategoryOptionComboStore;
-
-    public void setDataElementCategoryOptionComboStore(
-        GenericIdentifiableObjectStore<DataElementCategoryOptionCombo> dataElementCategoryOptionComboStore )
-    {
-        this.dataElementCategoryOptionComboStore = dataElementCategoryOptionComboStore;
+    private GenericDimensionalObjectStore<DataElementCategory> categoryStore;
+
+    public void setCategoryStore( GenericDimensionalObjectStore<DataElementCategory> categoryStore )
+    {
+        this.categoryStore = categoryStore;
+    }
+
+    private GenericDimensionalObjectStore<DataElementCategoryOption> categoryOptionStore;
+
+    public void setCategoryOptionStore( GenericDimensionalObjectStore<DataElementCategoryOption> categoryOptionStore )
+    {
+        this.categoryOptionStore = categoryOptionStore;
+    }
+
+    private GenericIdentifiableObjectStore<DataElementCategoryCombo> categoryComboStore;
+
+    public void setCategoryComboStore( GenericIdentifiableObjectStore<DataElementCategoryCombo> categoryComboStore )
+    {
+        this.categoryComboStore = categoryComboStore;
+    }
+
+    private CategoryOptionComboStore categoryOptionComboStore;
+
+    public void setCategoryOptionComboStore( CategoryOptionComboStore categoryOptionComboStore )
+    {
+        this.categoryOptionComboStore = categoryOptionComboStore;
     }
 
     private DataElementService dataElementService;
@@ -113,17 +110,17 @@
 
     public int addDataElementCategory( DataElementCategory dataElementCategory )
     {
-        return dataElementCategoryStore.save( dataElementCategory );
+        return categoryStore.save( dataElementCategory );
     }
 
     public void updateDataElementCategory( DataElementCategory dataElementCategory )
     {
-        dataElementCategoryStore.update( dataElementCategory );
+        categoryStore.update( dataElementCategory );
     }
 
     public void deleteDataElementCategory( DataElementCategory dataElementCategory )
     {
-        dataElementCategoryStore.delete( dataElementCategory );
+        categoryStore.delete( dataElementCategory );
     }
 
     public Collection<DataElementCategory> getDataDimensionDataElementCategories()
@@ -143,17 +140,17 @@
     
     public Collection<DataElementCategory> getAllDataElementCategories()
     {
-        return i18n( i18nService, dataElementCategoryStore.getAll() );
+        return i18n( i18nService, categoryStore.getAll() );
     }
 
     public DataElementCategory getDataElementCategory( int id )
     {
-        return i18n( i18nService, dataElementCategoryStore.get( id ) );
+        return i18n( i18nService, categoryStore.get( id ) );
     }
 
     public DataElementCategory getDataElementCategory( String uid )
     {
-        return i18n( i18nService, dataElementCategoryStore.getByUid( uid ) );
+        return i18n( i18nService, categoryStore.getByUid( uid ) );
     }
 
     public Collection<DataElementCategory> getDataElementCategories( final Collection<Integer> identifiers )
@@ -171,13 +168,13 @@
     
     public Collection<DataElementCategory> getDataElementCategoriesByUid( Collection<String> uids )
     {
-        return dataElementCategoryStore.getByUid( uids );
+        return categoryStore.getByUid( uids );
     }
 
     public DataElementCategory getDataElementCategoryByName( String name )
     {
         List<DataElementCategory> dataElementCategories = new ArrayList<DataElementCategory>(
-            dataElementCategoryStore.getAllEqName( name ) );
+            categoryStore.getAllEqName( name ) );
 
         if ( dataElementCategories.isEmpty() )
         {
@@ -187,43 +184,81 @@
         return i18n( i18nService, dataElementCategories.get( 0 ) );
     }
 
+    @Override
+    public Collection<DataElementCategory> getDataElementCategorysByConcept( Concept concept )
+    {
+        return i18n( i18nService, categoryStore.getByConcept( concept ) );
+    }
+
+    @Override
+    public Collection<DataElementCategory> getDataElementCategoryBetween( int first, int max )
+    {
+        return i18n( i18nService, categoryStore.getAllOrderedName( first, max ) );
+    }
+
+    @Override
+    public Collection<DataElementCategory> getDataElementCategoryBetweenByName( String name, int first, int max )
+    {
+        return i18n( i18nService, categoryStore.getAllLikeNameOrderedName( name, first, max ) );
+    }
+
+    public Collection<DataElementCategory> getDataElementCategorysBetween( int first, int max )
+    {
+        return i18n( i18nService, categoryStore.getAllOrderedName( first, max ) );
+    }
+
+    public Collection<DataElementCategory> getDataElementCategorysBetweenByName( String name, int first, int max )
+    {
+        return i18n( i18nService, categoryStore.getAllLikeNameOrderedName( name, first, max ) );
+    }
+
+    public int getDataElementCategoryCount()
+    {
+        return categoryStore.getCount();
+    }
+
+    public int getDataElementCategoryCountByName( String name )
+    {
+        return categoryStore.getCountLikeName( name );
+    }
+
     // -------------------------------------------------------------------------
     // CategoryOption
     // -------------------------------------------------------------------------
 
     public int addDataElementCategoryOption( DataElementCategoryOption dataElementCategoryOption )
     {
-        return dataElementCategoryOptionStore.save( dataElementCategoryOption );
+        return categoryOptionStore.save( dataElementCategoryOption );
     }
 
     public void updateDataElementCategoryOption( DataElementCategoryOption dataElementCategoryOption )
     {
-        dataElementCategoryOptionStore.update( dataElementCategoryOption );
+        categoryOptionStore.update( dataElementCategoryOption );
     }
 
     public void deleteDataElementCategoryOption( DataElementCategoryOption dataElementCategoryOption )
     {
-        dataElementCategoryOptionStore.delete( dataElementCategoryOption );
+        categoryOptionStore.delete( dataElementCategoryOption );
     }
 
     public DataElementCategoryOption getDataElementCategoryOption( int id )
     {
-        return i18n( i18nService, dataElementCategoryOptionStore.get( id ) );
+        return i18n( i18nService, categoryOptionStore.get( id ) );
     }
 
     public DataElementCategoryOption getDataElementCategoryOption( String uid )
     {
-        return i18n( i18nService, dataElementCategoryOptionStore.getByUid( uid ) );
+        return i18n( i18nService, categoryOptionStore.getByUid( uid ) );
     }
 
     public DataElementCategoryOption getDataElementCategoryOptionByName( String name )
     {
-        return i18n( i18nService, dataElementCategoryOptionStore.getByName( name ) );
+        return i18n( i18nService, categoryOptionStore.getByName( name ) );
     }
 
     public DataElementCategoryOption getDataElementCategoryOptionByCode( String code )
     {
-        return i18n( i18nService, dataElementCategoryOptionStore.getByCode( code ) );
+        return i18n( i18nService, categoryOptionStore.getByCode( code ) );
     }
 
     public Collection<DataElementCategoryOption> getDataElementCategoryOptions( final Collection<Integer> identifiers )
@@ -242,12 +277,42 @@
 
     public Collection<DataElementCategoryOption> getDataElementCategoryOptionsByUid( Collection<String> uids )
     {
-        return dataElementCategoryOptionStore.getByUid( uids );
+        return categoryOptionStore.getByUid( uids );
     }
 
     public Collection<DataElementCategoryOption> getAllDataElementCategoryOptions()
     {
-        return i18n( i18nService, dataElementCategoryOptionStore.getAll() );
+        return i18n( i18nService, categoryOptionStore.getAll() );
+    }
+
+    @Override
+    public Collection<DataElementCategoryOption> getDataElementCategoryOptionsBetween( int first, int max )
+    {
+        return i18n( i18nService, categoryOptionStore.getAllOrderedName( first, max ) );
+    }
+
+    @Override
+    public Collection<DataElementCategoryOption> getDataElementCategoryOptionsBetweenByName( String name, int first, int max )
+    {
+        return i18n( i18nService, categoryOptionStore.getAllLikeNameOrderedName( name, first, max ) );
+    }
+
+    @Override
+    public Collection<DataElementCategoryOption> getDataElementCategorOptionsByConcept( Concept concept )
+    {
+        return categoryOptionStore.getByConcept( concept );
+    }
+
+    @Override
+    public int getDataElementCategoryOptionCount()
+    {
+        return categoryOptionStore.getCount();
+    }
+
+    @Override
+    public int getDataElementCategoryOptionCountByName( String name )
+    {
+        return categoryOptionStore.getCountLikeName( name );
     }
 
     // -------------------------------------------------------------------------
@@ -256,32 +321,32 @@
 
     public int addDataElementCategoryCombo( DataElementCategoryCombo dataElementCategoryCombo )
     {
-        return dataElementCategoryComboStore.save( dataElementCategoryCombo );
+        return categoryComboStore.save( dataElementCategoryCombo );
     }
 
     public void updateDataElementCategoryCombo( DataElementCategoryCombo dataElementCategoryCombo )
     {
-        dataElementCategoryComboStore.save( dataElementCategoryCombo );
+        categoryComboStore.save( dataElementCategoryCombo );
     }
 
     public void deleteDataElementCategoryCombo( DataElementCategoryCombo dataElementCategoryCombo )
     {
-        dataElementCategoryComboStore.delete( dataElementCategoryCombo );
+        categoryComboStore.delete( dataElementCategoryCombo );
     }
 
     public Collection<DataElementCategoryCombo> getAllDataElementCategoryCombos()
     {
-        return i18n( i18nService, dataElementCategoryComboStore.getAll() );
+        return i18n( i18nService, categoryComboStore.getAll() );
     }
 
     public DataElementCategoryCombo getDataElementCategoryCombo( int id )
     {
-        return i18n( i18nService, dataElementCategoryComboStore.get( id ) );
+        return i18n( i18nService, categoryComboStore.get( id ) );
     }
 
     public DataElementCategoryCombo getDataElementCategoryCombo( String uid )
     {
-        return i18n( i18nService, dataElementCategoryComboStore.getByUid( uid ) );
+        return i18n( i18nService, categoryComboStore.getByUid( uid ) );
     }
 
     public Collection<DataElementCategoryCombo> getDataElementCategoryCombos( final Collection<Integer> identifiers )
@@ -300,36 +365,56 @@
 
     public DataElementCategoryCombo getDataElementCategoryComboByName( String name )
     {
-        return i18n( i18nService, dataElementCategoryComboStore.getByName( name ) );
-    }
-
+        return i18n( i18nService, categoryComboStore.getByName( name ) );
+    }
+
+    public int getDataElementCategoryComboCount()
+    {
+        return categoryComboStore.getCount();
+    }
+
+    public int getDataElementCategoryComboCountByName( String name )
+    {
+        return categoryComboStore.getCountLikeName( name );
+    }
+
+    public Collection<DataElementCategoryCombo> getDataElementCategoryCombosBetween( int first, int max )
+    {
+        return i18n( i18nService, categoryComboStore.getAllOrderedName( first, max ) );
+    }
+
+    public Collection<DataElementCategoryCombo> getDataElementCategoryCombosBetweenByName( String name, int first, int max )
+    {
+        return i18n( i18nService, categoryComboStore.getAllLikeNameOrderedName( name, first, max ) );
+    }
+    
     // -------------------------------------------------------------------------
     // CategoryOptionCombo
     // -------------------------------------------------------------------------
 
     public int addDataElementCategoryOptionCombo( DataElementCategoryOptionCombo dataElementCategoryOptionCombo )
     {
-        return dataElementCategoryOptionComboStore.save( dataElementCategoryOptionCombo );
+        return categoryOptionComboStore.save( dataElementCategoryOptionCombo );
     }
 
     public void updateDataElementCategoryOptionCombo( DataElementCategoryOptionCombo dataElementCategoryOptionCombo )
     {
-        dataElementCategoryOptionComboStore.update( dataElementCategoryOptionCombo );
+        categoryOptionComboStore.update( dataElementCategoryOptionCombo );
     }
 
     public void deleteDataElementCategoryOptionCombo( DataElementCategoryOptionCombo dataElementCategoryOptionCombo )
     {
-        dataElementCategoryOptionComboStore.delete( dataElementCategoryOptionCombo );
+        categoryOptionComboStore.delete( dataElementCategoryOptionCombo );
     }
 
     public DataElementCategoryOptionCombo getDataElementCategoryOptionCombo( int id )
     {
-        return dataElementCategoryOptionComboStore.get( id );
+        return categoryOptionComboStore.get( id );
     }
 
     public DataElementCategoryOptionCombo getDataElementCategoryOptionCombo( String uid )
     {
-        return dataElementCategoryOptionComboStore.getByUid( uid );
+        return categoryOptionComboStore.getByUid( uid );
     }
 
     public Collection<DataElementCategoryOptionCombo> getDataElementCategoryOptionCombos(
@@ -349,7 +434,7 @@
 
     public Collection<DataElementCategoryOptionCombo> getDataElementCategoryOptionCombosByUid( Collection<String> uids )
     {
-        return dataElementCategoryOptionComboStore.getByUid( uids );
+        return categoryOptionComboStore.getByUid( uids );
     }
 
     public DataElementCategoryOptionCombo getDataElementCategoryOptionCombo(
@@ -385,9 +470,14 @@
         return null;
     }
 
+    public DataElementCategoryOptionCombo getDataElementCategoryOptionCombo( DataElementCategoryCombo categoryCombo, Set<DataElementCategoryOption> categoryOptions )
+    {
+        return categoryOptionComboStore.getCategoryOptionCombo( categoryCombo, categoryOptions );
+    }
+    
     public Collection<DataElementCategoryOptionCombo> getAllDataElementCategoryOptionCombos()
     {
-        return dataElementCategoryOptionComboStore.getAll();
+        return categoryOptionComboStore.getAll();
     }
 
     public void generateDefaultDimension()
@@ -587,105 +677,15 @@
         return map;
     }
 
-    public int getDataElementCategoryCount()
-    {
-        return dataElementCategoryStore.getCount();
-    }
-
-    public int getDataElementCategoryCountByName( String name )
-    {
-        return dataElementCategoryStore.getCountLikeName( name );
-    }
-
-    @Override
-    public int getDataElementCategoryOptionCount()
-    {
-        return dataElementCategoryOptionStore.getCount();
-    }
-
-    @Override
-    public int getDataElementCategoryOptionCountByName( String name )
-    {
-        return dataElementCategoryOptionStore.getCountLikeName( name );
-    }
-
     @Override
     public int getDataElementCategoryOptionComboCount()
     {
-        return dataElementCategoryOptionComboStore.getCount();
+        return categoryOptionComboStore.getCount();
     }
 
     @Override
     public int getDataElementCategoryOptionComboCountByName( String name )
     {
-        return dataElementCategoryOptionComboStore.getCountLikeName( name );
-    }
-
-    public Collection<DataElementCategory> getDataElementCategorysBetween( int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryStore.getAllOrderedName( first, max ) );
-    }
-
-    public Collection<DataElementCategory> getDataElementCategorysBetweenByName( String name, int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryStore.getAllLikeNameOrderedName( name, first, max ) );
-    }
-
-    public int getDataElementCategoryComboCount()
-    {
-        return dataElementCategoryComboStore.getCount();
-    }
-
-    public int getDataElementCategoryComboCountByName( String name )
-    {
-        return dataElementCategoryComboStore.getCountLikeName( name );
-    }
-
-    public Collection<DataElementCategoryCombo> getDataElementCategoryCombosBetween( int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryComboStore.getAllOrderedName( first, max ) );
-    }
-
-    public Collection<DataElementCategoryCombo> getDataElementCategoryCombosBetweenByName( String name, int first,
-        int max )
-    {
-        return i18n( i18nService, dataElementCategoryComboStore.getAllLikeNameOrderedName( name, first, max ) );
-    }
-
-    @Override
-    public Collection<DataElementCategoryOption> getDataElementCategorOptionsByConcept( Concept concept )
-    {
-        return dataElementCategoryOptionStore.getByConcept( concept );
-    }
-
-    @Override
-    public Collection<DataElementCategory> getDataElementCategorysByConcept( Concept concept )
-    {
-        return i18n( i18nService, dataElementCategoryStore.getByConcept( concept ) );
-    }
-
-    @Override
-    public Collection<DataElementCategory> getDataElementCategoryBetween( int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryStore.getAllOrderedName( first, max ) );
-    }
-
-    @Override
-    public Collection<DataElementCategory> getDataElementCategoryBetweenByName( String name, int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryStore.getAllLikeNameOrderedName( name, first, max ) );
-    }
-
-    @Override
-    public Collection<DataElementCategoryOption> getDataElementCategoryOptionsBetween( int first, int max )
-    {
-        return i18n( i18nService, dataElementCategoryOptionStore.getAllOrderedName( first, max ) );
-    }
-
-    @Override
-    public Collection<DataElementCategoryOption> getDataElementCategoryOptionsBetweenByName( String name, int first,
-        int max )
-    {
-        return i18n( i18nService, dataElementCategoryOptionStore.getAllLikeNameOrderedName( name, first, max ) );
+        return categoryOptionComboStore.getCountLikeName( name );
     }
 }

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateCategoryOptionComboStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateCategoryOptionComboStore.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataelement/hibernate/HibernateCategoryOptionComboStore.java	2013-12-19 23:00:15 +0000
@@ -0,0 +1,67 @@
+package org.hisp.dhis.dataelement.hibernate;
+
+/*
+ * Copyright (c) 2004-2013, 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 java.util.Set;
+
+import org.hibernate.Query;
+import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore;
+import org.hisp.dhis.dataelement.CategoryOptionComboStore;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class HibernateCategoryOptionComboStore
+    extends HibernateIdentifiableObjectStore<DataElementCategoryOptionCombo>
+    implements CategoryOptionComboStore
+{
+    public DataElementCategoryOptionCombo getCategoryOptionCombo( DataElementCategoryCombo categoryCombo, Set<DataElementCategoryOption> categoryOptions )
+    {
+        String hql = "from DataElementCategoryOptionCombo co where co.categoryCombo = :categoryCombo";
+        
+        for ( DataElementCategoryOption option : categoryOptions )
+        {
+            hql += " and :option" + option.getId() + " in elements (co.categoryOptions)";
+        }
+        
+        Query query = getQuery( hql );
+        
+        query.setEntity( "categoryCombo", categoryCombo );
+        
+        for ( DataElementCategoryOption option : categoryOptions )
+        {
+            query.setEntity( "option" + option.getId(), option );
+        }
+        
+        return (DataElementCategoryOptionCombo) query.uniqueResult();
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java	2013-12-19 18:12:57 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java	2013-12-19 23:00:15 +0000
@@ -127,6 +127,12 @@
         
         return dataValueStore.getDataValue( dataElement, period, source, categoryOptionCombo, defaultOptionCombo );
     }
+
+    public DataValue getDataValue( DataElement dataElement, Period period, OrganisationUnit source, 
+        DataElementCategoryOptionCombo categoryOptionCombo, DataElementCategoryOptionCombo attributeOptionCombo )
+    {
+        return dataValueStore.getDataValue( dataElement, period, source, categoryOptionCombo, attributeOptionCombo );
+    }
     
     public DataValue getDataValue( int dataElementId, int periodId, int sourceId, int categoryOptionComboId )
     {

=== 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-12-19 18:12:57 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2013-12-19 23:00:15 +0000
@@ -156,8 +156,8 @@
     <property name="cacheable" value="true" />
   </bean>
 
-  <bean id="org.hisp.dhis.dataelement.DataElementCategoryOptionComboStore"
-    class="org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore">
+  <bean id="org.hisp.dhis.dataelement.CategoryOptionComboStore"
+    class="org.hisp.dhis.dataelement.hibernate.HibernateCategoryOptionComboStore">
     <property name="clazz" value="org.hisp.dhis.dataelement.DataElementCategoryOptionCombo" />
     <property name="sessionFactory" ref="sessionFactory" />
     <property name="cacheable" value="true" />
@@ -453,10 +453,10 @@
   <bean id="monitoringLastDayTask" class="org.hisp.dhis.validation.scheduling.MonitoringTask" />
 
   <bean id="org.hisp.dhis.dataelement.DataElementCategoryService" class="org.hisp.dhis.dataelement.DefaultDataElementCategoryService">
-    <property name="dataElementCategoryStore" ref="org.hisp.dhis.dataelement.DataElementCategoryStore" />
-    <property name="dataElementCategoryOptionStore" ref="org.hisp.dhis.dataelement.DataElementCategoryOptionStore" />
-    <property name="dataElementCategoryComboStore" ref="org.hisp.dhis.dataelement.DataElementCategoryComboStore" />
-    <property name="dataElementCategoryOptionComboStore" ref="org.hisp.dhis.dataelement.DataElementCategoryOptionComboStore" />
+    <property name="categoryStore" ref="org.hisp.dhis.dataelement.DataElementCategoryStore" />
+    <property name="categoryOptionStore" ref="org.hisp.dhis.dataelement.DataElementCategoryOptionStore" />
+    <property name="categoryComboStore" ref="org.hisp.dhis.dataelement.DataElementCategoryComboStore" />
+    <property name="categoryOptionComboStore" ref="org.hisp.dhis.dataelement.CategoryOptionComboStore" />
     <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
     <property name="i18nService" ref="org.hisp.dhis.i18n.I18nService" />
   </bean>

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementCategoryOptionComboStoreTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementCategoryOptionComboStoreTest.java	2013-08-23 16:05:01 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataelement/DataElementCategoryOptionComboStoreTest.java	2013-12-19 23:00:15 +0000
@@ -37,19 +37,15 @@
 import java.util.Set;
 
 import org.hisp.dhis.DhisSpringTest;
-import org.hisp.dhis.common.GenericStore;
-import org.hisp.dhis.hibernate.HibernateGenericStore;
 import org.junit.Test;
 
 /**
  * @author Lars Helge Overland
- * @version $Id$
  */
-@SuppressWarnings( "unchecked" )
 public class DataElementCategoryOptionComboStoreTest
     extends DhisSpringTest
 {
-    private GenericStore<DataElementCategoryOptionCombo> categoryOptionComboStore;
+    private CategoryOptionComboStore categoryOptionComboStore;
     
     private DataElementCategory categoryA;
     private DataElementCategory categoryB;
@@ -76,8 +72,7 @@
     {
         categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
         
-        categoryOptionComboStore = (HibernateGenericStore<DataElementCategoryOptionCombo>) 
-            getBean( "org.hisp.dhis.dataelement.DataElementCategoryOptionComboStore" );
+        categoryOptionComboStore = (CategoryOptionComboStore) getBean( "org.hisp.dhis.dataelement.CategoryOptionComboStore" );
         
         categoryOptionA = new DataElementCategoryOption( "Male" );
         categoryOptionB = new DataElementCategoryOption( "Female" );
@@ -218,6 +213,60 @@
             categoryOptionComboStore.getAll();
         
         assertNotNull( categoryOptionCombos );
-        assertEquals( 4, categoryOptionCombos.size() ); // Including default category option combo
+        assertEquals( 4, categoryOptionCombos.size() ); // Including default
+    }
+    
+    @Test
+    public void testGenerateCategoryOptionCombos()
+    {
+        categoryService.generateOptionCombos( categoryComboA );
+        categoryService.generateOptionCombos( categoryComboB );
+        
+        Collection<DataElementCategoryOptionCombo> optionCombos = categoryService.getAllDataElementCategoryOptionCombos();
+        
+        assertEquals( 7, optionCombos.size() ); // Including default
+    }
+    
+    @Test
+    public void testGetCategoryOptionCombo()
+    {
+        categoryService.generateOptionCombos( categoryComboA );
+        categoryService.generateOptionCombos( categoryComboB );
+        
+        Set<DataElementCategoryOption> categoryOptions1 = new HashSet<DataElementCategoryOption>();
+        categoryOptions1.add( categoryOptionA );
+        categoryOptions1.add( categoryOptionC );
+
+        Set<DataElementCategoryOption> categoryOptions2 = new HashSet<DataElementCategoryOption>();
+        categoryOptions2.add( categoryOptionA );
+        categoryOptions2.add( categoryOptionD );
+
+        Set<DataElementCategoryOption> categoryOptions3 = new HashSet<DataElementCategoryOption>();
+        categoryOptions3.add( categoryOptionB );
+        categoryOptions3.add( categoryOptionC );
+
+        Set<DataElementCategoryOption> categoryOptions4 = new HashSet<DataElementCategoryOption>();
+        categoryOptions4.add( categoryOptionB );
+        categoryOptions4.add( categoryOptionC );
+        
+        DataElementCategoryOptionCombo coc1 = categoryOptionComboStore.getCategoryOptionCombo( categoryComboA, categoryOptions1 );
+        DataElementCategoryOptionCombo coc2 = categoryOptionComboStore.getCategoryOptionCombo( categoryComboA, categoryOptions2 );
+        DataElementCategoryOptionCombo coc3 = categoryOptionComboStore.getCategoryOptionCombo( categoryComboA, categoryOptions3 );
+        DataElementCategoryOptionCombo coc4 = categoryOptionComboStore.getCategoryOptionCombo( categoryComboA, categoryOptions4 );
+        
+        assertNotNull( coc1 );
+        assertNotNull( coc2 );
+        assertNotNull( coc3 );
+        assertNotNull( coc4 );
+        
+        assertEquals( categoryComboA, coc1.getCategoryCombo() );
+        assertEquals( categoryComboA, coc2.getCategoryCombo() );
+        assertEquals( categoryComboA, coc3.getCategoryCombo() );
+        assertEquals( categoryComboA, coc4.getCategoryCombo() );
+        
+        assertEquals( categoryOptions1, coc1.getCategoryOptions() );
+        assertEquals( categoryOptions2, coc2.getCategoryOptions() );
+        assertEquals( categoryOptions3, coc3.getCategoryOptions() );
+        assertEquals( categoryOptions4, coc4.getCategoryOptions() );
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java	2013-12-19 18:12:57 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataValueController.java	2013-12-19 23:00:15 +0000
@@ -29,12 +29,16 @@
  */
 
 import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.lang.StringUtils;
 import org.hisp.dhis.api.utils.ContextUtils;
 import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataelement.DataElementService;
@@ -80,97 +84,187 @@
 
     @Autowired
     private DataSetService dataSetService;
-    
-    @PreAuthorize("hasRole('ALL') or hasRole('F_DATAVALUE_ADD')")
+
+    @PreAuthorize( "hasRole('ALL') or hasRole('F_DATAVALUE_ADD')" )
     @RequestMapping( method = RequestMethod.POST, produces = "text/plain" )
-    public void saveDataValue( @RequestParam String de, @RequestParam(required=false) String co, 
-        @RequestParam String pe, @RequestParam String ou, 
-        @RequestParam(required=false) String value, @RequestParam(required=false) String comment,
-        @RequestParam(required=false) boolean followUp, HttpServletResponse response )
+    public void saveDataValue( 
+        @RequestParam String de, 
+        @RequestParam( required = false ) String co, 
+        @RequestParam( required = false ) String cc, 
+        @RequestParam( required = false ) Set<String> cp, 
+        @RequestParam String pe, 
+        @RequestParam String ou, 
+        @RequestParam( required = false ) String value, 
+        @RequestParam( required = false ) String comment, 
+        @RequestParam( required = false ) boolean followUp, HttpServletResponse response )
     {
+        // ---------------------------------------------------------------------
+        // Data element validation
+        // ---------------------------------------------------------------------
+
         DataElement dataElement = dataElementService.getDataElement( de );
-        
+
         if ( dataElement == null )
         {
             ContextUtils.conflictResponse( response, "Illegal data element identifier: " + de );
             return;
         }
-        
+
+        // ---------------------------------------------------------------------
+        // Category option combo validation
+        // ---------------------------------------------------------------------
+
         DataElementCategoryOptionCombo categoryOptionCombo = null;
-        
-        if ( co == null )
+
+        if ( co != null )
+        {
+            categoryOptionCombo = categoryService.getDataElementCategoryOptionCombo( co );
+        }
+        else
         {
             categoryOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
         }
-        else
-        {
-            categoryOptionCombo = categoryService.getDataElementCategoryOptionCombo( co );
-        }
-        
+
         if ( categoryOptionCombo == null )
         {
             ContextUtils.conflictResponse( response, "Illegal category option combo identifier: " + co );
             return;
         }
-        
+
+        // ---------------------------------------------------------------------
+        // Attribute category combo validation
+        // ---------------------------------------------------------------------
+
+        if ( ( cc == null && ( cp != null && !cp.isEmpty() ) || ( cc != null && ( cp == null || cp.isEmpty() ) ) ) )
+        {
+            ContextUtils.conflictResponse( response, "Both or none of category combination and category options must be present" );
+            return;
+        }
+
+        DataElementCategoryCombo categoryCombo = null;
+        
+        if ( cc != null && ( categoryCombo = categoryService.getDataElementCategoryCombo( cc ) ) == null )
+        {
+            ContextUtils.conflictResponse( response, "Illegal category combo identifier: " + cc );
+            return;
+        }
+
+        // ---------------------------------------------------------------------
+        // Attribute category options validation
+        // ---------------------------------------------------------------------
+
+        DataElementCategoryOptionCombo attributeOptionCombo = null;
+
+        if ( cp != null )
+        {
+            Set<DataElementCategoryOption> categoryOptions = new HashSet<DataElementCategoryOption>();
+
+            for ( String id : cp )
+            {
+                DataElementCategoryOption categoryOption = categoryService.getDataElementCategoryOption( id );
+                
+                if ( categoryOption != null )
+                {
+                    ContextUtils.conflictResponse( response, "Illegal category option identifier: " + id );
+                    return;
+                }
+                
+                categoryOptions.add( categoryOption );
+            }
+            
+            attributeOptionCombo = categoryService.getDataElementCategoryOptionCombo( categoryCombo, categoryOptions );
+            
+            if ( attributeOptionCombo == null )
+            {
+                ContextUtils.conflictResponse( response, "Attribute option combo does not exist for given category combo and category options" );
+                return;
+            }
+        }
+
+        if ( attributeOptionCombo == null )
+        {
+            attributeOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
+        }
+        
+        // ---------------------------------------------------------------------
+        // Period validation
+        // ---------------------------------------------------------------------
+
         Period period = PeriodType.getPeriodFromIsoString( pe );
-        
+
         if ( period == null )
         {
             ContextUtils.conflictResponse( response, "Illegal period identifier: " + pe );
             return;
         }
-        
+
+        // ---------------------------------------------------------------------
+        // Organisation unit validation
+        // ---------------------------------------------------------------------
+
         OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( ou );
-        
+
         if ( organisationUnit == null )
         {
             ContextUtils.conflictResponse( response, "Illegal organisation unit identifier: " + ou );
             return;
         }
 
-        if ( dataSetService.isLocked( dataElement, period, organisationUnit, null ) )
-        {
-            ContextUtils.conflictResponse( response, "Data set is locked" );
-            return;
-        }
-        
+        // ---------------------------------------------------------------------
+        // Data value and comment validation
+        // ---------------------------------------------------------------------
+
         String valid = ValidationUtils.dataValueIsValid( value, dataElement );
-        
+
         if ( valid != null )
         {
             ContextUtils.conflictResponse( response, "Invalid value: " + value + ", must match data element type: " + dataElement.getType() );
             return;
         }
-        
+
         valid = ValidationUtils.commentIsValid( comment );
-        
+
         if ( valid != null )
         {
             ContextUtils.conflictResponse( response, "Invalid comment: " + comment );
             return;
         }
+
+        // ---------------------------------------------------------------------
+        // Locking validation
+        // ---------------------------------------------------------------------
+
+        if ( dataSetService.isLocked( dataElement, period, organisationUnit, null ) )
+        {
+            ContextUtils.conflictResponse( response, "Data set is locked" );
+            return;
+        }
+
+        // ---------------------------------------------------------------------
+        // Assemble and save data value
+        // ---------------------------------------------------------------------
         
         String storedBy = currentUserService.getCurrentUsername();
 
         Date now = new Date();
 
-        DataValue dataValue = dataValueService.getDataValue( dataElement, period, organisationUnit, categoryOptionCombo );
-        
+        DataValue dataValue = dataValueService.getDataValue( dataElement, period, organisationUnit, categoryOptionCombo, attributeOptionCombo );
+
         if ( dataValue == null )
         {
-            dataValue = new DataValue( dataElement, period, organisationUnit, categoryOptionCombo, null, null, storedBy, now, null );
-            
+            dataValue = new DataValue( dataElement, period, organisationUnit, categoryOptionCombo, attributeOptionCombo, 
+                null, storedBy, now, null );
+
             if ( value != null )
             {
                 dataValue.setValue( StringUtils.trimToNull( value ) );
             }
-            
+
             if ( comment != null )
             {
                 dataValue.setComment( StringUtils.trimToNull( comment ) );
             }
-            
+
             dataValueService.addDataValue( dataValue );
         }
         else
@@ -179,17 +273,17 @@
             {
                 dataValue.setValue( StringUtils.trimToNull( value ) );
             }
-            
+
             if ( comment != null )
             {
                 dataValue.setComment( StringUtils.trimToNull( comment ) );
             }
-            
+
             if ( followUp )
             {
                 dataValue.toggleFollowUp();
             }
-            
+
             dataValue.setTimestamp( now );
             dataValue.setStoredBy( storedBy );