← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 11879: added custom PathExtensionContentNegotiationStrategy that supports extensions with multiple dots....

 

------------------------------------------------------------
revno: 11879
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2013-09-03 15:47:49 +0200
message:
  added custom PathExtensionContentNegotiationStrategy that supports extensions with multiple dots. Added support for .xml.gz and .json.gz for all meta-data.
added:
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/CustomPathExtensionContentNegotiationStrategy.java
modified:
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonJsonView.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonXmlView.java
  dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml


--
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
=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/CustomPathExtensionContentNegotiationStrategy.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/CustomPathExtensionContentNegotiationStrategy.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/CustomPathExtensionContentNegotiationStrategy.java	2013-09-03 13:47:49 +0000
@@ -0,0 +1,103 @@
+package org.hisp.dhis.api.view;
+
+/*
+ * Copyright (c) 2004-2013, 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.springframework.http.MediaType;
+import org.springframework.util.StringUtils;
+import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.util.UrlPathHelper;
+import org.springframework.web.util.WebUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Custom PathExtensionContentNegotiationStrategy that handles multiple dots in filename.
+ * Based on:
+ * org.springframework.web.accept.PathExtensionContentNegotiationStrategy
+ * org.springframework.util.StringUtils
+ *
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class CustomPathExtensionContentNegotiationStrategy extends PathExtensionContentNegotiationStrategy
+{
+    private static final UrlPathHelper urlPathHelper = new UrlPathHelper();
+
+    static
+    {
+        urlPathHelper.setUrlDecode( false );
+    }
+
+    public CustomPathExtensionContentNegotiationStrategy( Map<String, MediaType> mediaTypes )
+    {
+        super( mediaTypes );
+    }
+
+    @Override
+    protected String getMediaTypeKey( NativeWebRequest webRequest )
+    {
+        HttpServletRequest servletRequest = webRequest.getNativeRequest( HttpServletRequest.class );
+
+        if ( servletRequest == null )
+        {
+            return null;
+        }
+
+        String path = urlPathHelper.getLookupPathForRequest( servletRequest );
+        String filename = WebUtils.extractFullFilenameFromUrlPath( path );
+        String extension = getFilenameExtension( filename );
+        return (StringUtils.hasText( extension )) ? extension.toLowerCase( Locale.ENGLISH ) : null;
+    }
+
+    private static final char EXTENSION_SEPARATOR = '.';
+
+    private static final String FOLDER_SEPARATOR = "/";
+
+    public static String getFilenameExtension( String path )
+    {
+        if ( path == null )
+        {
+            return null;
+        }
+        int extIndex = path.indexOf( EXTENSION_SEPARATOR );
+        if ( extIndex == -1 )
+        {
+            return null;
+        }
+        int folderIndex = path.indexOf( FOLDER_SEPARATOR );
+        if ( folderIndex > extIndex )
+        {
+            return null;
+        }
+        return path.substring( extIndex + 1 );
+    }
+
+}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonJsonView.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonJsonView.java	2013-08-23 16:00:30 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonJsonView.java	2013-09-03 13:47:49 +0000
@@ -29,12 +29,16 @@
  */
 
 import com.fasterxml.jackson.databind.util.JSONPObject;
+import org.hisp.dhis.api.utils.ContextUtils;
 import org.hisp.dhis.dxf2.utils.JacksonUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.servlet.view.AbstractView;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
 import java.util.Map;
