← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 7390: fixes to importer, correctly handles updates for attributeValues (expressions etc remaining)

 

------------------------------------------------------------
revno: 7390
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2012-06-25 23:14:42 +0300
message:
  fixes to importer, correctly handles updates for attributeValues (expressions etc remaining)
removed:
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/FieldHandler.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionalUtils.java
added:
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/HandlerUtils.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionUtils.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeValue.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultObjectBridge.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/utils/JacksonUtils.java
  dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-integration/src/main/java/org/hisp/dhis/integration/components/Dxf2MetaDataEndpoint.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/MetaDataController.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/attribute/AttributeValue.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeValue.java	2012-03-27 17:38:48 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeValue.java	2012-06-25 20:14:42 +0000
@@ -68,6 +68,40 @@
         this.value = value;
     }
 
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o ) return true;
+        if ( o == null || getClass() != o.getClass() ) return false;
+
+        AttributeValue that = (AttributeValue) o;
+
+        if ( id != that.id ) return false;
+        if ( attribute != null ? !attribute.equals( that.attribute ) : that.attribute != null ) return false;
+        if ( value != null ? !value.equals( that.value ) : that.value != null ) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = id;
+        result = 31 * result + (attribute != null ? attribute.hashCode() : 0);
+        result = 31 * result + (value != null ? value.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "AttributeValue{" +
+            "id=" + id +
+            ", attribute=" + attribute +
+            ", value='" + value + '\'' +
+            '}';
+    }
+
     @JsonIgnore
     public int getId()
     {

=== 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	2012-05-21 09:25:15 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementOperand.java	2012-06-25 20:14:42 +0000
@@ -461,80 +461,67 @@
     // -------------------------------------------------------------------------
 
     @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o ) return true;
+        if ( o == null || getClass() != o.getClass() ) return false;
+
+        DataElementOperand that = (DataElementOperand) o;
+
+        if ( dataElementId != that.dataElementId ) return false;
+        if ( frequencyOrder != that.frequencyOrder ) return false;
+        if ( id != that.id ) return false;
+        if ( optionComboId != that.optionComboId ) return false;
+        if ( aggregationLevels != null ? !aggregationLevels.equals( that.aggregationLevels ) : that.aggregationLevels != null )
+            return false;
+        if ( aggregationOperator != null ? !aggregationOperator.equals( that.aggregationOperator ) : that.aggregationOperator != null )
+            return false;
+        if ( categoryOptionCombo != null ? !categoryOptionCombo.equals( that.categoryOptionCombo ) : that.categoryOptionCombo != null )
+            return false;
+        if ( dataElement != null ? !dataElement.equals( that.dataElement ) : that.dataElement != null ) return false;
+        if ( operandId != null ? !operandId.equals( that.operandId ) : that.operandId != null ) return false;
+        if ( operandName != null ? !operandName.equals( that.operandName ) : that.operandName != null ) return false;
+        if ( operandType != null ? !operandType.equals( that.operandType ) : that.operandType != null ) return false;
+        if ( valueType != null ? !valueType.equals( that.valueType ) : that.valueType != null ) return false;
+
+        return true;
+    }
+
+    @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;
-
+        int result = id;
+        result = 31 * result + (dataElement != null ? dataElement.hashCode() : 0);
+        result = 31 * result + (categoryOptionCombo != null ? categoryOptionCombo.hashCode() : 0);
+        result = 31 * result + dataElementId;
+        result = 31 * result + optionComboId;
+        result = 31 * result + (operandId != null ? operandId.hashCode() : 0);
+        result = 31 * result + (operandName != null ? operandName.hashCode() : 0);
+        result = 31 * result + (valueType != null ? valueType.hashCode() : 0);
+        result = 31 * result + (aggregationOperator != null ? aggregationOperator.hashCode() : 0);
+        result = 31 * result + (aggregationLevels != null ? aggregationLevels.hashCode() : 0);
+        result = 31 * result + frequencyOrder;
+        result = 31 * result + (operandType != null ? operandType.hashCode() : 0);
         return result;
     }
 
     @Override
-    public boolean equals( Object object )
-    {
-        if ( this == object )
-        {
-            return true;
-        }
-
-        if ( object == null )
-        {
-            return false;
-        }
-
-        if ( getClass() != object.getClass() )
-        {
-            return false;
-        }
-
-        final DataElementOperand other = (DataElementOperand) object;
-
-        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;
-    }
-
-    @Override
     public String toString()
     {
-        return "[DataElementId: " + dataElementId + ", CategoryOptionComboId: " + optionComboId + "]";
+        return "DataElementOperand{" +
+            "id=" + id +
+            ", dataElement=" + dataElement +
+            ", categoryOptionCombo=" + categoryOptionCombo +
+            ", dataElementId=" + dataElementId +
+            ", optionComboId=" + optionComboId +
+            ", operandId='" + operandId + '\'' +
+            ", operandName='" + operandName + '\'' +
+            ", valueType='" + valueType + '\'' +
+            ", aggregationOperator='" + aggregationOperator + '\'' +
+            ", aggregationLevels=" + aggregationLevels +
+            ", frequencyOrder=" + frequencyOrder +
+            ", operandType='" + operandType + '\'' +
+            '}';
     }
 
     public int compareTo( DataElementOperand other )

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java	2012-05-22 16:20:33 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/Expression.java	2012-06-25 20:14:42 +0000
@@ -136,64 +136,46 @@
     // -------------------------------------------------------------------------
 
     @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o ) return true;
