=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/DefaultObjectBundleService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/DefaultObjectBundleService.java 2016-03-12 13:39:37 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/DefaultObjectBundleService.java 2016-03-13 04:20:01 +0000 @@ -97,15 +97,13 @@ @Override public ObjectBundle create( ObjectBundleParams params ) { + PreheatParams preheatParams = params.getPreheatParams(); + if ( params.getUser() == null ) { params.setUser( currentUserService.getCurrentUser() ); } - ObjectBundle bundle = new ObjectBundle( params ); - bundle.addObjects( params.getObjects() ); - - PreheatParams preheatParams = params.getPreheatParams(); preheatParams.setUser( params.getUser() ); if ( PreheatMode.REFERENCE == preheatParams.getPreheatMode() ) @@ -113,16 +111,11 @@ preheatParams.setReferences( preheatService.collectReferences( params.getObjects() ) ); } - bundle.setPreheat( preheatService.preheat( preheatParams ) ); + ObjectBundle bundle = new ObjectBundle( params, preheatService.preheat( preheatParams ), params.getObjects() ); bundle.setObjectReferences( preheatService.collectObjectReferences( params.getObjects() ) ); - if ( !bundle.getImportMode().isCreate() ) - { - return bundle; - } - // add preheat placeholders for objects that will be created - for ( Class klass : bundle.getObjects().keySet() ) + for ( Class klass : bundle.getObjectMap().keySet() ) { Map, Map>> map = bundle.getPreheat().getMap(); @@ -164,77 +157,32 @@ for ( Class klass : klasses ) { + if ( bundle.getImportMode().isCreateAndUpdate() ) + { + objectBundleValidation.addObjectErrorReports( validateBySchemas( klass, bundle.getObjectMap().get( klass ), bundle ) ); + objectBundleValidation.addObjectErrorReports( preheatService.checkReferences( bundle.getObjectMap().get( klass ), + bundle.getPreheat(), bundle.getPreheatIdentifier() ) ); + } + if ( bundle.getImportMode().isCreate() ) { - Iterator iterator = bundle.getObjects().get( klass ).iterator(); - int idx = 0; - - while ( iterator.hasNext() ) - { - IdentifiableObject identifiableObject = iterator.next(); - IdentifiableObject object = bundle.getPreheat().get( bundle.getPreheatIdentifier(), identifiableObject ); - - if ( object != null && object.getId() > 0 ) - { - ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); - objectErrorReport.addErrorReport( new ErrorReport( klass, ErrorCode.E5000, bundle.getPreheatIdentifier(), - bundle.getPreheatIdentifier().getIdentifiersWithName( identifiableObject ) ) ); - objectBundleValidation.addObjectErrorReport( objectErrorReport ); - - iterator.remove(); - } - - idx++; - } - } - else if ( bundle.getImportMode().isUpdate() || bundle.getImportMode().isDelete() ) - { - Iterator iterator = bundle.getObjects().get( klass ).iterator(); - int idx = 0; - - while ( iterator.hasNext() ) - { - IdentifiableObject identifiableObject = iterator.next(); - IdentifiableObject object = bundle.getPreheat().get( bundle.getPreheatIdentifier(), identifiableObject ); - - if ( object == null ) - { - if ( Preheat.isDefaultClass( identifiableObject.getClass() ) ) continue; - - ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); - objectErrorReport.addErrorReport( new ErrorReport( klass, ErrorCode.E5001, bundle.getPreheatIdentifier(), - bundle.getPreheatIdentifier().getIdentifiersWithName( identifiableObject ) ) ); - objectBundleValidation.addObjectErrorReport( objectErrorReport ); - iterator.remove(); - } - - idx++; - } - } - - List objectErrorReports = preheatService.checkReferences( bundle.getObjects().get( klass ), bundle.getPreheat(), bundle.getPreheatIdentifier() ); - objectBundleValidation.addObjectErrorReports( objectErrorReports ); - - if ( !bundle.getImportMode().isDelete() ) - { - Iterator iterator = bundle.getObjects().get( klass ).iterator(); - int idx = 0; - - while ( iterator.hasNext() ) - { - IdentifiableObject object = iterator.next(); - List validationErrorReports = schemaValidator.validate( object ); - ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); - - if ( !validationErrorReports.isEmpty() ) - { - objectErrorReport.addErrorReports( validationErrorReports ); - iterator.remove(); - } - - objectBundleValidation.addObjectErrorReport( objectErrorReport ); - idx++; - } + objectBundleValidation.addObjectErrorReports( validateForCreate( klass, bundle.getObjects( klass, true ), bundle ) ); + objectBundleValidation.addObjectErrorReports( validateBySchemas( klass, bundle.getObjects( klass, false ), bundle ) ); + objectBundleValidation.addObjectErrorReports( preheatService.checkReferences( bundle.getObjectMap().get( klass ), + bundle.getPreheat(), bundle.getPreheatIdentifier() ) ); + } + + if ( bundle.getImportMode().isUpdate() ) + { + objectBundleValidation.addObjectErrorReports( validateForUpdate( klass, bundle.getObjects( klass, false ), bundle ) ); + objectBundleValidation.addObjectErrorReports( validateBySchemas( klass, bundle.getObjects( klass, true ), bundle ) ); + objectBundleValidation.addObjectErrorReports( preheatService.checkReferences( bundle.getObjectMap().get( klass ), + bundle.getPreheat(), bundle.getPreheatIdentifier() ) ); + } + + if ( bundle.getImportMode().isDelete() ) + { + objectBundleValidation.addObjectErrorReports( validateForDelete( klass, bundle.getObjects( klass, false ), bundle ) ); } } @@ -243,6 +191,137 @@ return objectBundleValidation; } + public List validateForCreate( Class klass, List objects, ObjectBundle bundle ) + { + List objectErrorReports = new ArrayList<>(); + + if ( objects == null || objects.isEmpty() ) + { + return objectErrorReports; + } + + Iterator iterator = objects.iterator(); + int idx = 0; + + while ( iterator.hasNext() ) + { + IdentifiableObject identifiableObject = iterator.next(); + IdentifiableObject object = bundle.getPreheat().get( bundle.getPreheatIdentifier(), identifiableObject ); + + if ( object != null && object.getId() > 0 ) + { + ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); + objectErrorReport.addErrorReport( new ErrorReport( klass, ErrorCode.E5000, bundle.getPreheatIdentifier(), + bundle.getPreheatIdentifier().getIdentifiersWithName( identifiableObject ) ) ); + objectErrorReports.add( objectErrorReport ); + iterator.remove(); + } + + idx++; + } + + return objectErrorReports; + } + + public List validateForUpdate( Class klass, List objects, ObjectBundle bundle ) + { + List objectErrorReports = new ArrayList<>(); + + if ( objects == null || objects.isEmpty() ) + { + return objectErrorReports; + } + + Iterator iterator = objects.iterator(); + int idx = 0; + + while ( iterator.hasNext() ) + { + IdentifiableObject identifiableObject = iterator.next(); + IdentifiableObject object = bundle.getPreheat().get( bundle.getPreheatIdentifier(), identifiableObject ); + + if ( object == null || object.getId() == 0 ) + { + if ( Preheat.isDefaultClass( identifiableObject.getClass() ) ) continue; + + ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); + objectErrorReport.addErrorReport( new ErrorReport( klass, ErrorCode.E5001, bundle.getPreheatIdentifier(), + bundle.getPreheatIdentifier().getIdentifiersWithName( identifiableObject ) ) ); + objectErrorReports.add( objectErrorReport ); + iterator.remove(); + } + + idx++; + } + + return objectErrorReports; + } + + public List validateForDelete( Class klass, List objects, ObjectBundle bundle ) + { + List objectErrorReports = new ArrayList<>(); + + if ( objects == null || objects.isEmpty() ) + { + return objectErrorReports; + } + + Iterator iterator = objects.iterator(); + int idx = 0; + + while ( iterator.hasNext() ) + { + IdentifiableObject identifiableObject = iterator.next(); + IdentifiableObject object = bundle.getPreheat().get( bundle.getPreheatIdentifier(), identifiableObject ); + + if ( object == null || object.getId() == 0 ) + { + if ( Preheat.isDefaultClass( identifiableObject.getClass() ) ) continue; + + ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); + objectErrorReport.addErrorReport( new ErrorReport( klass, ErrorCode.E5001, bundle.getPreheatIdentifier(), + bundle.getPreheatIdentifier().getIdentifiersWithName( identifiableObject ) ) ); + objectErrorReports.add( objectErrorReport ); + iterator.remove(); + } + + idx++; + } + + return objectErrorReports; + } + + public List validateBySchemas( Class klass, List objects, ObjectBundle bundle ) + { + List objectErrorReports = new ArrayList<>(); + + if ( objects == null || objects.isEmpty() ) + { + return objectErrorReports; + } + + Iterator iterator = objects.iterator(); + int idx = 0; + + while ( iterator.hasNext() ) + { + IdentifiableObject identifiableObject = iterator.next(); + List validationErrorReports = schemaValidator.validate( identifiableObject ); + + if ( !validationErrorReports.isEmpty() ) + { + ObjectErrorReport objectErrorReport = new ObjectErrorReport( klass, idx ); + objectErrorReport.addErrorReports( validationErrorReports ); + objectErrorReports.add( objectErrorReport ); + iterator.remove(); + } + + idx++; + } + + return objectErrorReports; + } + @Override @SuppressWarnings( "unchecked" ) public void commit( ObjectBundle bundle ) @@ -384,7 +463,7 @@ schemaService.getMetadataSchemas().forEach( schema -> { Class klass = (Class) schema.getKlass(); - if ( bundle.getObjects().containsKey( klass ) ) + if ( bundle.getObjectMap().containsKey( klass ) ) { klasses.add( klass ); } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundle.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundle.java 2016-03-12 13:39:37 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundle.java 2016-03-13 04:20:01 +0000 @@ -39,8 +39,10 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * @author Morten Olav Hansen @@ -61,16 +63,19 @@ private final FlushMode flushMode; + private final Preheat preheat; + private ObjectBundleStatus objectBundleStatus = ObjectBundleStatus.CREATED; - private Preheat preheat = new Preheat(); - - private Map, List> objects = new HashMap<>(); + private Map, List>> objects = new HashMap<>(); private Map, Map>> objectReferences = new HashMap<>(); - public ObjectBundle( ObjectBundleParams params ) + public ObjectBundle( ObjectBundleParams params, Preheat preheat, Map, List> objectMap ) { + if ( !objects.containsKey( Boolean.TRUE ) ) objects.put( Boolean.TRUE, new HashMap<>() ); + if ( !objects.containsKey( Boolean.FALSE ) ) objects.put( Boolean.FALSE, new HashMap<>() ); + this.user = params.getUser(); this.objectBundleMode = params.getObjectBundleMode(); this.preheatIdentifier = params.getPreheatIdentifier(); @@ -78,6 +83,9 @@ this.preheatMode = params.getPreheatMode(); this.mergeMode = params.getMergeMode(); this.flushMode = params.getFlushMode(); + this.preheat = preheat; + + addObject( objectMap ); } public User getUser() @@ -130,70 +138,81 @@ return preheat; } - public void setPreheat( Preheat preheat ) - { - this.preheat = preheat; - } - - @SuppressWarnings( "unchecked" ) - public void addObject( IdentifiableObject object ) + private void addObject( IdentifiableObject object ) { if ( object == null ) { return; } - if ( !objects.containsKey( object.getClass() ) ) - { - objects.put( object.getClass(), new ArrayList<>() ); - } - - objects.get( object.getClass() ).add( object ); - - if ( preheat.get( preheatIdentifier, object ) == null ) - { - preheat.put( preheatIdentifier, object ); + if ( !objects.get( Boolean.TRUE ).containsKey( object.getClass() ) ) + { + objects.get( Boolean.TRUE ).put( object.getClass(), new ArrayList<>() ); + } + + if ( !objects.get( Boolean.FALSE ).containsKey( object.getClass() ) ) + { + objects.get( Boolean.FALSE ).put( object.getClass(), new ArrayList<>() ); + } + + if ( isPersisted( object ) ) + { + objects.get( Boolean.TRUE ).get( object.getClass() ).add( object ); + } + else + { + objects.get( Boolean.FALSE ).get( object.getClass() ).add( object ); + } } - public void addObjects( List objects ) + private void addObject( List objects ) { objects.forEach( this::addObject ); } - public void addObjects( Map, List> objects ) - { - objects.keySet().forEach( klass -> addObjects( objects.get( klass ) ) ); - } - - public Map, List> getObjects() - { - return objects; - } - - public List getObjects( Class klass, boolean persisted ) - { - List objectMap = new ArrayList<>(); - - if ( !objects.containsKey( klass ) ) - { - return objectMap; - } - - objects.get( klass ).forEach( object -> { - IdentifiableObject cachedObject = preheat.get( preheatIdentifier, object ); - boolean isPersisted = !(cachedObject == null || cachedObject.getId() == 0); - - if ( persisted && isPersisted ) objectMap.add( object ); - if ( !persisted && !isPersisted ) objectMap.add( object ); + private void addObject( Map, List> objects ) + { + objects.keySet().forEach( klass -> addObject( objects.get( klass ) ) ); + } + + public Map, List> getObjectMap() + { + Set> klasses = new HashSet<>(); + klasses.addAll( objects.get( Boolean.TRUE ).keySet() ); + klasses.addAll( objects.get( Boolean.FALSE ).keySet() ); + + Map, List> objectMap = new HashMap<>(); + + klasses.forEach( klass -> { + objectMap.put( klass, new ArrayList<>() ); + objectMap.get( klass ).addAll( objects.get( Boolean.TRUE ).get( klass ) ); + objectMap.get( klass ).addAll( objects.get( Boolean.FALSE ).get( klass ) ); } ); return objectMap; } - public void setObjects( Map, List> objects ) + public List getObjects( Class klass, boolean persisted ) { - this.objects = objects; + List identifiableObjects = null; + + if ( persisted ) + { + if ( objects.get( Boolean.TRUE ).containsKey( klass ) ) + { + identifiableObjects = objects.get( Boolean.TRUE ).get( klass ); + } + } + else + { + if ( objects.get( Boolean.FALSE ).containsKey( klass ) ) + { + identifiableObjects = objects.get( Boolean.FALSE ).get( klass ); + } + } + + return identifiableObjects != null ? identifiableObjects : new ArrayList<>(); } public Map> getObjectReferences( Class klass ) @@ -210,4 +229,10 @@ { this.objectReferences = objectReferences; } + + public boolean isPersisted( IdentifiableObject object ) + { + IdentifiableObject cachedObject = preheat.get( preheatIdentifier, object ); + return !(cachedObject == null || cachedObject.getId() == 0); + } } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/hooks/UserObjectBundleHook.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/hooks/UserObjectBundleHook.java 2016-03-12 08:52:42 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata2/objectbundle/hooks/UserObjectBundleHook.java 2016-03-13 04:20:01 +0000 @@ -116,9 +116,9 @@ @SuppressWarnings( "unchecked" ) public void postImport( ObjectBundle objectBundle ) { - if ( !objectBundle.getObjects().containsKey( User.class ) ) return; + if ( !objectBundle.getObjectMap().containsKey( User.class ) ) return; - List objects = objectBundle.getObjects().get( User.class ); + List objects = objectBundle.getObjectMap().get( User.class ); Map> userReferences = objectBundle.getObjectReferences( User.class ); Map> userCredentialsReferences = objectBundle.getObjectReferences( UserCredentials.class ); === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundleServiceTest.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundleServiceTest.java 2016-03-12 13:39:37 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata2/objectbundle/ObjectBundleServiceTest.java 2016-03-13 04:20:01 +0000 @@ -128,15 +128,16 @@ @Test public void testObjectBundleShouldAddToObjectAndPreheat() { + DataElementGroup dataElementGroup = fromJson( "dxf2/degAUidRef.json", DataElementGroup.class ); + ObjectBundleParams params = new ObjectBundleParams(); params.setObjectBundleMode( ObjectBundleMode.VALIDATE ); + params.addObject( dataElementGroup ); ObjectBundle bundle = objectBundleService.create( params ); - - DataElementGroup dataElementGroup = fromJson( "dxf2/degAUidRef.json", DataElementGroup.class ); - bundle.addObject( dataElementGroup ); - - assertTrue( bundle.getObjects().get( DataElementGroup.class ).contains( dataElementGroup ) ); + bundle.getPreheat().put( bundle.getPreheatIdentifier(), dataElementGroup ); + + assertTrue( bundle.getObjectMap().get( DataElementGroup.class ).contains( dataElementGroup ) ); assertTrue( bundle.getPreheat().containsKey( PreheatIdentifier.UID, DataElementGroup.class, dataElementGroup.getUid() ) ); } @@ -148,6 +149,7 @@ ObjectBundleParams params = new ObjectBundleParams(); params.setObjectBundleMode( ObjectBundleMode.VALIDATE ); + params.setImportMode( ImportStrategy.CREATE ); params.setObjects( metadata ); ObjectBundle bundle = objectBundleService.create( params ); @@ -205,6 +207,7 @@ ObjectBundleParams params = new ObjectBundleParams(); params.setObjectBundleMode( ObjectBundleMode.VALIDATE ); + params.setImportMode( ImportStrategy.CREATE ); params.setObjects( metadata ); ObjectBundle bundle = objectBundleService.create( params ); @@ -246,24 +249,44 @@ } @Test - public void testPreheatValidationsInvalidObjects() throws IOException + public void testCreatePreheatValidationsInvalidObjects() throws IOException { Map, List> metadata = renderService.fromMetadata( new ClassPathResource( "dxf2/de_validate2.json" ).getInputStream(), RenderFormat.JSON ); ObjectBundleParams params = new ObjectBundleParams(); params.setObjectBundleMode( ObjectBundleMode.VALIDATE ); + params.setImportMode( ImportStrategy.CREATE ); params.setObjects( metadata ); ObjectBundle bundle = objectBundleService.create( params ); ObjectBundleValidation validate = objectBundleService.validate( bundle ); assertFalse( validate.getObjectErrorReports().isEmpty() ); - assertEquals( 5, validate.getErrorReportsByCode( DataElement.class, ErrorCode.E5002 ).size() ); + + assertEquals( 3, validate.getErrorReportsByCode( DataElement.class, ErrorCode.E5002 ).size() ); assertEquals( 3, validate.getErrorReportsByCode( DataElement.class, ErrorCode.E4000 ).size() ); } @Test + public void testUpdatePreheatValidationsInvalidObjects() throws IOException + { + Map, List> metadata = renderService.fromMetadata( + new ClassPathResource( "dxf2/de_validate2.json" ).getInputStream(), RenderFormat.JSON ); + + ObjectBundleParams params = new ObjectBundleParams(); + params.setObjectBundleMode( ObjectBundleMode.VALIDATE ); + params.setImportMode( ImportStrategy.UPDATE ); + params.setObjects( metadata ); + + ObjectBundle bundle = objectBundleService.create( params ); + ObjectBundleValidation validate = objectBundleService.validate( bundle ); + + assertFalse( validate.getObjectErrorReports().isEmpty() ); + assertEquals( 3, validate.getErrorReportsByCode( DataElement.class, ErrorCode.E5001 ).size() ); + } + + @Test public void testUpdateRequiresValidReferencesUID() throws IOException { Map, List> metadata = renderService.fromMetadata( @@ -299,7 +322,7 @@ assertEquals( 1, validate.getErrorReportsByCode( DataElement.class, ErrorCode.E5001 ).size() ); assertFalse( validate.getErrorReportsByCode( DataElement.class, ErrorCode.E4000 ).isEmpty() ); - assertEquals( 0, bundle.getObjects().get( DataElement.class ).size() ); + assertEquals( 0, bundle.getObjectMap().get( DataElement.class ).size() ); } @Test @@ -1214,7 +1237,7 @@ params.setObjects( metadata ); ObjectBundle bundle = objectBundleService.create( params ); - objectBundleService.validate( bundle ); + assertTrue( objectBundleService.validate( bundle ).getObjectErrorReports().isEmpty() ); objectBundleService.commit( bundle ); DataElement dataElementA = dataElementMap.get( "deabcdefghA" );