+import java.util.zip.GZIPOutputStream;
 
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
@@ -44,30 +48,54 @@
 {
     private static String CONTENT_TYPE_APPLICATION_JSON = "application/json";
 
+    private static String CONTENT_TYPE_APPLICATION_JSON_GZIP = "application/json+gzip";
+
     private static String CONTENT_TYPE_APPLICATION_JAVASCRIPT = "application/javascript";
 
+    private static String CONTENT_TYPE_APPLICATION_JAVASCRIPT_GZIP = "application/javascript+gzip";
+
     private boolean withPadding = false;
 
+    private boolean withCompression = false;
+
     private String callbackParameter = "callback";
 
     private String paddingFunction = "callback";
 
+    @Autowired
+    private ContextUtils contextUtils;
+
     public JacksonJsonView()
     {
         setContentType( CONTENT_TYPE_APPLICATION_JSON );
     }
 
-    public JacksonJsonView( boolean withPadding )
+    public JacksonJsonView( boolean withPadding, boolean withCompression )
     {
         this.withPadding = withPadding;
+        this.withCompression = withCompression;
 
         if ( !withPadding )
         {
-            setContentType( CONTENT_TYPE_APPLICATION_JSON );
+            if ( !withCompression )
+            {
+                setContentType( CONTENT_TYPE_APPLICATION_JSON );
+            }
+            else
+            {
+                setContentType( CONTENT_TYPE_APPLICATION_JSON_GZIP );
+            }
         }
         else
         {
-            setContentType( CONTENT_TYPE_APPLICATION_JAVASCRIPT );
+            if ( !withCompression )
+            {
+                setContentType( CONTENT_TYPE_APPLICATION_JAVASCRIPT );
+            }
+            else
+            {
+                setContentType( CONTENT_TYPE_APPLICATION_JAVASCRIPT_GZIP );
+            }
         }
     }
 
@@ -81,6 +109,11 @@
         this.paddingFunction = paddingFunction;
     }
 
+    public void setWithCompression( boolean withCompression )
+    {
+        this.withCompression = withCompression;
+    }
+
     @Override
     protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request,
         HttpServletResponse response ) throws Exception
@@ -89,6 +122,19 @@
         Class<?> viewClass = JacksonUtils.getViewClass( model.get( "viewClass" ) );
         response.setContentType( getContentType() + "; charset=UTF-8" );
 
