=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java 2015-03-15 20:49:24 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java 2015-03-31 17:17:03 +0000 @@ -208,6 +208,14 @@ Collection getOrganisationUnitsByNames( Collection names ); /** + * Returns all OrganisationUnits matching the given codes. + * + * @param codes codes of OrganisationUnits to return. + * @return the OrganisationUnits matching the given codes. + */ + Collection getOrganisationUnitsByCodes( Collection codes ); + + /** * Returns all root OrganisationUnits. A root OrganisationUnit is an * OrganisationUnit with no parent/the parent set to null. * === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java 2015-01-17 07:41:26 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitStore.java 2015-03-31 17:17:03 +0000 @@ -67,6 +67,14 @@ Collection getByNames( Collection names ); /** + * Retrieves all OrganisationUnits matching the given codes. + * + * @param codes codes of the OrganisationUnits to return. + * @return all OrganisationUnits matching the given codes. + */ + Collection getByCodes( Collection codes ); + + /** * Returns all OrganisationUnits by status. * * @param active Get active or inactive === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java 2015-03-15 20:49:24 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java 2015-03-31 17:17:03 +0000 @@ -271,12 +271,19 @@ return organisationUnitStore.getAllEqNameIgnoreCase( name ); } - @Override public Collection getOrganisationUnitsByNames( Collection names ) + @Override + public Collection getOrganisationUnitsByNames( Collection names ) { return i18n( i18nService, organisationUnitStore.getByNames( names ) ); } @Override + public Collection getOrganisationUnitsByCodes( Collection codes ) + { + return i18n( i18nService, organisationUnitStore.getByCodes( codes ) ); + } + + @Override public Collection getRootOrganisationUnits() { return i18n( i18nService, organisationUnitStore.getRootOrganisationUnits()); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java 2015-02-19 09:18:17 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java 2015-04-08 15:29:00 +0000 @@ -31,6 +31,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; @@ -92,6 +93,11 @@ @SuppressWarnings( "unchecked" ) public Collection getByNames( Collection names ) { + if ( names == null || names.isEmpty() ) + { + return new ArrayList<>(); + } + Query query = getQuery( "from OrganisationUnit where name in :names" ); query.setParameterList( "names", names ); @@ -99,6 +105,22 @@ } @Override + @SuppressWarnings( "unchecked" ) + public Collection getByCodes( Collection codes ) + { + + if ( codes == null || codes.isEmpty() ) + { + return new ArrayList<>(); + } + + Query query = getQuery( "from OrganisationUnit where code in :codes" ); + query.setParameterList( "codes", codes ); + + return query.list(); + } + + @Override @SuppressWarnings("unchecked") public Collection getAllOrganisationUnitsByStatus( boolean active ) { === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/gml/DefaultGmlImportService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/gml/DefaultGmlImportService.java 2015-03-05 16:05:19 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/gml/DefaultGmlImportService.java 2015-04-09 23:35:37 +0000 @@ -29,7 +29,11 @@ */ import com.google.common.base.Function; +import com.google.common.base.Strings; +import com.google.common.collect.Iterators; import com.google.common.collect.Maps; +import org.hisp.dhis.common.IdentifiableObjectManager; +import org.hisp.dhis.common.IdentifiableProperty; import org.hisp.dhis.common.MergeStrategy; import org.hisp.dhis.dxf2.common.ImportOptions; import org.hisp.dhis.dxf2.metadata.ImportService; @@ -51,6 +55,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Map; /** @@ -74,6 +81,9 @@ @Autowired private OrganisationUnitService organisationUnitService; + @Autowired + private IdentifiableObjectManager idObjectManager; + // ------------------------------------------------------------------------- // GmlImportService implementation // ------------------------------------------------------------------------- @@ -83,48 +93,43 @@ throws IOException, TransformerException { InputStream dxfStream = transformGml( inputStream ); - MetaData metaData = renderService.fromXml( dxfStream, MetaData.class ); - dxfStream.close(); - Map namedMap = Maps.uniqueIndex( metaData.getOrganisationUnits(), - new Function() - { - @Override - public String apply( OrganisationUnit organisationUnit ) - { - return organisationUnit.getName(); - } - } - ); - - // Fetch persisted OrganisationUnits and merge imported GML properties - Collection persistedOrgUnits = organisationUnitService.getOrganisationUnitsByNames( namedMap.keySet() ); - - for( OrganisationUnit persisted : persistedOrgUnits ) + Map uidMap = Maps.newHashMap(), codeMap = Maps.newHashMap(), nameMap = Maps.newHashMap(); + + matchAndFilterOnIdentifiers( metaData.getOrganisationUnits(), uidMap, codeMap, nameMap ); + + Map persistedUidMap = getMatchingPersistedOrgUnits( uidMap.keySet(), IdentifiableProperty.UID ); + Map persistedCodeMap = getMatchingPersistedOrgUnits( codeMap.keySet(), IdentifiableProperty.CODE ); + Map persistedNameMap = getMatchingPersistedOrgUnits( nameMap.keySet(), IdentifiableProperty.NAME ); + + Iterator persistedIterator = Iterators.concat( persistedUidMap.values().iterator(), + persistedCodeMap.values().iterator(), persistedNameMap.values().iterator() ); + + while ( persistedIterator.hasNext() ) { - OrganisationUnit unit = namedMap.get( persisted.getName() ); - - if( unit == null || unit.getCoordinates() == null || unit.getFeatureType() == null ) - { - continue; - } - - String coordinates = unit.getCoordinates(), - featureType = unit.getFeatureType(); - - unit.mergeWith( persisted, MergeStrategy.MERGE_IF_NOT_NULL ); - - unit.setCoordinates( coordinates ); - unit.setFeatureType( featureType ); - - if( persisted.getParent() != null ) - { - OrganisationUnit parent = new OrganisationUnit(); - parent.setUid( persisted.getParent().getUid() ); - unit.setParent( parent ); - } + OrganisationUnit persisted = persistedIterator.next(), imported = null; + + if ( !Strings.isNullOrEmpty( persisted.getUid() ) && uidMap.containsKey( persisted.getUid() ) ) + { + imported = uidMap.get( persisted.getUid() ); + } + else if ( !Strings.isNullOrEmpty( persisted.getCode() ) && codeMap.containsKey( persisted.getCode() ) ) + { + imported = codeMap.get( persisted.getCode() ); + } + else if ( !Strings.isNullOrEmpty( persisted.getName() ) && nameMap.containsKey( persisted.getName() ) ) + { + imported = nameMap.get( persisted.getName() ); + } + + if ( imported == null || imported.getCoordinates() == null || imported.getFeatureType() == null ) + { + continue; // Failed to dereference a persisted entity for this org unit or geo data incomplete/missing, therefore ignore + } + + mergeNonGeoData( persisted, imported ); } return metaData; @@ -157,4 +162,65 @@ return new ByteArrayInputStream( output.toByteArray() ); } + + private void matchAndFilterOnIdentifiers( List sourceList, Map uidMap, Map codeMap, Map nameMap ) + { + for ( OrganisationUnit orgUnit : sourceList ) // Identifier Matching priority: uid, code, name + { + // Only matches if UID is actually in DB as an empty UID on input will be replaced by auto-generated value + if ( !Strings.isNullOrEmpty( orgUnit.getUid() ) && idObjectManager.exists( OrganisationUnit.class, orgUnit.getUid() ) ) + { + uidMap.put( orgUnit.getUid(), orgUnit ); + } + else if ( !Strings.isNullOrEmpty( orgUnit.getCode() ) ) + { + codeMap.put( orgUnit.getCode(), orgUnit ); + } + else if ( !Strings.isNullOrEmpty( orgUnit.getName() ) ) + { + nameMap.put( orgUnit.getName(), orgUnit ); + } + } + } + + private Map getMatchingPersistedOrgUnits( Collection identifiers, final IdentifiableProperty idProperty ) + { + Collection orgUnits = + idProperty == IdentifiableProperty.UID ? organisationUnitService.getOrganisationUnitsByUid( identifiers ) : + idProperty == IdentifiableProperty.CODE ? organisationUnitService.getOrganisationUnitsByCodes( identifiers ) : + idProperty == IdentifiableProperty.NAME ? organisationUnitService.getOrganisationUnitsByNames( identifiers ) : + new HashSet(); + + return Maps.uniqueIndex( orgUnits, + new Function() + { + @Override + public String apply( OrganisationUnit organisationUnit ) + { + return idProperty == IdentifiableProperty.UID ? organisationUnit.getUid() : + idProperty == IdentifiableProperty.CODE ? organisationUnit.getCode() : + idProperty == IdentifiableProperty.NAME ? organisationUnit.getName() : null; + } + } + ); + } + + private void mergeNonGeoData( OrganisationUnit source, OrganisationUnit target ) + { + String coordinates = target.getCoordinates(), + featureType = target.getFeatureType(); + + target.mergeWith( source, MergeStrategy.MERGE ); + + target.setCoordinates( coordinates ); + target.setFeatureType( featureType ); + + if ( source.getParent() != null ) + { + OrganisationUnit parent = new OrganisationUnit(); + parent.setUid( source.getParent().getUid() ); + target.setParent( parent ); + } + } } === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/gml/gml2dxf2.xsl' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/gml/gml2dxf2.xsl 2015-03-24 16:52:51 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/gml/gml2dxf2.xsl 2015-04-09 23:35:37 +0000 @@ -78,14 +78,27 @@ - + + + - - - - - - + + + + + + + + + + + + + + + + + true === modified file 'dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/util/ImportMetaDataGmlTask.java' --- dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/util/ImportMetaDataGmlTask.java 2015-02-17 06:00:52 +0000 +++ dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/util/ImportMetaDataGmlTask.java 2015-04-09 14:51:07 +0000 @@ -88,7 +88,7 @@ { gmlImportService.importGml( inputStream, userUid, importOptions, taskId ); } - catch ( IOException | TransformerException e) + catch ( IOException | TransformerException e ) { log.error( "Unable to read GML data from input stream", e ); }