+        if ( o == null || getClass() != o.getClass() ) return false;
+
+        Expression that = (Expression) o;
+
+        if ( id != that.id ) return false;
+        if ( dataElementsInExpression != null ? !dataElementsInExpression.equals( that.dataElementsInExpression ) : that.dataElementsInExpression != null )
+            return false;
+        if ( description != null ? !description.equals( that.description ) : that.description != null ) return false;
+        if ( expression != null ? !expression.equals( that.expression ) : that.expression != null ) return false;
+        if ( optionCombosInExpression != null ? !optionCombosInExpression.equals( that.optionCombosInExpression ) : that.optionCombosInExpression != null )
+            return false;
+
+        return true;
+    }
+
+    @Override
     public int hashCode()
     {
-        final int PRIME = 31;
-
-        int result = 1;
-
-        result = PRIME * result + ((description == null) ? 0 : description.hashCode());
-
-        result = PRIME * result + ((expression == null) ? 0 : expression.hashCode());
+        int result = id;
+        result = 31 * result + (expression != null ? expression.hashCode() : 0);
+        result = 31 * result + (description != null ? description.hashCode() : 0);
+        result = 31 * result + (dataElementsInExpression != null ? dataElementsInExpression.hashCode() : 0);
+        result = 31 * result + (optionCombosInExpression != null ? optionCombosInExpression.hashCode() : 0);
 
         return result;
     }
 
     @Override
-    public boolean equals( Object obj )
+    public String toString()
     {
-        if ( this == obj )
-        {
-            return true;
-        }
-
-        if ( obj == null )
-        {
-            return false;
-        }
-
-        if ( getClass() != obj.getClass() )
-        {
-            return false;
-        }
-
-        final Expression other = (Expression) obj;
-
-        if ( description == null )
-        {
-            if ( other.description != null )
-            {
-                return false;
-            }
-        }
-        else if ( !description.equals( other.description ) )
-        {
-            return false;
-        }
-
-        if ( expression == null )
-        {
-            if ( other.expression != null )
-            {
-                return false;
-            }
-        }
-        else if ( !expression.equals( other.expression ) )
-        {
-            return false;
-        }
-
-        return true;
+        return "Expression{" +
+            "id=" + id +
+            ", expression='" + expression + '\'' +
+            ", description='" + description + '\'' +
+            ", dataElementsInExpression=" + dataElementsInExpression.size() +
+            ", optionCombosInExpression=" + optionCombosInExpression.size() +
+            '}';
     }
 
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultObjectBridge.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultObjectBridge.java	2012-05-28 21:23:50 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/DefaultObjectBridge.java	2012-06-25 20:14:42 +0000
@@ -27,23 +27,18 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.common.IdentifiableObjectManager;
 import org.hisp.dhis.common.NameableObject;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.period.PeriodStore;
 import org.hisp.dhis.period.PeriodType;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.*;
+
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
@@ -66,6 +61,10 @@
     // Internal and Semi-Public maps
     //-------------------------------------------------------------------------------------------------------
 
+    private static final List<Class<?>> registeredTypes = new ArrayList<Class<?>>();
+
+    private static final List<Class<?>> shortNameNotUnique = new ArrayList<Class<?>>();
+
     private Map<Class<?>, Collection<?>> masterMap;
 
     private Map<String, PeriodType> periodTypeMap;
@@ -78,8 +77,6 @@
 
     private Map<Class<? extends NameableObject>, Map<String, NameableObject>> shortNameMap;
 
-    private static final List<Class<?>> registeredTypes = new ArrayList<Class<?>>();
-
     private boolean writeEnabled = true;
 
     //-------------------------------------------------------------------------------------------------------
@@ -94,6 +91,8 @@
         {
             registeredTypes.add( clazz );
         }
+
+        shortNameNotUnique.add( OrganisationUnit.class );
     }
 
     @Override
