dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #36478
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 18657: wip, support partial update of object (PATCH)
------------------------------------------------------------
revno: 18657
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2015-03-23 12:42:24 +0700
message:
wip, support partial update of object (PATCH)
modified:
dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/DefaultRenderService.java
dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/RenderService.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-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/DefaultRenderService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/DefaultRenderService.java 2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/DefaultRenderService.java 2015-03-23 05:42:24 +0000
@@ -104,6 +104,12 @@
}
@Override
+ public <T> T fromJson( String input, Class<T> klass ) throws IOException
+ {
+ return jsonMapper.readValue( input, klass );
+ }
+
+ @Override
public <T> void toXml( OutputStream output, T value ) throws IOException
{
xmlMapper.writeValue( output, value );
@@ -121,10 +127,26 @@
return xmlMapper.readValue( input, klass );
}
+ @Override
+ public <T> T fromXml( String input, Class<T> klass ) throws IOException
+ {
+ return xmlMapper.readValue( input, klass );
+ }
+
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
+ public ObjectMapper getJsonMapper()
+ {
+ return jsonMapper;
+ }
+
+ public XmlMapper getXmlMapper()
+ {
+ return xmlMapper;
+ }
+
private void configureObjectMappers()
{
ObjectMapper[] objectMappers = new ObjectMapper[]{ jsonMapper, xmlMapper };
=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/RenderService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/RenderService.java 2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/render/RenderService.java 2015-03-23 05:42:24 +0000
@@ -47,9 +47,13 @@
<T> T fromJson( InputStream input, Class<T> klass ) throws IOException;
+ <T> T fromJson( String input, Class<T> klass ) throws IOException;
+
<T> void toXml( OutputStream output, T value ) throws IOException;
<T> void toXml( OutputStream output, T value, Class<?> klass ) throws IOException;
<T> T fromXml( InputStream input, Class<T> klass ) throws IOException;
+
+ <T> T fromXml( String input, Class<T> klass ) throws IOException;
}
=== 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 2015-03-20 03:00:33 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractCrudController.java 2015-03-23 05:42:24 +0000
@@ -28,6 +28,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.google.common.base.Enums;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
@@ -47,6 +50,7 @@
import org.hisp.dhis.dxf2.metadata.ImportService;
import org.hisp.dhis.dxf2.metadata.ImportTypeSummary;
import org.hisp.dhis.dxf2.objectfilter.ObjectFilterService;
+import org.hisp.dhis.dxf2.render.DefaultRenderService;
import org.hisp.dhis.dxf2.render.RenderService;
import org.hisp.dhis.hibernate.exception.CreateAccessDeniedException;
import org.hisp.dhis.hibernate.exception.DeleteAccessDeniedException;
@@ -76,6 +80,7 @@
import org.hisp.dhis.webapi.webdomain.WebOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
+import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -88,6 +93,7 @@
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -235,6 +241,86 @@
return getObjectInternal( pvUid, rpParameters, Lists.<String>newArrayList(), Lists.newArrayList( pvProperty + fieldFilter ), translateOptions );
}
+ @RequestMapping( value = "/{uid}", method = RequestMethod.PATCH )
+ public void partialUpdateObject(
+ @PathVariable( "uid" ) String pvUid, @RequestParam Map<String, String> rpParameters,
+ HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ WebOptions options = new WebOptions( rpParameters );
+ List<T> entities = getEntity( pvUid, options );
+
+ if ( entities.isEmpty() )
+ {
+ ContextUtils.notFoundResponse( response, getEntityName() + " does not exist: " + pvUid );
+ return;
+ }
+
+ T persistedObject = entities.get( 0 );
+
+ if ( !aclService.canUpdate( currentUserService.getCurrentUser(), persistedObject ) )
+ {
+ throw new UpdateAccessDeniedException( "You don't have the proper permissions to update this object." );
+ }
+
+ String payload = StreamUtils.copyToString( request.getInputStream(), Charset.forName( "UTF-8" ) );
+ List<String> properties = new ArrayList<>();
+ T object = null;
+
+ if ( isJson( request ) )
+ {
+ properties = getJsonProperties( payload );
+ object = renderService.fromJson( payload, getEntityClass() );
+ }
+ else if ( isXml( request ) )
+ {
+ properties = getXmlProperties( payload );
+ object = renderService.fromXml( payload, getEntityClass() );
+ }
+
+ properties = getPersistedProperties( properties );
+
+ if ( properties.isEmpty() || object == null )
+ {
+ response.setStatus( HttpServletResponse.SC_NO_CONTENT );
+ return;
+ }
+
+ response.setStatus( HttpServletResponse.SC_NO_CONTENT );
+ }
+
+ private List<String> getJsonProperties( String payload ) throws IOException
+ {
+ ObjectMapper mapper = ((DefaultRenderService) renderService).getJsonMapper();
+ JsonNode root = mapper.readTree( payload );
+
+ return Lists.newArrayList( root.fieldNames() );
+ }
+
+ private List<String> getXmlProperties( String payload ) throws IOException
+ {
+ XmlMapper mapper = ((DefaultRenderService) renderService).getXmlMapper();
+ JsonNode root = mapper.readTree( payload );
+
+ return Lists.newArrayList( root.fieldNames() );
+ }
+
+ private List<String> getPersistedProperties( List<String> properties )
+ {
+ List<String> persistedProperties = new ArrayList<>();
+
+ Schema schema = getSchema();
+
+ for ( String property : properties )
+ {
+ if ( schema.havePersistedProperty( property ) )
+ {
+ persistedProperties.add( property );
+ }
+ }
+
+ return persistedProperties;
+ }
+
@RequestMapping( value = "/{uid}/{property}", method = { RequestMethod.PUT, RequestMethod.PATCH } )
public void updateObjectProperty(
@PathVariable( "uid" ) String pvUid, @PathVariable( "property" ) String pvProperty, @RequestParam Map<String, String> rpParameters,
@@ -952,7 +1038,16 @@
*/
protected boolean isJson( HttpServletRequest request )
{
- return isCompatibleWith( request.getContentType(), MediaType.APPLICATION_JSON );
+ String type = request.getContentType();
+ type = !StringUtils.isEmpty( type ) ? type : MediaType.APPLICATION_JSON_VALUE;
+
+ // allow type to be overridden by path extension
+ if ( request.getPathInfo().endsWith( ".json" ) )
+ {
+ type = MediaType.APPLICATION_JSON_VALUE;
+ }
+
+ return isCompatibleWith( type, MediaType.APPLICATION_JSON );
}
/**
@@ -963,7 +1058,16 @@
*/
protected boolean isXml( HttpServletRequest request )
{
- return isCompatibleWith( request.getContentType(), MediaType.APPLICATION_XML );
+ String type = request.getContentType();
+ type = !StringUtils.isEmpty( type ) ? type : MediaType.APPLICATION_JSON_VALUE;
+
+ // allow type to be overridden by path extension
+ if ( request.getPathInfo().endsWith( ".xml" ) )
+ {
+ type = MediaType.APPLICATION_XML_VALUE;
+ }
+
+ return isCompatibleWith( type, MediaType.APPLICATION_XML );
}
protected boolean isCompatibleWith( String type, MediaType mediaType )