← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15526: rewrote filter functionality to use node rendrer system, only supports json for now (but xml is c...

 

------------------------------------------------------------
revno: 15526
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-06-03 00:47:30 +0200
message:
  rewrote filter functionality to use node rendrer system, only supports json for now (but xml is coming soon)
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java
  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/FilterService.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.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/node/AbstractNode.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java	2014-06-01 14:30:40 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java	2014-06-02 22:47:30 +0000
@@ -69,6 +69,11 @@
     @Override
     public <T extends Node> T addNode( T node ) throws InvalidTypeException
     {
+        if ( node == null )
+        {
+            return null;
+        }
+
         nodes.add( node );
         return node;
     }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java	2014-05-31 23:48:24 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/exception/InvalidTypeException.java	2014-06-02 22:47:30 +0000
@@ -31,7 +31,7 @@
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
-public class InvalidTypeException extends Exception
+public class InvalidTypeException extends RuntimeException
 {
     public InvalidTypeException( String message )
     {

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java	2014-06-01 12:21:14 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java	2014-06-02 22:47:30 +0000
@@ -28,8 +28,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  */
 
-import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import org.hisp.dhis.node.Node;
 import org.hisp.dhis.node.NodeSerializer;
 import org.hisp.dhis.node.types.CollectionNode;
@@ -49,7 +51,7 @@
 {
     public static final String CONTENT_TYPE = "application/json";
 
-    private final JsonFactory jsonFactory = new JsonFactory();
+    private final ObjectMapper objectMapper = new ObjectMapper();
 
     @Override
     public String contentType()
@@ -59,13 +61,17 @@
 
     public JacksonJsonNodeSerializer()
     {
-
+        objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL );
+        objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
+        objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false );
+        objectMapper.configure( SerializationFeature.WRAP_EXCEPTIONS, true );
+        objectMapper.getFactory().enable( JsonGenerator.Feature.QUOTE_FIELD_NAMES );
     }
 
     @Override
     public void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException
     {
-        JsonGenerator generator = jsonFactory.createGenerator( outputStream );
+        JsonGenerator generator = objectMapper.getFactory().createGenerator( outputStream );
 
         renderRootNode( rootNode, generator );
         generator.flush();
@@ -86,6 +92,11 @@
 
     private void renderSimpleNode( SimpleNode simpleNode, JsonGenerator generator, boolean writeKey ) throws IOException
     {
+        if ( simpleNode.getValue() == null ) // add hint for this, exclude if null
+        {
+            return;
+        }
+
         if ( writeKey )
         {
             generator.writeObjectField( simpleNode.getName(), simpleNode.getValue() );

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java	2014-06-01 12:21:14 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java	2014-06-02 22:47:30 +0000
@@ -94,6 +94,11 @@
 
     private void renderSimpleNode( SimpleNode simpleNode, XMLStreamWriter writer ) throws XMLStreamException
     {
+        if ( simpleNode.getValue() == null ) // add hint for this, exclude if null
+        {
+            return;
+        }
+
         String value = String.format( "%s", simpleNode.getValue() );
 
         writeStartElement( simpleNode, writer );
@@ -103,6 +108,11 @@
 
     private void renderSimpleNodeAttribute( SimpleNode simpleNode, XMLStreamWriter writer ) throws XMLStreamException
     {
+        if ( simpleNode.getValue() == null ) // add hint for this, exclude if null
+        {
+            return;
+        }
+
         String value = String.format( "%s", simpleNode.getValue() );
 
         if ( simpleNode.haveHint( NodeHint.Type.XML_NAMESPACE ) )

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java	2014-06-02 21:00:27 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/schema/DefaultSchemaService.java	2014-06-02 22:47:30 +0000
@@ -30,7 +30,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import javassist.util.proxy.ProxyFactory;
+import org.hisp.dhis.system.util.ReflectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.OrderComparator;
 
@@ -80,10 +80,7 @@
             return null;
         }
 
-        if ( ProxyFactory.isProxyClass( klass ) )
-        {
-            klass = klass.getSuperclass();
-        }
+        klass = ReflectionUtils.getRealClass( klass );
 
         if ( classSchemaMap.containsKey( klass ) )
         {
@@ -108,6 +105,8 @@
             return schema;
         }
 
+        klass = ReflectionUtils.getRealClass( klass );
+
         schema = new Schema( klass, klass.getName(), klass.getName() );
         schema.setPropertyMap( propertyIntrospectorService.getPropertiesMap( schema.getKlass() ) );
 

=== modified 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-02 21:35:16 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/DefaultFilterService.java	2014-06-02 22:47:30 +0000
@@ -32,6 +32,9 @@
 import com.google.common.collect.Maps;
 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;
@@ -80,13 +83,15 @@
     }
 
     @Override
-    public <T extends IdentifiableObject> List<Object> filterProperties( List<T> objects, String include, String exclude )
+    public <T extends IdentifiableObject> CollectionNode filterProperties( Class<?> klass, List<T> objects,
+        String include, String exclude )
     {
-        List<Object> output = Lists.newArrayList();
+        Schema rootSchema = schemaService.getDynamicSchema( klass );
+        CollectionNode collectionNode = new CollectionNode( rootSchema.getPlural() ); // replace with 'xml' collection name
 
         if ( objects.isEmpty() )
         {
-            return output;
+            return collectionNode;
         }
 
         Map<String, Map> fieldMap = Maps.newHashMap();
@@ -118,22 +123,22 @@
 
         for ( Object object : objects )
         {
-            output.add( buildObjectOutput( object, fieldMap ) );
+            collectionNode.addNode( buildObjectOutput( fieldMap, object ) );
         }
 
-        return output;
+        return collectionNode;
     }
 
     @SuppressWarnings( "unchecked" )
-    private Map<String, Object> buildObjectOutput( Object object, Map<String, Map> fieldMap )
+    private ComplexNode buildObjectOutput( Map<String, Map> fieldMap, Object object )
     {
         if ( object == null )
         {
             return null;
         }
 
-        Map<String, Object> output = Maps.newHashMap();
         Schema schema = schemaService.getDynamicSchema( object.getClass() );
+        ComplexNode complexNode = new ComplexNode( schema.getSingular() );
 
         for ( String fieldKey : fieldMap.keySet() )
         {
@@ -156,58 +161,62 @@
             {
                 if ( !property.isIdentifiableObject() )
                 {
-                    output.put( fieldKey, returnValue );
+                    complexNode.addNode( new SimpleNode( fieldKey, returnValue ) );
                 }
                 else if ( !property.isCollection() )
                 {
-                    output.put( fieldKey, getIdentifiableObjectProperties( returnValue ) );
+                    complexNode.addNode( getIdentifiableObjectProperties( returnValue, IDENTIFIABLE_PROPERTIES ) );
                 }
                 else
                 {
-                    output.put( fieldKey, getIdentifiableObjectCollectionProperties( returnValue ) );
+                    complexNode.addNode( getIdentifiableObjectCollectionProperties( returnValue, IDENTIFIABLE_PROPERTIES, fieldKey ) );
                 }
             }
             else
             {
                 if ( property.isCollection() )
                 {
-                    List<Object> list = Lists.newArrayList();
-                    output.put( fieldKey, list );
+                    CollectionNode collectionNode = complexNode.addNode( new CollectionNode( property.getXmlCollectionName() ) );
 
-                    for ( Object obj : (Collection<?>) returnValue )
+                    for ( Object collectionObject : (Collection<?>) returnValue )
                     {
-                        Map<String, Object> properties = buildObjectOutput( obj, fieldValue );
+                        ComplexNode node = buildObjectOutput( fieldValue, collectionObject );
 
-                        if ( !properties.isEmpty() )
+                        if ( !node.getNodes().isEmpty() )
                         {
-                            list.add( properties );
+                            collectionNode.addNode( node );
                         }
                     }
                 }
                 else
                 {
-                    Map<String, Object> map = buildObjectOutput( returnValue, fieldValue );
+                    ComplexNode node = buildObjectOutput( fieldValue, returnValue );
 
-                    if ( !map.isEmpty() )
+                    if ( !node.getNodes().isEmpty() )
                     {
-                        output.put( fieldKey, map );
+                        complexNode.addNode( node );
                     }
                 }
             }
         }
 
-        return output;
-    }
-
-    private List<Map<String, Object>> getIdentifiableObjectCollectionProperties( Object object )
-    {
-        return getIdentifiableObjectCollectionProperties( object, IDENTIFIABLE_PROPERTIES );
+        return complexNode;
     }
 
     @SuppressWarnings( "unchecked" )
-    private List<Map<String, Object>> getIdentifiableObjectCollectionProperties( Object object, List<String> fields )
+    private CollectionNode getIdentifiableObjectCollectionProperties( Object object, List<String> fields, String collectionName )
     {
-        List<Map<String, Object>> output = Lists.newArrayList();
+        if ( object == null )
+        {
+            return null;
+        }
+
+        if ( !Collection.class.isInstance( object ) )
+        {
+            return null;
+        }
+
+        CollectionNode collectionNode = new CollectionNode( collectionName );
         Collection<IdentifiableObject> identifiableObjects;
 
         try
@@ -217,28 +226,33 @@
         catch ( ClassCastException ex )
         {
             ex.printStackTrace();
-            return output;
+            return collectionNode;
         }
 
         for ( IdentifiableObject identifiableObject : identifiableObjects )
         {
-            Map<String, Object> properties = getIdentifiableObjectProperties( identifiableObject, fields );
-            output.add( properties );
-        }
-
-        return output;
-    }
-
-    private Map<String, Object> getIdentifiableObjectProperties( Object object )
-    {
-        return getIdentifiableObjectProperties( object, IDENTIFIABLE_PROPERTIES );
-    }
-
-    private Map<String, Object> getIdentifiableObjectProperties( Object object, List<String> fields )
-    {
-        Map<String, Object> map = Maps.newLinkedHashMap();
+            collectionNode.addNode( getIdentifiableObjectProperties( identifiableObject, fields ) );
+        }
+
+        return collectionNode;
+    }
+
+    private ComplexNode getIdentifiableObjectProperties( Object object, List<String> fields )
+    {
+        if ( object == null )
+        {
+            return null;
+        }
+
+        if ( !IdentifiableObject.class.isInstance( object ) )
+        {
+            return null;
+        }
+
         Schema schema = schemaService.getDynamicSchema( object.getClass() );
 
+        ComplexNode complexNode = new ComplexNode( schema.getSingular() );
+
         for ( String field : fields )
         {
             Property property = schema.getPropertyMap().get( field );
@@ -252,11 +266,11 @@
 
             if ( o != null )
             {
-                map.put( field, o );
+                complexNode.addNode( new SimpleNode( field, o ) );
             }
         }
 
-        return map;
+        return complexNode;
     }
 
     @SuppressWarnings( "unchecked" )
@@ -268,7 +282,6 @@
         {
             if ( !schema.getPropertyMap().containsKey( field ) )
             {
-                System.err.println( "Skipping non-existent field: " + field );
                 continue;
             }
 

=== modified 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-04-14 06:43:16 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/filter/FilterService.java	2014-06-02 22:47:30 +0000
@@ -29,6 +29,7 @@
  */
 
 import org.hisp.dhis.common.IdentifiableObject;
+import org.hisp.dhis.node.types.CollectionNode;
 
 import java.util.List;
 
@@ -54,5 +55,6 @@
      * @param exclude Exclusion filter
      * @return List of objects with only wanted properties
      */
-    <T extends IdentifiableObject> List<Object> filterProperties( List<T> objects, String include, String exclude );
+    <T extends IdentifiableObject> CollectionNode filterProperties( Class<?> klass, List<T> objects,
+        String include, String exclude );
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java	2014-03-26 11:32:35 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/ReflectionUtils.java	2014-06-02 22:47:30 +0000
@@ -28,6 +28,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import javassist.util.proxy.ProxyFactory;
+import org.hibernate.collection.spi.PersistentCollection;
 import org.hisp.dhis.system.util.functional.Function1;
 import org.hisp.dhis.system.util.functional.Predicate;
 import org.springframework.util.StringUtils;
@@ -497,4 +499,19 @@
             throw new RuntimeException( "Unknown Collection type." );
         }
     }
+
+    public static Class<?> getRealClass( Class<?> klass )
+    {
+        if ( ProxyFactory.isProxyClass( klass ) )
+        {
+            klass = klass.getSuperclass();
+        }
+
+        while ( PersistentCollection.class.isAssignableFrom( klass ) )
+        {
+            klass = klass.getSuperclass();
+        }
+
+        return klass;
+    }
 }

=== 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-02 19:07:47 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java	2014-06-02 22:47:30 +0000
@@ -29,7 +29,6 @@
  */
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import org.hisp.dhis.acl.Access;
 import org.hisp.dhis.acl.AclService;
 import org.hisp.dhis.common.BaseIdentifiableObject;
@@ -46,6 +45,10 @@
 import org.hisp.dhis.hibernate.exception.DeleteAccessDeniedException;
 import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException;
 import org.hisp.dhis.importexport.ImportStrategy;
+import org.hisp.dhis.node.NodeService;
+import org.hisp.dhis.node.types.ComplexNode;
+import org.hisp.dhis.node.types.RootNode;
+import org.hisp.dhis.node.types.SimpleNode;
 import org.hisp.dhis.schema.Schema;
 import org.hisp.dhis.schema.SchemaService;
 import org.hisp.dhis.system.util.ReflectionUtils;
@@ -106,6 +109,9 @@
     @Autowired
     protected ImportService importService;
 
+    @Autowired
+    protected NodeService nodeService;
+
     //--------------------------------------------------------------------------
     // GET
     //--------------------------------------------------------------------------
@@ -204,24 +210,21 @@
         // enable property filter
         if ( include != null || exclude != null )
         {
-            List<Object> objects = filterService.filterProperties( entityList, include, exclude );
-            Map<String, Object> output = Maps.newLinkedHashMap();
+            RootNode rootNode = new RootNode( "metadata" );
 
             if ( hasPaging )
             {
-                output.put( "pager", metaData.getPager() );
-            }
-
-            if ( schema != null )
-            {
-                output.put( schema.getPlural(), objects );
-            }
-            else
-            {
-                output.put( "objects", objects );
-            }
-
-            renderService.toJson( response.getOutputStream(), output );
+                ComplexNode pagerNode = rootNode.addNode( new ComplexNode( "pager" ) );
+                pagerNode.addNode( new SimpleNode( "page", metaData.getPager().getPage() ) );
+                pagerNode.addNode( new SimpleNode( "pageCount", metaData.getPager().getPageCount() ) );
+                pagerNode.addNode( new SimpleNode( "total", metaData.getPager().getTotal() ) );
+                pagerNode.addNode( new SimpleNode( "nextPage", metaData.getPager().getNextPage() ) );
+                pagerNode.addNode( new SimpleNode( "prevPage", metaData.getPager().getPrevPage() ) );
+            }
+
+            rootNode.addNode( filterService.filterProperties( getEntityClass(), entityList, include, exclude ) );
+
+            nodeService.serialize( rootNode, "application/json", response.getOutputStream() );
         }
         else
         {