+        OutputStream outputStream;
+
+        if ( !withCompression )
+        {
+            outputStream = response.getOutputStream();
+        }
+        else
+        {
+            response.setContentType( ContextUtils.CONTENT_TYPE_GZIP );
+            response.addHeader( ContextUtils.HEADER_CONTENT_TRANSFER_ENCODING, "binary" );
+            outputStream = new GZIPOutputStream( response.getOutputStream() );
+        }
+
         if ( withPadding )
         {
             String callback = request.getParameter( callbackParameter );
@@ -103,11 +149,11 @@
 
         if ( viewClass != null )
         {
-            JacksonUtils.toJsonWithView( response.getOutputStream(), object, viewClass );
+            JacksonUtils.toJsonWithView( outputStream, object, viewClass );
         }
         else
         {
-            JacksonUtils.toJson( response.getOutputStream(), object );
+            JacksonUtils.toJson( outputStream, object );
         }
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonXmlView.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonXmlView.java	2013-08-23 16:00:30 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/view/JacksonXmlView.java	2013-09-03 13:47:49 +0000
@@ -29,12 +29,16 @@
  */
 
 
+import org.hisp.dhis.api.utils.ContextUtils;
 import org.hisp.dhis.dxf2.utils.JacksonUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.servlet.view.AbstractView;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
 import java.util.Map;
+import java.util.zip.GZIPOutputStream;
 
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
@@ -44,11 +48,37 @@
 {
     private static String CONTENT_TYPE_APPLICATION_XML = "application/xml";
 
+    private static String CONTENT_TYPE_APPLICATION_XML_GZIP = "application/xml+gzip";
+
+    private boolean withCompression = false;
+
+    @Autowired
+    private ContextUtils contextUtils;
+
     public JacksonXmlView()
     {
         setContentType( CONTENT_TYPE_APPLICATION_XML );
     }
 
+    public JacksonXmlView( boolean withCompression )
+    {
+        this.withCompression = withCompression;
+
+        if ( !withCompression )
+        {
+            setContentType( CONTENT_TYPE_APPLICATION_XML );
+        }
+        else
+        {
+            setContentType( CONTENT_TYPE_APPLICATION_XML_GZIP );
+        }
+    }
+
+    public void setWithCompression( boolean withCompression )
+    {
+        this.withCompression = withCompression;
+    }
+
     @Override
     protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request,
         HttpServletResponse response ) throws Exception
@@ -58,13 +88,26 @@
         response.setContentType( getContentType() + "; charset=UTF-8" );
         response.setStatus( HttpServletResponse.SC_OK );
 
+        OutputStream outputStream;
+
+        if ( !withCompression )
+        {
+            outputStream = response.getOutputStream();
+        }
+        else
+        {
+            response.setContentType( ContextUtils.CONTENT_TYPE_GZIP );
+            response.addHeader( ContextUtils.HEADER_CONTENT_TRANSFER_ENCODING, "binary" );
+            outputStream = new GZIPOutputStream( response.getOutputStream() );
+        }
+
         if ( viewClass != null )
         {
-            JacksonUtils.toXmlWithView( response.getOutputStream(), object, viewClass );
+            JacksonUtils.toXmlWithView( outputStream, object, viewClass );
         }
         else
         {
-            JacksonUtils.toXml( response.getOutputStream(), object );
+            JacksonUtils.toXml( outputStream, object );
         }
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml'
--- dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml	2013-07-22 11:18:51 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml	2013-09-03 13:47:49 +0000
@@ -25,17 +25,19 @@
 
   <bean id="headerContentNegotiationStrategy" class="org.springframework.web.accept.HeaderContentNegotiationStrategy" />
 
-  <bean id="pathExtensionContentNegotiationStrategy" class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
+  <bean id="pathExtensionContentNegotiationStrategy" class="org.hisp.dhis.api.view.CustomPathExtensionContentNegotiationStrategy">
     <constructor-arg name="mediaTypes">
       <map>
-        <entry key="html" value="text/html" />
         <entry key="json" value="application/json" />
+        <entry key="json.gz" value="application/json+gzip" />
         <entry key="jsonp" value="application/javascript" />
         <entry key="xml" value="application/xml" />
+        <entry key="xml.gz" value="application/xml+gzip" />
         <entry key="png" value="image/png" />
         <entry key="pdf" value="application/pdf" />
         <entry key="xls" value="application/vnd.ms-excel" />
         <entry key="csv" value="application/csv" />
+        <entry key="html" value="text/html" />
       </map>
     </constructor-arg>
   </bean>
@@ -56,12 +58,32 @@
 
     <property name="defaultViews">
       <list>
-        <bean class="org.hisp.dhis.api.view.JacksonXmlView" />
-
-        <bean class="org.hisp.dhis.api.view.JacksonJsonView" />
-
-        <bean class="org.hisp.dhis.api.view.JacksonJsonView">
-          <constructor-arg name="withPadding" value="true" />
+        <bean class="org.hisp.dhis.api.view.JacksonXmlView">
+          <constructor-arg name="withCompression" value="false" />
+        </bean>
+
+        <bean class="org.hisp.dhis.api.view.JacksonXmlView">
+          <constructor-arg name="withCompression" value="true" />
+        </bean>
+
+        <bean class="org.hisp.dhis.api.view.JacksonJsonView">
+          <constructor-arg name="withPadding" value="false" />
+          <constructor-arg name="withCompression" value="false" />
+        </bean>
+
+        <bean class="org.hisp.dhis.api.view.JacksonJsonView">
+          <constructor-arg name="withPadding" value="false" />
+          <constructor-arg name="withCompression" value="true" />
+        </bean>
+
+        <bean class="org.hisp.dhis.api.view.JacksonJsonView">
+          <constructor-arg name="withPadding" value="true" />
+          <constructor-arg name="withCompression" value="false" />
+        </bean>
+
+        <bean class="org.hisp.dhis.api.view.JacksonJsonView">
+          <constructor-arg name="withPadding" value="true" />
+          <constructor-arg name="withCompression" value="true" />
         </bean>
 
         <bean class="org.hisp.dhis.api.view.PdfGridView" />