=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFieldFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFieldFilterService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFieldFilterService.java 2014-06-17 15:28:24 +0000 @@ -0,0 +1,352 @@ +package org.hisp.dhis.dxf2.filter; + +/* + * Copyright (c) 2004-2014, 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 com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.hisp.dhis.common.IdentifiableObject; +import org.hisp.dhis.node.types.CollectionNode; +import org.hisp.dhis.node.types.ComplexNode; +import org.hisp.dhis.node.types.SimpleNode; +import org.hisp.dhis.schema.Property; +import org.hisp.dhis.schema.Schema; +import org.hisp.dhis.schema.SchemaService; +import org.hisp.dhis.system.util.ReflectionUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Morten Olav Hansen + */ +public class DefaultFieldFilterService implements FieldFilterService +{ + static final ImmutableMap> FIELD_PRESETS = ImmutableMap.>builder() + .put( "all", Lists.newArrayList( "*" ) ) + .put( "identifiable", Lists.newArrayList( "id", "name", "code", "created", "lastUpdated", "href" ) ) + .put( "nameable", Lists.newArrayList( "id", "name", "shortName", "description", "code", "created", "lastUpdated", "href" ) ) + .build(); + + @Autowired + private ParserService parserService; + + @Autowired + private SchemaService schemaService; + + @Override + public CollectionNode filter( Class klass, List objects, List fieldList ) + { + if ( objects == null ) + { + return null; + } + + String fields = fieldList == null ? "" : Joiner.on( "," ).join( fieldList ); + + Schema rootSchema = schemaService.getDynamicSchema( klass ); + + Map fieldMap = Maps.newHashMap(); + Schema schema = schemaService.getDynamicSchema( objects.get( 0 ).getClass() ); + + if ( fields == null ) + { + for ( Property property : schema.getProperties() ) + { + fieldMap.put( property.getName(), Maps.newHashMap() ); + } + } + else + { + fieldMap = parserService.parsePropertyFilter( fields ); + } + + CollectionNode collectionNode = new CollectionNode( rootSchema.getCollectionName() ); + collectionNode.setNamespace( rootSchema.getNamespace() ); + + for ( Object object : objects ) + { + collectionNode.addChild( buildComplexNode( fieldMap, klass, object ) ); + } + + return collectionNode; + } + + @SuppressWarnings( "unchecked" ) + private ComplexNode buildComplexNode( Map fieldMap, Class klass, Object object ) + { + Schema schema = schemaService.getDynamicSchema( klass ); + + ComplexNode complexNode = new ComplexNode( schema.getName() ); + complexNode.setNamespace( schema.getNamespace() ); + + if ( object == null ) + { + return complexNode; + } + + updateFields( fieldMap, schema.getKlass() ); + + for ( String fieldKey : fieldMap.keySet() ) + { + if ( !schema.getPropertyMap().containsKey( fieldKey ) ) + { + continue; + } + + Property property = schema.getPropertyMap().get( fieldKey ); + + Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() ); + Schema propertySchema = schemaService.getDynamicSchema( property.getKlass() ); + + Map fieldValue = fieldMap.get( fieldKey ); + + if ( property.isCollection() ) + { + updateFields( fieldValue, property.getItemKlass() ); + } + else + { + updateFields( fieldValue, property.getKlass() ); + } + + if ( fieldValue.isEmpty() ) + { + List fields = FIELD_PRESETS.get( "identifiable" ); + + if ( property.isCollection() ) + { + Collection collection = (Collection) returnValue; + + CollectionNode collectionNode = complexNode.addChild( new CollectionNode( property.getCollectionName() ) ); + collectionNode.setNamespace( property.getNamespace() ); + + if ( property.isIdentifiableObject() ) + { + for ( Object collectionObject : collection ) + { + collectionNode.addChild( getProperties( property, collectionObject, fields ) ); + } + } + else if ( !property.isSimple() ) + { + Map map = getFullFieldMap( schemaService.getDynamicSchema( property.getItemKlass() ) ); + + for ( Object collectionObject : collection ) + { + ComplexNode node = buildComplexNode( map, property.getItemKlass(), collectionObject ); + + if ( !node.getChildren().isEmpty() ) + { + collectionNode.addChild( node ); + } + } + } + else + { + for ( Object collectionObject : collection ) + { + collectionNode.addChild( new SimpleNode( property.getName(), collectionObject ) ); + } + } + } + else if ( property.isIdentifiableObject() ) + { + complexNode.addChild( getProperties( property, returnValue, fields ) ); + } + else + { + if ( propertySchema.getProperties().isEmpty() ) + { + SimpleNode simpleNode = new SimpleNode( fieldKey, returnValue ); + simpleNode.setAttribute( property.isAttribute() ); + simpleNode.setNamespace( property.getNamespace() ); + + complexNode.addChild( simpleNode ); + } + else + { + complexNode.addChild( buildComplexNode( getFullFieldMap( propertySchema ), property.getKlass(), + returnValue ) ); + } + } + } + else + { + if ( property.isCollection() ) + { + CollectionNode collectionNode = complexNode.addChild( new CollectionNode( property.getCollectionName() ) ); + collectionNode.setNamespace( property.getNamespace() ); + + for ( Object collectionObject : (Collection) returnValue ) + { + ComplexNode node = buildComplexNode( fieldValue, property.getItemKlass(), collectionObject ); + + if ( !node.getChildren().isEmpty() ) + { + collectionNode.addChild( node ); + } + } + } + else + { + ComplexNode node = buildComplexNode( fieldValue, property.getKlass(), returnValue ); + + if ( !node.getChildren().isEmpty() ) + { + complexNode.addChild( node ); + } + } + } + } + + return complexNode; + } + + private void updateFields( Map fieldMap, Class klass ) + { + // we need two run this (at least) two times, since some of the presets might contain other presets + _updateFields( fieldMap, klass, true ); + _updateFields( fieldMap, klass, false ); + } + + private void _updateFields( Map fieldMap, Class klass, boolean expandOnly ) + { + Schema schema = schemaService.getDynamicSchema( klass ); + List cleanupFields = Lists.newArrayList(); + + for ( String fieldKey : Sets.newHashSet( fieldMap.keySet() ) ) + { + if ( "*".equals( fieldKey ) ) + { + for ( String mapKey : schema.getPropertyMap().keySet() ) + { + if ( !fieldMap.containsKey( mapKey ) ) + { + fieldMap.put( mapKey, Maps.newHashMap() ); + } + } + + cleanupFields.add( fieldKey ); + } + else if ( fieldKey.startsWith( ":" ) ) + { + List fields = FIELD_PRESETS.get( fieldKey.substring( 1 ) ); + + if ( fields == null ) + { + continue; + } + + for ( String field : fields ) + { + if ( !fieldMap.containsKey( field ) ) + { + fieldMap.put( field, Maps.newHashMap() ); + } + } + + cleanupFields.add( fieldKey ); + } + else if ( fieldKey.startsWith( "!" ) && !expandOnly ) + { + cleanupFields.add( fieldKey ); + } + } + + for ( String field : cleanupFields ) + { + fieldMap.remove( field ); + + if ( !expandOnly ) + { + fieldMap.remove( field.substring( 1 ) ); + } + } + } + + private Map getFullFieldMap( Schema schema ) + { + Map map = Maps.newHashMap(); + + for ( String mapKey : schema.getPropertyMap().keySet() ) + { + map.put( mapKey, Maps.newHashMap() ); + } + + return map; + } + + private ComplexNode getProperties( Property currentProperty, Object object, List fields ) + { + if ( object == null ) + { + return null; + } + + ComplexNode complexNode = new ComplexNode( currentProperty.getName() ); + complexNode.setNamespace( currentProperty.getNamespace() ); + + Schema schema; + + if ( currentProperty.isCollection() ) + { + schema = schemaService.getDynamicSchema( currentProperty.getItemKlass() ); + + } + else + { + schema = schemaService.getDynamicSchema( currentProperty.getKlass() ); + } + + for ( String field : fields ) + { + Property property = schema.getPropertyMap().get( field ); + + if ( property == null ) + { + continue; + } + + Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() ); + + SimpleNode simpleNode = new SimpleNode( field, returnValue ); + simpleNode.setAttribute( property.isAttribute() ); + simpleNode.setNamespace( property.getNamespace() ); + + complexNode.addChild( simpleNode ); + } + + return complexNode; + } +} === removed file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java 2014-06-17 15:16:25 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java 1970-01-01 00:00:00 +0000 @@ -1,489 +0,0 @@ -package org.hisp.dhis.dxf2.filter; - -/* - * Copyright (c) 2004-2014, 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 com.google.common.base.Joiner; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.hisp.dhis.common.IdentifiableObject; -import org.hisp.dhis.dxf2.filter.ops.Op; -import org.hisp.dhis.node.types.CollectionNode; -import org.hisp.dhis.node.types.ComplexNode; -import org.hisp.dhis.node.types.SimpleNode; -import org.hisp.dhis.schema.Property; -import org.hisp.dhis.schema.Schema; -import org.hisp.dhis.schema.SchemaService; -import org.hisp.dhis.system.util.ReflectionUtils; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * @author Morten Olav Hansen - */ -public class DefaultFilterService implements FilterService -{ - static final ImmutableMap> FIELD_PRESETS = ImmutableMap.>builder() - .put( "all", Lists.newArrayList( "*" ) ) - .put( "identifiable", Lists.newArrayList( "id", "name", "code", "created", "lastUpdated", "href" ) ) - .put( "nameable", Lists.newArrayList( "id", "name", "shortName", "description", "code", "created", "lastUpdated", "href" ) ) - .build(); - - @Autowired - private ParserService parserService; - - @Autowired - private SchemaService schemaService; - - @Override - public List objectFilter( List objects, List filters ) - { - if ( objects == null || objects.isEmpty() ) - { - return Lists.newArrayList(); - } - - Filters parsed = parserService.parseObjectFilter( filters ); - - List list = Lists.newArrayList(); - - for ( T object : objects ) - { - if ( evaluateWithFilters( object, parsed ) ) - { - list.add( object ); - } - } - - return list; - } - - @Override - public CollectionNode fieldFilter( Class klass, List objects, - List fieldList ) - { - if ( objects == null ) - { - return null; - } - - String fields = fieldList == null ? "" : Joiner.on( "," ).join( fieldList ); - - Schema rootSchema = schemaService.getDynamicSchema( klass ); - - Map fieldMap = Maps.newHashMap(); - Schema schema = schemaService.getDynamicSchema( objects.get( 0 ).getClass() ); - - if ( fields == null ) - { - for ( Property property : schema.getProperties() ) - { - fieldMap.put( property.getName(), Maps.newHashMap() ); - } - } - else - { - fieldMap = parserService.parsePropertyFilter( fields ); - } - - CollectionNode collectionNode = new CollectionNode( rootSchema.getCollectionName() ); - collectionNode.setNamespace( rootSchema.getNamespace() ); - - for ( Object object : objects ) - { - collectionNode.addChild( buildComplexNode( fieldMap, klass, object ) ); - } - - return collectionNode; - } - - @SuppressWarnings( "unchecked" ) - private ComplexNode buildComplexNode( Map fieldMap, Class klass, Object object ) - { - Schema schema = schemaService.getDynamicSchema( klass ); - - ComplexNode complexNode = new ComplexNode( schema.getName() ); - complexNode.setNamespace( schema.getNamespace() ); - - if ( object == null ) - { - return complexNode; - } - - updateFields( fieldMap, schema.getKlass() ); - - for ( String fieldKey : fieldMap.keySet() ) - { - if ( !schema.getPropertyMap().containsKey( fieldKey ) ) - { - continue; - } - - Property property = schema.getPropertyMap().get( fieldKey ); - - Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() ); - Schema propertySchema = schemaService.getDynamicSchema( property.getKlass() ); - - Map fieldValue = fieldMap.get( fieldKey ); - - if ( property.isCollection() ) - { - updateFields( fieldValue, property.getItemKlass() ); - } - else - { - updateFields( fieldValue, property.getKlass() ); - } - - if ( fieldValue.isEmpty() ) - { - List fields = FIELD_PRESETS.get( "identifiable" ); - - if ( property.isCollection() ) - { - Collection collection = (Collection) returnValue; - - CollectionNode collectionNode = complexNode.addChild( new CollectionNode( property.getCollectionName() ) ); - collectionNode.setNamespace( property.getNamespace() ); - - if ( property.isIdentifiableObject() ) - { - for ( Object collectionObject : collection ) - { - collectionNode.addChild( getProperties( property, collectionObject, fields ) ); - } - } - else if ( !property.isSimple() ) - { - Map map = getFullFieldMap( schemaService.getDynamicSchema( property.getItemKlass() ) ); - - for ( Object collectionObject : collection ) - { - ComplexNode node = buildComplexNode( map, property.getItemKlass(), collectionObject ); - - if ( !node.getChildren().isEmpty() ) - { - collectionNode.addChild( node ); - } - } - } - else - { - for ( Object collectionObject : collection ) - { - collectionNode.addChild( new SimpleNode( property.getName(), collectionObject ) ); - } - } - } - else if ( property.isIdentifiableObject() ) - { - complexNode.addChild( getProperties( property, returnValue, fields ) ); - } - else - { - if ( propertySchema.getProperties().isEmpty() ) - { - SimpleNode simpleNode = new SimpleNode( fieldKey, returnValue ); - simpleNode.setAttribute( property.isAttribute() ); - simpleNode.setNamespace( property.getNamespace() ); - - complexNode.addChild( simpleNode ); - } - else - { - complexNode.addChild( buildComplexNode( getFullFieldMap( propertySchema ), property.getKlass(), - returnValue ) ); - } - } - } - else - { - if ( property.isCollection() ) - { - CollectionNode collectionNode = complexNode.addChild( new CollectionNode( property.getCollectionName() ) ); - collectionNode.setNamespace( property.getNamespace() ); - - for ( Object collectionObject : (Collection) returnValue ) - { - ComplexNode node = buildComplexNode( fieldValue, property.getItemKlass(), collectionObject ); - - if ( !node.getChildren().isEmpty() ) - { - collectionNode.addChild( node ); - } - } - } - else - { - ComplexNode node = buildComplexNode( fieldValue, property.getKlass(), returnValue ); - - if ( !node.getChildren().isEmpty() ) - { - complexNode.addChild( node ); - } - } - } - } - - return complexNode; - } - - private void updateFields( Map fieldMap, Class klass ) - { - // we need two run this (at least) two times, since some of the presets might contain other presets - _updateFields( fieldMap, klass, true ); - _updateFields( fieldMap, klass, false ); - } - - private void _updateFields( Map fieldMap, Class klass, boolean expandOnly ) - { - Schema schema = schemaService.getDynamicSchema( klass ); - List cleanupFields = Lists.newArrayList(); - - for ( String fieldKey : Sets.newHashSet( fieldMap.keySet() ) ) - { - if ( "*".equals( fieldKey ) ) - { - for ( String mapKey : schema.getPropertyMap().keySet() ) - { - if ( !fieldMap.containsKey( mapKey ) ) - { - fieldMap.put( mapKey, Maps.newHashMap() ); - } - } - - cleanupFields.add( fieldKey ); - } - else if ( fieldKey.startsWith( ":" ) ) - { - List fields = FIELD_PRESETS.get( fieldKey.substring( 1 ) ); - - if ( fields == null ) - { - continue; - } - - for ( String field : fields ) - { - if ( !fieldMap.containsKey( field ) ) - { - fieldMap.put( field, Maps.newHashMap() ); - } - } - - cleanupFields.add( fieldKey ); - } - else if ( fieldKey.startsWith( "!" ) && !expandOnly ) - { - cleanupFields.add( fieldKey ); - } - } - - for ( String field : cleanupFields ) - { - fieldMap.remove( field ); - - if ( !expandOnly ) - { - fieldMap.remove( field.substring( 1 ) ); - } - } - } - - private Map getFullFieldMap( Schema schema ) - { - Map map = Maps.newHashMap(); - - for ( String mapKey : schema.getPropertyMap().keySet() ) - { - map.put( mapKey, Maps.newHashMap() ); - } - - return map; - } - - private ComplexNode getProperties( Property currentProperty, Object object, List fields ) - { - if ( object == null ) - { - return null; - } - - ComplexNode complexNode = new ComplexNode( currentProperty.getName() ); - complexNode.setNamespace( currentProperty.getNamespace() ); - - Schema schema; - - if ( currentProperty.isCollection() ) - { - schema = schemaService.getDynamicSchema( currentProperty.getItemKlass() ); - - } - else - { - schema = schemaService.getDynamicSchema( currentProperty.getKlass() ); - } - - for ( String field : fields ) - { - Property property = schema.getPropertyMap().get( field ); - - if ( property == null ) - { - continue; - } - - Object returnValue = ReflectionUtils.invokeMethod( object, property.getGetterMethod() ); - - SimpleNode simpleNode = new SimpleNode( field, returnValue ); - simpleNode.setAttribute( property.isAttribute() ); - simpleNode.setNamespace( property.getNamespace() ); - - complexNode.addChild( simpleNode ); - } - - return complexNode; - } - - @SuppressWarnings( "unchecked" ) - private boolean evaluateWithFilters( T object, Filters filters ) - { - Schema schema = schemaService.getDynamicSchema( object.getClass() ); - - for ( String field : filters.getFilters().keySet() ) - { - if ( !schema.getPropertyMap().containsKey( field ) ) - { - continue; - } - - Property descriptor = schema.getPropertyMap().get( field ); - - if ( descriptor == null ) - { - continue; - } - - Object value = ReflectionUtils.invokeMethod( object, descriptor.getGetterMethod() ); - - Object filter = filters.getFilters().get( field ); - - if ( FilterOps.class.isInstance( filter ) ) - { - if ( evaluateFilterOps( value, (FilterOps) filter ) ) - { - return false; - } - } - else - { - Map map = (Map) filters.getFilters().get( field ); - Filters f = new Filters(); - f.setFilters( map ); - - if ( map.containsKey( "__self__" ) ) - { - if ( evaluateFilterOps( value, (FilterOps) map.get( "__self__" ) ) ) - { - return false; - } - - map.remove( "__self__" ); - } - - if ( !descriptor.isCollection() ) - { - if ( !evaluateWithFilters( value, f ) ) - { - return false; - } - } - else - { - Collection objectCollection = (Collection) value; - - if ( objectCollection.isEmpty() ) - { - return false; - } - - boolean include = false; - - for ( Object idObject : objectCollection ) - { - if ( evaluateWithFilters( idObject, f ) ) - { - include = true; - } - } - - if ( !include ) - { - return false; - } - } - } - } - - return true; - } - - private boolean evaluateFilterOps( Object value, FilterOps filterOps ) - { - // filter through every operator treating multiple of same operator as OR - for ( String operator : filterOps.getFilters().keySet() ) - { - boolean include = false; - - List ops = filterOps.getFilters().get( operator ); - - for ( Op op : ops ) - { - switch ( op.evaluate( value ) ) - { - case INCLUDE: - { - include = true; - } - } - } - - if ( !include ) - { - return true; - } - } - - return false; - } -} === added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultObjectFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultObjectFilterService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultObjectFilterService.java 2014-06-17 15:28:24 +0000 @@ -0,0 +1,189 @@ +package org.hisp.dhis.dxf2.filter; + +/* + * Copyright (c) 2004-2014, 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 com.google.common.collect.Lists; +import org.hisp.dhis.common.IdentifiableObject; +import org.hisp.dhis.dxf2.filter.ops.Op; +import org.hisp.dhis.schema.Property; +import org.hisp.dhis.schema.Schema; +import org.hisp.dhis.schema.SchemaService; +import org.hisp.dhis.system.util.ReflectionUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Morten Olav Hansen + */ +public class DefaultObjectFilterService implements ObjectFilterService +{ + @Autowired + private ParserService parserService; + + @Autowired + private SchemaService schemaService; + + @Override + public List filter( List objects, List filters ) + { + if ( objects == null || objects.isEmpty() ) + { + return Lists.newArrayList(); + } + + Filters parsed = parserService.parseObjectFilter( filters ); + + List list = Lists.newArrayList(); + + for ( T object : objects ) + { + if ( evaluateWithFilters( object, parsed ) ) + { + list.add( object ); + } + } + + return list; + } + + @SuppressWarnings( "unchecked" ) + private boolean evaluateWithFilters( T object, Filters filters ) + { + Schema schema = schemaService.getDynamicSchema( object.getClass() ); + + for ( String field : filters.getFilters().keySet() ) + { + if ( !schema.getPropertyMap().containsKey( field ) ) + { + continue; + } + + Property descriptor = schema.getPropertyMap().get( field ); + + if ( descriptor == null ) + { + continue; + } + + Object value = ReflectionUtils.invokeMethod( object, descriptor.getGetterMethod() ); + + Object filter = filters.getFilters().get( field ); + + if ( FilterOps.class.isInstance( filter ) ) + { + if ( evaluateFilterOps( value, (FilterOps) filter ) ) + { + return false; + } + } + else + { + Map map = (Map) filters.getFilters().get( field ); + Filters f = new Filters(); + f.setFilters( map ); + + if ( map.containsKey( "__self__" ) ) + { + if ( evaluateFilterOps( value, (FilterOps) map.get( "__self__" ) ) ) + { + return false; + } + + map.remove( "__self__" ); + } + + if ( !descriptor.isCollection() ) + { + if ( !evaluateWithFilters( value, f ) ) + { + return false; + } + } + else + { + Collection objectCollection = (Collection) value; + + if ( objectCollection.isEmpty() ) + { + return false; + } + + boolean include = false; + + for ( Object idObject : objectCollection ) + { + if ( evaluateWithFilters( idObject, f ) ) + { + include = true; + } + } + + if ( !include ) + { + return false; + } + } + } + } + + return true; + } + + private boolean evaluateFilterOps( Object value, FilterOps filterOps ) + { + // filter through every operator treating multiple of same operator as OR + for ( String operator : filterOps.getFilters().keySet() ) + { + boolean include = false; + + List ops = filterOps.getFilters().get( operator ); + + for ( Op op : ops ) + { + switch ( op.evaluate( value ) ) + { + case INCLUDE: + { + include = true; + } + } + } + + if ( !include ) + { + return true; + } + } + + return false; + } +} === added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FieldFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FieldFilterService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FieldFilterService.java 2014-06-17 15:28:24 +0000 @@ -0,0 +1,49 @@ +package org.hisp.dhis.dxf2.filter; + +/* + * Copyright (c) 2004-2014, 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.common.IdentifiableObject; +import org.hisp.dhis.node.types.CollectionNode; + +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +public interface FieldFilterService +{ + /** + * Perform inclusion/exclusion on a list of objects. + * + * @param objects List to filter + * @param fieldList Field filter + * @return List of objects with only wanted properties + */ + CollectionNode filter( Class klass, List objects, List fieldList ); +} === removed file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java 2014-06-17 15:16:25 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java 1970-01-01 00:00:00 +0000 @@ -1,58 +0,0 @@ -package org.hisp.dhis.dxf2.filter; - -/* - * Copyright (c) 2004-2014, 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.common.IdentifiableObject; -import org.hisp.dhis.node.types.CollectionNode; - -import java.util.List; - -/** - * @author Morten Olav Hansen - */ -public interface FilterService -{ - /** - * Filter a list of objects based on un-parsed filter string. - * - * @param objects List to filter - * @param filters Filter string - * @return Filtered object list - */ - List objectFilter( List objects, List filters ); - - /** - * Perform inclusion/exclusion on a list of objects. - * - * @param objects List to filter - * @param fieldList Field filter - * @return List of objects with only wanted properties - */ - CollectionNode fieldFilter( Class klass, List objects, List fieldList ); -} === added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/ObjectFilterService.java' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/ObjectFilterService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/ObjectFilterService.java 2014-06-17 15:28:24 +0000 @@ -0,0 +1,49 @@ +package org.hisp.dhis.dxf2.filter; + +/* + * Copyright (c) 2004-2014, 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.common.IdentifiableObject; + +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +public interface ObjectFilterService +{ + /** + * Filter a list of objects based on un-parsed filter string. + * In-memory filter + * + * @param objects List to filter + * @param filters Filter string + * @return Filtered object list + */ + List filter( List objects, List filters ); +} === modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/META-INF/dhis/beans.xml 2014-05-28 19:02:46 +0000 +++ dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/META-INF/dhis/beans.xml 2014-06-17 15:28:24 +0000 @@ -5,7 +5,9 @@ - + + + === modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java 2014-06-17 14:37:19 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java 2014-06-17 15:28:24 +0000 @@ -38,7 +38,8 @@ import org.hisp.dhis.common.IdentifiableObjectManager; import org.hisp.dhis.common.Pager; import org.hisp.dhis.common.PagerUtils; -import org.hisp.dhis.dxf2.filter.FilterService; +import org.hisp.dhis.dxf2.filter.FieldFilterService; +import org.hisp.dhis.dxf2.filter.ObjectFilterService; import org.hisp.dhis.dxf2.metadata.ImportService; import org.hisp.dhis.dxf2.metadata.ImportTypeSummary; import org.hisp.dhis.dxf2.render.RenderService; @@ -95,7 +96,10 @@ protected CurrentUserService currentUserService; @Autowired - protected FilterService filterService; + protected ObjectFilterService objectFilterService; + + @Autowired + protected FieldFilterService fieldFilterService; @Autowired protected AclService aclService; @@ -119,7 +123,7 @@ // GET //-------------------------------------------------------------------------- - @RequestMapping(method = RequestMethod.GET) + @RequestMapping( method = RequestMethod.GET ) public @ResponseBody RootNode getObjectList( @RequestParam Map parameters, HttpServletResponse response, HttpServletRequest request ) { @@ -154,7 +158,7 @@ // enable object filter if ( !filters.isEmpty() ) { - entityList = filterService.objectFilter( entityList, filters ); + entityList = objectFilterService.filter( entityList, filters ); if ( hasPaging ) { @@ -187,20 +191,20 @@ pagerNode.addChild( new SimpleNode( "prevPage", pager.getPrevPage() ) ); } - rootNode.addChild( filterService.fieldFilter( getEntityClass(), entityList, fields ) ); + rootNode.addChild( fieldFilterService.filter( getEntityClass(), entityList, fields ) ); return rootNode; } - @RequestMapping(value = "/{uid}/{property}", method = RequestMethod.GET) - public @ResponseBody RootNode getObjectProperty( @PathVariable("uid") String uid, @PathVariable("property") String property, + @RequestMapping( value = "/{uid}/{property}", method = RequestMethod.GET ) + public @ResponseBody RootNode getObjectProperty( @PathVariable( "uid" ) String uid, @PathVariable( "property" ) String property, @RequestParam Map parameters, HttpServletRequest request, HttpServletResponse response ) throws Exception { return getObjectInternal( uid, parameters, Lists.newArrayList(), Lists.newArrayList( property ) ); } - @RequestMapping(value = "/{uid}", method = RequestMethod.GET) - public @ResponseBody RootNode getObject( @PathVariable("uid") String uid, @RequestParam Map parameters, + @RequestMapping( value = "/{uid}", method = RequestMethod.GET ) + public @ResponseBody RootNode getObject( @PathVariable( "uid" ) String uid, @RequestParam Map parameters, HttpServletRequest request, HttpServletResponse response ) throws Exception { List fields = Lists.newArrayList( contextService.getParameterValues( "fields" ) ); @@ -225,7 +229,7 @@ throw new NotFoundException( uid ); } - entities = filterService.objectFilter( entities, filters ); + entities = objectFilterService.filter( entities, filters ); if ( options.hasLinks() ) { @@ -243,7 +247,7 @@ postProcessEntity( entity, options, parameters ); } - CollectionNode collectionNode = filterService.fieldFilter( getEntityClass(), entities, fields ); + CollectionNode collectionNode = fieldFilterService.filter( getEntityClass(), entities, fields ); if ( options.booleanTrue( "useWrapper" ) || entities.size() > 1 ) { @@ -268,7 +272,7 @@ // POST //-------------------------------------------------------------------------- - @RequestMapping(method = RequestMethod.POST, consumes = { "application/xml", "text/xml" }) + @RequestMapping( method = RequestMethod.POST, consumes = { "application/xml", "text/xml" } ) public void postXmlObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception { if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) ) @@ -281,7 +285,7 @@ renderService.toXml( response.getOutputStream(), summary ); } - @RequestMapping(method = RequestMethod.POST, consumes = "application/json") + @RequestMapping( method = RequestMethod.POST, consumes = "application/json" ) public void postJsonObject( HttpServletResponse response, HttpServletRequest request, InputStream input ) throws Exception { if ( !aclService.canCreate( currentUserService.getCurrentUser(), getEntityClass() ) ) @@ -298,9 +302,9 @@ // PUT //-------------------------------------------------------------------------- - @RequestMapping(value = "/{uid}", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE }) - @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void putXmlObject( HttpServletResponse response, HttpServletRequest request, @PathVariable("uid") String uid, InputStream + @RequestMapping( value = "/{uid}", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE } ) + @ResponseStatus( value = HttpStatus.NO_CONTENT ) + public void putXmlObject( HttpServletResponse response, HttpServletRequest request, @PathVariable( "uid" ) String uid, InputStream input ) throws Exception { List objects = getEntity( uid ); @@ -323,9 +327,9 @@ renderService.toXml( response.getOutputStream(), summary ); } - @RequestMapping(value = "/{uid}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void putJsonObject( HttpServletResponse response, HttpServletRequest request, @PathVariable("uid") String uid, InputStream + @RequestMapping( value = "/{uid}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE ) + @ResponseStatus( value = HttpStatus.NO_CONTENT ) + public void putJsonObject( HttpServletResponse response, HttpServletRequest request, @PathVariable( "uid" ) String uid, InputStream input ) throws Exception { List objects = getEntity( uid ); @@ -352,9 +356,9 @@ // DELETE //-------------------------------------------------------------------------- - @RequestMapping(value = "/{uid}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void deleteObject( HttpServletResponse response, HttpServletRequest request, @PathVariable("uid") String uid ) throws + @RequestMapping( value = "/{uid}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE ) + @ResponseStatus( value = HttpStatus.NO_CONTENT ) + public void deleteObject( HttpServletResponse response, HttpServletRequest request, @PathVariable( "uid" ) String uid ) throws Exception { List objects = getEntity( uid ); @@ -504,7 +508,7 @@ private String entitySimpleName; - @SuppressWarnings("unchecked") + @SuppressWarnings( "unchecked" ) protected Class getEntityClass() { if ( entityClass == null ) @@ -536,7 +540,7 @@ return entitySimpleName; } - @SuppressWarnings("unchecked") + @SuppressWarnings( "unchecked" ) protected T getEntityInstance() { try