@@ -369,7 +368,7 @@
         {
             NameableObject nameableObject = (NameableObject) object;
 
-            if ( nameableObject.getShortName() != null )
+            if ( _shortNameUnique( object ) && nameableObject.getShortName() != null )
             {
                 IdentifiableObject match = getShortNameMatch( nameableObject );
 
@@ -409,7 +408,7 @@
                 if ( map == null )
                 {
                     // might be dynamically sub-classed by javassist or cglib, fetch superclass and try again
-                    map = uidMap.get( identifiableObject.getClass().getSuperclass() );
+                    map = codeMap.get( identifiableObject.getClass().getSuperclass() );
                 }
 
                 map.put( identifiableObject.getCode(), identifiableObject );
@@ -417,12 +416,12 @@
 
             if ( identifiableObject.getName() != null )
             {
-                Map<String, IdentifiableObject> map = uidMap.get( identifiableObject.getClass() );
+                Map<String, IdentifiableObject> map = nameMap.get( identifiableObject.getClass() );
 
                 if ( map == null )
                 {
                     // might be dynamically sub-classed by javassist or cglib, fetch superclass and try again
-                    map = uidMap.get( identifiableObject.getClass().getSuperclass() );
+                    map = nameMap.get( identifiableObject.getClass().getSuperclass() );
                 }
 
                 map.put( identifiableObject.getName(), identifiableObject );
@@ -433,7 +432,7 @@
         {
             NameableObject nameableObject = (NameableObject) object;
 
-            if ( nameableObject.getShortName() != null )
+            if ( _shortNameUnique( object ) && nameableObject.getShortName() != null )
             {
                 Map<String, NameableObject> map = shortNameMap.get( nameableObject.getClass() );
 
@@ -508,4 +507,17 @@
 
         return false;
     }
+
+    private <T> boolean _shortNameUnique( T object )
+    {
+        for ( Class clazz : shortNameNotUnique )
+        {
+            if ( clazz.isAssignableFrom( object.getClass() ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }

=== removed file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/FieldHandler.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/FieldHandler.java	2012-05-23 18:35:22 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/FieldHandler.java	1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
-package org.hisp.dhis.dxf2.metadata.handlers;
-
-/*
- * Copyright (c) 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 java.lang.reflect.Field;
-
-/**
- * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
- */
-public interface FieldHandler
-{
-    boolean canHandle( Field field );
-}

=== added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/HandlerUtils.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/HandlerUtils.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/handlers/HandlerUtils.java	2012-06-25 20:14:42 +0000
@@ -0,0 +1,64 @@
+package org.hisp.dhis.dxf2.metadata.handlers;
+
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class HandlerUtils
+{
+    @SuppressWarnings( "unchecked" )
+    public static <T> void preObjectHandlers( T object, List<ObjectHandler> objectHandlers )
+    {
+        for ( ObjectHandler objectHandler : objectHandlers )
+        {
+            if ( objectHandler.canHandle( object.getClass() ) )
+            {
+                objectHandler.preImportObject( object );
+            }
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public static <T> void postObjectHandlers( T object, List<ObjectHandler> objectHandlers )
+    {
+        for ( ObjectHandler objectHandler : objectHandlers )
+        {
+            if ( objectHandler.canHandle( object.getClass() ) )
+            {
+                objectHandler.postImportObject( object );
+            }
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public static <T> void preObjectsHandlers( List<T> objects, List<ObjectHandler> objectHandlers )
+    {
+        if ( objects.size() > 0 )
+        {
+            for ( ObjectHandler objectHandler : objectHandlers )
+            {
+                if ( objectHandler.canHandle( objects.get( 0 ).getClass() ) )
+                {
+                    objectHandler.preImportObjects( objects );
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public static <T> void postObjectsHandlers( List<T> objects, List<ObjectHandler> objectHandlers )
+    {
+        if ( objects.size() > 0 )
+        {
+            for ( ObjectHandler objectHandler : objectHandlers )
+            {
+                if ( objectHandler.canHandle( objects.get( 0 ).getClass() ) )
+                {
+                    objectHandler.postImportObjects( objects );
+                }
+            }
+        }
+    }
+
+}

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2012-06-23 15:51:43 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/importers/DefaultIdentifiableObjectImporter.java	2012-06-25 20:14:42 +0000
@@ -40,7 +40,7 @@
 import org.hisp.dhis.dataelement.DataElementOperandService;
 import org.hisp.dhis.dxf2.importsummary.ImportConflict;
 import org.hisp.dhis.dxf2.metadata.*;
-import org.hisp.dhis.dxf2.metadata.handlers.FieldHandler;
+import org.hisp.dhis.dxf2.metadata.handlers.HandlerUtils;
 import org.hisp.dhis.dxf2.metadata.handlers.ObjectHandler;
 import org.hisp.dhis.expression.Expression;
 import org.hisp.dhis.expression.ExpressionService;
@@ -48,7 +48,7 @@
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.period.PeriodType;
-import org.hisp.dhis.system.util.FunctionalUtils;
+import org.hisp.dhis.system.util.FunctionUtils;
 import org.hisp.dhis.system.util.ReflectionUtils;
 import org.hisp.dhis.system.util.functional.Function1;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -94,9 +94,6 @@
     @Autowired( required = false )
     private List<ObjectHandler> objectHandlers;
 
-    @Autowired( required = false )
-    private List<FieldHandler> fieldHandlers;
-
     //-------------------------------------------------------------------------------------------------------
     // Constructor
     //-------------------------------------------------------------------------------------------------------
@@ -116,6 +113,202 @@
 
     protected ImportOptions options;
 
+    // keeping this internal for now, might be split into several classes
+    private class NonIdentifiableObjects
+    {
+        private Set<AttributeValue> attributeValues = new HashSet<AttributeValue>();
+        // private Set<DataElementOperand> compulsoryDataElementOperands = new HashSet<DataElementOperand>();
+        private Set<DataElementOperand> greyedFields = new HashSet<DataElementOperand>();
+        private Expression leftSide;
+        private Expression rightSide;
+
+        public void extract( T object )
+        {
+            attributeValues = extractAttributeValues( object );
+            // compulsoryDataElementOperands = extractDataElementOperands( object, "compulsoryDataElementOperands" );
+            greyedFields = extractDataElementOperands( object, "greyedFields" );
+            leftSide = extractExpression( object, "leftSide" );
+            rightSide = extractExpression( object, "rightSide" );
+        }
+
+        public void delete( T object )
+        {
+            if ( !options.isDryRun() )
+            {
+                deleteAttributeValues( object );
+                // deleteDataElementOperands( compulsoryDataElementOperands );
+                // deleteDataElementOperands( object, "greyedFields" );
+                // deleteExpression( object, "leftSide" );
+                // deleteExpression( object, "rightSide" );
+            }
+        }
+
+        public void save( T object )
+        {
+            saveAttributeValues( object, attributeValues );
+            saveExpression( object, "leftSide", leftSide );
+            saveExpression( object, "rightSide", rightSide );
+            // newDataElementOperands( object, "compulsoryDataElementOperands", compulsoryDataElementOperands );
+            saveDataElementOperands( object, "greyedFields", greyedFields );
+        }
+
+        private Expression extractExpression( T object, String fieldName )
+        {
+            Expression expression = null;
+
+            if ( ReflectionUtils.findGetterMethod( fieldName, object ) != null )
+            {
+                expression = ReflectionUtils.invokeGetterMethod( fieldName, object );
+
+                if ( expression != null )
+                {
+                    ReflectionUtils.invokeSetterMethod( fieldName, object, new Object[] { null } );
+                }
+            }
+
+            return expression;
+        }
+
+        private Set<DataElementOperand> extractDataElementOperands( T object, String fieldName )
+        {
+            Set<DataElementOperand> dataElementOperands = new HashSet<DataElementOperand>();
+
+            if ( ReflectionUtils.findGetterMethod( fieldName, object ) != null )
+            {
+                Set<DataElementOperand> detachedDataElementOperands = ReflectionUtils.invokeGetterMethod( fieldName, object );
+                dataElementOperands = new HashSet<DataElementOperand>( detachedDataElementOperands );
+
+                if ( detachedDataElementOperands.size() > 0 )
+                {
+                    detachedDataElementOperands.clear();
+                    ReflectionUtils.invokeSetterMethod( fieldName, object, new HashSet<DataElementOperand>() );
+                }
+            }
+
+            return dataElementOperands;
+        }
+
+        private Set<AttributeValue> extractAttributeValues( T object )
+        {
+            Set<AttributeValue> attributeValues = new HashSet<AttributeValue>();
+
+            if ( ReflectionUtils.findGetterMethod( "attributeValues", object ) != null )
+            {
+                attributeValues = ReflectionUtils.invokeGetterMethod( "attributeValues", object );
+
+                if ( attributeValues.size() > 0 )
+                {
+                    ReflectionUtils.invokeSetterMethod( "attributeValues", object, new HashSet<AttributeValue>() );
+                }
+            }
+
+            return attributeValues;
+        }
+
+        private void saveExpression( T object, String fieldName, Expression expression )
+        {
+            if ( expression != null )
+            {
+                Map<Field, Collection<Object>> identifiableObjectCollections = detachCollectionFields( expression );
+                reattachCollectionFields( expression, identifiableObjectCollections );
+
+                expression.setId( 0 );
+                expressionService.addExpression( expression );
+
+                ReflectionUtils.invokeSetterMethod( fieldName, object, expression );
+            }
+        }
+
+        private void saveDataElementOperands( T object, String field, Set<DataElementOperand> dataElementOperands )
+        {
+            if ( dataElementOperands.size() > 0 )
+            {
+                for ( DataElementOperand dataElementOperand : dataElementOperands )
+                {
+                    Map<Field, Object> identifiableObjects = detachFields( dataElementOperand );
+                    reattachFields( dataElementOperand, identifiableObjects );
+
+                    dataElementOperand.setId( 0 );
+                    dataElementOperandService.addDataElementOperand( dataElementOperand );
+                }
+
+                ReflectionUtils.invokeSetterMethod( field, object, dataElementOperands );
+            }
+        }
+
+        private void saveAttributeValues( T object, Set<AttributeValue> attributeValues )
+        {
+            if ( attributeValues.size() > 0 )
+            {
+                FunctionUtils.forEach( attributeValues, new Function1<AttributeValue>()
+                {
+                    @Override
+                    public void apply( AttributeValue attributeValue )
+                    {
+                        Attribute attribute = objectBridge.getObject( attributeValue.getAttribute() );
+
+                        if ( attribute == null )
+                        {
+                            log.warn( "Unknown reference to " + attributeValue.getAttribute() + " on object " + attributeValue );
+                            return;
+                        }
+
+                        attributeValue.setId( 0 );
+                        attributeValue.setAttribute( attribute );
+                    }
+                } );
+
+                for ( AttributeValue attributeValue : attributeValues )
+                {
+                    attributeService.addAttributeValue( attributeValue );
+                }
+
+                ReflectionUtils.invokeSetterMethod( "attributeValues", object, attributeValues );
+            }
+        }
+
+        private void deleteExpression( T object, String fieldName )
+        {
+            Expression expression = extractExpression( object, fieldName );
+
+            if ( expression != null )
+            {
+                expressionService.deleteExpression( expression );
+            }
+        }
+
+        private void deleteDataElementOperands( T object, String fieldName )
+        {
+            Set<DataElementOperand> dataElementOperands = extractDataElementOperands( object, fieldName );
+
+            FunctionUtils.forEach( dataElementOperands, new Function1<DataElementOperand>()
+            {
+                @Override
+                public void apply( DataElementOperand dataElementOperand )
+                {
+                    dataElementOperandService.deleteDataElementOperand( dataElementOperand );
+                }
+            } );
+        }
+
+        private void deleteAttributeValues( T object )
+        {
+            if ( !Attribute.class.isAssignableFrom( object.getClass() ) )
+            {
+                Set<AttributeValue> attributeValues = extractAttributeValues( object );
+
+                FunctionUtils.forEach( attributeValues, new Function1<AttributeValue>()
+                {
+                    @Override
+                    public void apply( AttributeValue attributeValue )
+                    {
+                        attributeService.deleteAttributeValue( attributeValue );
+                    }
+                } );
+            }
+        }
+    }
+
     //-------------------------------------------------------------------------------------------------------
     // Generic implementations of newObject and updatedObject
     //-------------------------------------------------------------------------------------------------------
@@ -131,16 +324,15 @@
         // make sure that the internalId is 0, so that the system will generate a ID
         object.setId( 0 );
 
-        // FIXME add uidValidator.. part of bean validation impl?
-        // object.setUid( CodeGenerator.generateCode() );
+        NonIdentifiableObjects nonIdentifiableObjects = new NonIdentifiableObjects();
+        nonIdentifiableObjects.extract( object );
+
+        Map<Field, Object> fields = detachFields( object );
+        Map<Field, Collection<Object>> collectionFields = detachCollectionFields( object );
+
+        reattachFields( object, fields );
 
         log.debug( "Trying to save new object => " + ImportUtils.getDisplayName( object ) + " (" + object.getClass().getSimpleName() + ")" );
-
-        Map<Field, Object> fields = detachFields( object );
-        reattachFields( object, fields );
-
-        Map<Field, Collection<Object>> collectionFields = detachCollectionFields( object );
-
         objectBridge.saveObject( object );
 
         updatePeriodTypes( object );
@@ -148,6 +340,13 @@
 
         objectBridge.updateObject( object );
 
+        if ( !options.isDryRun() )
+        {
+            sessionFactory.getCurrentSession().flush();
+            nonIdentifiableObjects.save( object );
+            sessionFactory.getCurrentSession().flush();
+        }
+
         log.debug( "Save successful." );
 
         return true;
@@ -156,33 +355,42 @@
     /**
      * Update object from old => new.
      *
-     * @param object    Object to import
-     * @param oldObject The current version of the object
+     * @param object          Object to import
+     * @param persistedObject The current version of the object
      * @return An ImportConflict instance if there was a conflict, otherwise null
      */
-    protected boolean updateObject( T object, T oldObject )
+    protected boolean updateObject( T object, T persistedObject )
     {
-        log.debug( "Starting update of object " + ImportUtils.getDisplayName( oldObject ) + " (" + oldObject.getClass()
+        NonIdentifiableObjects nonIdentifiableObjects = new NonIdentifiableObjects();
+        nonIdentifiableObjects.extract( object );
+        nonIdentifiableObjects.delete( persistedObject );
+
+        Map<Field, Object> fields = detachFields( object );
+        Map<Field, Collection<Object>> collectionFields = detachCollectionFields( object );
+
+        persistedObject.mergeWith( object );
+        updatePeriodTypes( persistedObject );
+
+        reattachFields( persistedObject, fields );
+        reattachCollectionFields( persistedObject, collectionFields );
+
+        log.debug( "Starting update of object " + ImportUtils.getDisplayName( persistedObject ) + " (" + persistedObject.getClass()
             .getSimpleName() + ")" );
 
-        Map<Field, Object> fields = detachFields( object );
-        reattachFields( object, fields );
-
-        Map<Field, Collection<Object>> collectionFields = detachCollectionFields( object );
-
-        oldObject.mergeWith( object );
-        updatePeriodTypes( oldObject );
-
-        reattachCollectionFields( oldObject, collectionFields );
-
-        objectBridge.updateObject( oldObject );
+        objectBridge.updateObject( persistedObject );
+
+        if ( !options.isDryRun() )
+        {
+            sessionFactory.getCurrentSession().flush();
+            nonIdentifiableObjects.save( persistedObject );
+            sessionFactory.getCurrentSession().flush();
+        }
 
         log.debug( "Update successful." );
 
         return true;
     }
 
-    // FIXME to static ATM, should be refactor out.. "type handler", not idObject
     private void updatePeriodTypes( T object )
     {
         for ( Field field : object.getClass().getDeclaredFields() )
@@ -212,213 +420,22 @@
             return summaryType;
         }
 
-        preObjectsHandlers( objects );
+        HandlerUtils.preObjectsHandlers( objects, objectHandlers );
 
         for ( T object : objects )
         {
-            preObjectHandlers( object );
-
-            // FIXME add to scanner, and use field handlers for this
-            Set<AttributeValue> attributeValues = getAndClearAttributeValues( object );
-            Set<DataElementOperand> compulsoryDataElementOperands = getAndClearDataElementOperands( object, "compulsoryDataElementOperands" );
-            Set<DataElementOperand> greyedFields = getAndClearDataElementOperands( object, "greyedFields" );
-            Expression leftSide = getAndClearExpression( object, "leftSide" );
-            Expression rightSide = getAndClearExpression( object, "rightSide" );
+            HandlerUtils.preObjectHandlers( object, objectHandlers );
 
             importObjectLocal( object );
 
-            if ( !options.isDryRun() )
-            {
-                sessionFactory.getCurrentSession().flush();
-
-                newAttributeValues( object, attributeValues );
-                newExpression( object, "leftSide", leftSide );
-                newExpression( object, "rightSide", rightSide );
-                // newDataElementOperands( object, "compulsoryDataElementOperands", compulsoryDataElementOperands );
-                newDataElementOperands( object, "greyedFields", greyedFields );
-
-                sessionFactory.getCurrentSession().flush();
-            }
-
-            postObjectHandlers( object );
+            HandlerUtils.postObjectHandlers( object, objectHandlers );
         }
 
-        postObjectsHandlers( objects );
+        HandlerUtils.postObjectsHandlers( objects, objectHandlers );
 
         return summaryType;
     }
 
-
-    @SuppressWarnings( "unchecked" )
-    private void preObjectHandlers( T object )
-    {
-        for ( ObjectHandler objectHandler : objectHandlers )
-        {
-            if ( objectHandler.canHandle( object.getClass() ) )
-            {
-                objectHandler.preImportObject( object );
-            }
-        }
-    }
-
-    @SuppressWarnings( "unchecked" )
-    private void postObjectHandlers( T object )
-    {
-        for ( ObjectHandler objectHandler : objectHandlers )
-        {
-            if ( objectHandler.canHandle( object.getClass() ) )
-            {
-                objectHandler.postImportObject( object );
-            }
-        }
-    }
-
-    @SuppressWarnings( "unchecked" )
-    private void preObjectsHandlers( List<T> objects )
-    {
-        if ( objects.size() > 0 )
-        {
-            for ( ObjectHandler objectHandler : objectHandlers )
-            {
-                if ( objectHandler.canHandle( objects.get( 0 ).getClass() ) )
-                {
-                    objectHandler.preImportObjects( objects );
-                }
-            }
-        }
-    }
-
-    @SuppressWarnings( "unchecked" )
-    private void postObjectsHandlers( List<T> objects )
-    {
-        if ( objects.size() > 0 )
-        {
-            for ( ObjectHandler objectHandler : objectHandlers )
-            {
-                if ( objectHandler.canHandle( objects.get( 0 ).getClass() ) )
-                {
-                    objectHandler.postImportObjects( objects );
-                }
-            }
-        }
-    }
-
-    // FIXME add type check
-    private Expression getAndClearExpression( T object, String fieldName )
-    {
-        Expression expression = null;
-
-        if ( ReflectionUtils.findGetterMethod( fieldName, object ) != null )
-        {
-            expression = ReflectionUtils.invokeGetterMethod( fieldName, object );
-
-            if ( expression != null )
-            {
-                ReflectionUtils.invokeSetterMethod( fieldName, object, new Object[] { null } );
-            }
-        }
-
-        return expression;
-    }
-
-    // FIXME add type check
-    private Set<DataElementOperand> getAndClearDataElementOperands( T object, String fieldName )
-    {
-        Set<DataElementOperand> dataElementOperands = new HashSet<DataElementOperand>();
-
-        if ( ReflectionUtils.findGetterMethod( fieldName, object ) != null )
-        {
-            Set<DataElementOperand> detachedDataElementOperands = ReflectionUtils.invokeGetterMethod( fieldName, object );
-            dataElementOperands = new HashSet<DataElementOperand>( detachedDataElementOperands );
-
-            if ( detachedDataElementOperands.size() > 0 )
-            {
-                detachedDataElementOperands.clear();
-                ReflectionUtils.invokeSetterMethod( fieldName, object, new HashSet<DataElementOperand>() );
-            }
-        }
-
-        return dataElementOperands;
-    }
-
-    // FIXME add type check
-    private Set<AttributeValue> getAndClearAttributeValues( T object )
-    {
-        Set<AttributeValue> attributeValues = new HashSet<AttributeValue>();
-
-        if ( ReflectionUtils.findGetterMethod( "attributeValues", object ) != null )
-        {
-            attributeValues = ReflectionUtils.invokeGetterMethod( "attributeValues", object );
-
-            if ( attributeValues.size() > 0 )
-            {
-                ReflectionUtils.invokeSetterMethod( "attributeValues", object, new HashSet<AttributeValue>() );
-            }
-        }
-
-        return attributeValues;
-    }
-
-    private void newExpression( T object, String field, Expression expression )
-    {
-        if ( expression != null )
-        {
-            Map<Field, Collection<Object>> identifiableObjectCollections = detachCollectionFields( expression );
-            reattachCollectionFields( expression, identifiableObjectCollections );
-
-            expression.setId( 0 );
-            expressionService.addExpression( expression );
-
-            sessionFactory.getCurrentSession().flush();
-
-            ReflectionUtils.invokeSetterMethod( field, object, expression );
-        }
-    }
-
-    private void newDataElementOperands( T object, String field, Set<DataElementOperand> dataElementOperands )
-    {
-        if ( dataElementOperands.size() > 0 )
-        {
-            for ( DataElementOperand dataElementOperand : dataElementOperands )
-            {
-                Map<Field, Object> identifiableObjects = detachFields( dataElementOperand );
-                reattachFields( dataElementOperand, identifiableObjects );
-
-                dataElementOperand.setId( 0 );
-                dataElementOperandService.addDataElementOperand( dataElementOperand );
-            }
-
-            ReflectionUtils.invokeSetterMethod( field, object, dataElementOperands );
-        }
-    }
-
-    private void newAttributeValues( T object, Set<AttributeValue> attributeValues )
-    {
-        if ( attributeValues.size() > 0 )
-        {
-            for ( AttributeValue attributeValue : attributeValues )
-            {
-                Attribute attribute = objectBridge.getObject( attributeValue.getAttribute() );
-
-                if ( attribute == null )
-                {
-                    log.warn( "Unknown reference to " + attributeValue.getAttribute() + " on object " + attributeValue );
-                    continue;
-                }
-
-                attributeValue.setId( 0 );
-                attributeValue.setAttribute( attribute );
-            }
-
-            for ( AttributeValue attributeValue : attributeValues )
-            {
-                attributeService.addAttributeValue( attributeValue );
-            }
-
-            ReflectionUtils.invokeSetterMethod( "attributeValues", object, attributeValues );
-        }
-    }
-
     @Override
     public ImportTypeSummary importObject( T object, ImportOptions options )
     {
@@ -455,7 +472,6 @@
     private void startImport( T object )
     {
         T oldObject = objectBridge.getObject( object );
-        List<ImportConflict> importConflicts = new ArrayList<ImportConflict>();
 
         if ( ImportStrategy.NEW.equals( options.getImportStrategy() ) )
         {
@@ -495,7 +511,6 @@
         ImportConflict conflict = null;
         boolean success = true;
 
-        // FIXME add bean validation for this
         if ( object.getName() == null || object.getName().length() == 0 )
         {
             conflict = new ImportConflict( ImportUtils.getDisplayName( object ), "Empty name for object " + object );
@@ -566,7 +581,7 @@
 
     private boolean validateForNewStrategy( T object )
     {
-        ImportConflict conflict = null;
+        ImportConflict conflict;
         Collection<T> objects = objectBridge.getObjects( object );
 
         if ( objects.size() > 0 )
@@ -586,7 +601,6 @@
         {
             return null;
         }
-        // FIXME this is a bit too static ATM, should be refactored out into its own "type handler"
         else if ( Period.class.isAssignableFrom( identifiableObject.getClass() ) )
         {
             Period period = (Period) identifiableObject;
@@ -608,7 +622,7 @@
         final Map<Field, Object> fieldMap = new HashMap<Field, Object>();
         final Collection<Field> fieldCollection = ReflectionUtils.collectFields( object.getClass(), idObjects );
 
-        FunctionalUtils.forEach( fieldCollection, new Function1<Field>()
+        FunctionUtils.forEach( fieldCollection, new Function1<Field>()
         {
             @Override
             public void apply( Field field )
@@ -653,7 +667,7 @@
         final Map<Field, Collection<Object>> collectionFields = new HashMap<Field, Collection<Object>>();
         final Collection<Field> fieldCollection = ReflectionUtils.collectFields( object.getClass(), idObjectCollectionsWithScanned );
 
-        FunctionalUtils.forEach( fieldCollection, new Function1<Field>()
+        FunctionUtils.forEach( fieldCollection, new Function1<Field>()
         {
             @Override
             public void apply( Field field )
@@ -672,29 +686,33 @@
         return collectionFields;
     }
 
-    private void reattachCollectionFields( Object object, Map<Field, Collection<Object>> collectionFields )
+    private void reattachCollectionFields( final Object object, Map<Field, Collection<Object>> collectionFields )
     {
         for ( Field field : collectionFields.keySet() )
         {
             Collection<Object> collection = collectionFields.get( field );
-            Collection<Object> objects = ReflectionUtils.newCollectionInstance( field.getType() );
+            final Collection<Object> objects = ReflectionUtils.newCollectionInstance( field.getType() );
 
-            for ( Object idObject : collection )
+            FunctionUtils.forEach( collection, new Function1<Object>()
             {
-                IdentifiableObject ref = findObjectByReference( (IdentifiableObject) idObject );
+                @Override
+                public void apply( Object object )
+                {
+                    IdentifiableObject ref = findObjectByReference( (IdentifiableObject) object );
 
-                if ( ref != null )
-                {
-                    objects.add( ref );
-                }
-                else
-                {
-                    if ( ExchangeClasses.getImportMap().get( idObject.getClass() ) != null )
-                    {
-                        reportReferenceError( object, idObject );
-                    }
-                }
-            }
+                    if ( ref != null )
+                    {
+                        objects.add( ref );
+                    }
+                    else
+                    {
+                        if ( ExchangeClasses.getImportMap().get( object.getClass() ) != null )
+                        {
+                            reportReferenceError( object, object );
+                        }
+                    }
+                }
+            } );
 
             if ( !options.isDryRun() )
             {

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/utils/JacksonUtils.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/utils/JacksonUtils.java	2012-06-06 12:48:05 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/utils/JacksonUtils.java	2012-06-25 20:14:42 +0000
@@ -61,11 +61,11 @@
     static
     {
         ObjectMapper[] objectMappers = new ObjectMapper[] { jsonMapper, xmlMapper };
-        DateFormat format = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
+        // DateFormat format = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
 
         for ( ObjectMapper objectMapper : objectMappers )
         {
-            objectMapper.setDateFormat( format );
+            // objectMapper.setDateFormat( format );
             objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL );
             objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
             objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false );

=== modified file 'dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml	2012-05-25 21:10:19 +0000
+++ dhis-2/dhis-dxf2/src/main/resources/META-INF/dhis/beans.xml	2012-06-25 20:14:42 +0000
@@ -16,8 +16,12 @@
 
   <!-- register object handlers -->
 
-  <bean id="org.hisp.dhis.dxf2.metadata.handlers.OrganisationUnitObjectHandler"
-      class="org.hisp.dhis.dxf2.metadata.handlers.OrganisationUnitObjectHandler" />
+  <bean id="organisationUnitObjectHandler"
+      class="org.hisp.dhis.dxf2.metadata.handlers.OrganisationUnitObjectHandler" scope="prototype"/>
+
+  <!-- register field handlers -->
+
+
 
   <!-- register importers -->
 

=== modified file 'dhis-2/dhis-services/dhis-service-integration/src/main/java/org/hisp/dhis/integration/components/Dxf2MetaDataEndpoint.java'
--- dhis-2/dhis-services/dhis-service-integration/src/main/java/org/hisp/dhis/integration/components/Dxf2MetaDataEndpoint.java	2012-06-24 13:01:12 +0000
+++ dhis-2/dhis-services/dhis-service-integration/src/main/java/org/hisp/dhis/integration/components/Dxf2MetaDataEndpoint.java	2012-06-25 20:14:42 +0000
@@ -37,10 +37,10 @@
 /**
  * metadataendpoint is created using a uri of the form:
  * dhis2:metadata?dryRun=true|false
- * 
+ *
  * @author bobj
  */
-public class Dxf2MetaDataEndpoint 
+public class Dxf2MetaDataEndpoint
     extends DefaultEndpoint
 {
     protected ImportService importService;
@@ -49,9 +49,9 @@
     {
         return importService;
     }
-    
+
     protected ImportOptions options;
-    
+
     public ImportOptions getImportOptions()
     {
         return this.options;
@@ -60,7 +60,7 @@
     // -------------------------------------------------------------------------
     // Parameters supported by this end point 
     // -------------------------------------------------------------------------
-    
+
     public void setDryRun( Boolean dryRun )
     {
         options.setDryRun( dryRun );
@@ -75,7 +75,7 @@
     {
         super( uri, component );
         this.importService = importService;
-        options= new ImportOptions();
+        options = new ImportOptions();
     }
 
     @Override

=== added file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionUtils.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionUtils.java	2012-06-25 20:14:42 +0000
@@ -0,0 +1,51 @@
+package org.hisp.dhis.system.util;
+
+/*
+ * 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.system.util.functional.Function1;
+
+import java.util.Collection;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class FunctionUtils
+{
+    public static <T> void forEach( Collection<T> collection, Function1<T> function )
+    {
+        for ( T object : collection )
+        {
+            if(object == null)
+            {
+                continue;
+            }
+
+            function.apply( object );
+        }
+    }
+}

=== removed file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionalUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionalUtils.java	2012-06-04 09:29:45 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/FunctionalUtils.java	1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
-package org.hisp.dhis.system.util;
-
-/*
- * 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.system.util.functional.Function1;
-
-import java.util.Collection;
-
-/**
- * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
- */
-public class FunctionalUtils
-{
-    public static <T> void forEach( Collection<T> collection, Function1<T> function )
-    {
-        for ( T object : collection )
-        {
-            function.apply( object );
-        }
-    }
-}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/MetaDataController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/MetaDataController.java	2012-06-22 16:25:04 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/MetaDataController.java	2012-06-25 20:14:42 +0000
@@ -257,7 +257,6 @@
         JacksonUtils.toJson( response.getOutputStream(), summary );
     }
 
-
     @RequestMapping( value = { MetaDataController.RESOURCE_PATH + ".gz", MetaDataController.RESOURCE_PATH + ".xml.gz" }, method = RequestMethod.POST, consumes = { "application/xml", "text/*" } )
     @PreAuthorize( "hasRole('ALL') or hasRole('F_METADATA_IMPORT')" )
     public void importGZippedXml( ImportOptions importOptions, HttpServletResponse response, HttpServletRequest request ) throws JAXBException, IOException