← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16067: Impl support for putting analytics engine/Web API in maintenance mode. This implies that all requ...

 

------------------------------------------------------------
revno: 16067
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2014-07-10 12:27:53 +0200
message:
  Impl support for putting analytics engine/Web API in maintenance mode. This implies that all requests should return 503 Service unavailable, and avoid that the request executes a database query. This is useful when you need to do maintenance or re-run the analytics tables on a live system without taking down the entire system / allowing users to do perform other functions like data entry.
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MaintenanceModeException.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AnalyticsController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CrudControllerAdvice.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAnalyticsController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/utils/ContextUtils.java
  dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetGeneralSettingsAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemGeneralSettings.vm


--
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-api/src/main/java/org/hisp/dhis/common/MaintenanceModeException.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MaintenanceModeException.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MaintenanceModeException.java	2014-07-10 10:27:53 +0000
@@ -0,0 +1,41 @@
+package org.hisp.dhis.common;
+
+/*
+ * 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.
+ */
+
+/**
+ * @author Lars Helge Overland
+ */
+public class MaintenanceModeException
+    extends RuntimeException
+{
+    public MaintenanceModeException( String message )
+    {
+        super( message );
+    }
+}

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2014-06-26 14:38:54 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/setting/SystemSettingManager.java	2014-07-10 10:27:53 +0000
@@ -97,6 +97,7 @@
     final String KEY_ANALYTICS_MAX_LIMIT = "keyAnalyticsMaxLimit";
     final String KEY_CUSTOM_LOGIN_PAGE_LOGO = "keyCustomLoginPageLogo";
     final String KEY_CUSTOM_TOP_MENU_LOGO = "keyCustomTopMenuLogo";
+    final String KEY_ANALYTICS_MAINTENANCE_MODE = "keyAnalyticsMaintenanceMode";
 
     final String DEFAULT_SCHEDULE_AGGREGATE_QUERY_BUILDER_TASK_STRATEGY = "lastMonth";
     final String DEFAULT_FLAG = "dhis2";

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java	2014-04-14 08:42:46 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java	2014-07-10 10:27:53 +0000
@@ -31,6 +31,7 @@
 import java.util.List;
 
 import org.hisp.dhis.common.IllegalQueryException;
+import org.hisp.dhis.common.MaintenanceModeException;
 
 /**
  * @author Lars Helge Overland
@@ -62,6 +63,14 @@
         throws IllegalQueryException;
     
     /**
+     * Checks whether the analytics engine is in maintenance mode.
+     * 
+     * @throws MaintenanceModeException if analytics engine is in maintenance mode.
+     */
+    void validateMaintenanceMode()
+        throws MaintenanceModeException;
+    
+    /**
      * Creates a DataQueryGroups object. It is mandatory to group the queries by
      * the following criteria: 1) partition / year 2) organisation  unit level
      * 3) period type 4) aggregation type. The DataQueryGroups contains groups of 

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2014-07-02 11:08:10 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2014-07-10 10:27:53 +0000
@@ -640,6 +640,8 @@
      */
     private Map<String, Double> getAggregatedValueMap( DataQueryParams params, String tableName )        
     {
+        queryPlanner.validateMaintenanceMode();
+        
         int optimalQueries = MathUtils.getWithin( SystemUtils.getCpuCores(), 1, MAX_QUERIES );
         
         Timer t = new Timer().start();

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java	2014-06-18 15:37:44 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java	2014-07-10 10:27:53 +0000
@@ -69,6 +69,7 @@
 import org.hisp.dhis.common.DimensionalObject;
 import org.hisp.dhis.common.IllegalQueryException;
 import org.hisp.dhis.common.ListMap;
+import org.hisp.dhis.common.MaintenanceModeException;
 import org.hisp.dhis.common.NameableObject;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementGroup;
@@ -205,6 +206,17 @@
         }
     }
     
+    public void validateMaintenanceMode()
+        throws MaintenanceModeException
+    {
+        boolean maintenance = (Boolean) systemSettingManager.getSystemSetting( SystemSettingManager.KEY_ANALYTICS_MAINTENANCE_MODE, false );
+        
+        if ( maintenance )
+        {
+            throw new MaintenanceModeException( "Analytics engine is in maintenanec mode, try again later" );
+        }
+    }
+    
     public DataQueryGroups planQuery( DataQueryParams params, int optimalQueries, String tableName )
     {
         validate( params );

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java	2014-04-19 07:47:34 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java	2014-07-10 10:27:53 +0000
@@ -31,6 +31,7 @@
 import java.util.List;
 
 import org.hisp.dhis.common.IllegalQueryException;
+import org.hisp.dhis.common.MaintenanceModeException;
 
 /**
  * @author Lars Helge Overland
@@ -38,8 +39,8 @@
 public interface EventQueryPlanner
 {    
     void validate( EventQueryParams params )
-        throws IllegalQueryException;
-    
+        throws IllegalQueryException, MaintenanceModeException;
+        
     /**
      * Plans the given params and returns a list of params.
      * 

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java	2014-04-28 18:23:49 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java	2014-07-10 10:27:53 +0000
@@ -44,6 +44,7 @@
 import org.hisp.dhis.analytics.table.PartitionUtils;
 import org.hisp.dhis.common.DimensionalObject;
 import org.hisp.dhis.common.IllegalQueryException;
+import org.hisp.dhis.common.MaintenanceModeException;
 import org.hisp.dhis.common.NameableObject;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
@@ -78,7 +79,7 @@
 
     @Override
     public void validate( EventQueryParams params )
-        throws IllegalQueryException
+        throws IllegalQueryException, MaintenanceModeException
     {
         String violation = null;
 
@@ -87,6 +88,8 @@
             throw new IllegalQueryException( "Params cannot be null" );
         }
         
+        queryPlanner.validateMaintenanceMode();
+        
         if ( !params.hasOrganisationUnits() )
         {
             violation = "At least one organisation unit must be specified";
@@ -186,6 +189,12 @@
         return params;
     }
     
+    public void validateMaintenanceMode()
+        throws MaintenanceModeException
+    {
+        queryPlanner.validateMaintenanceMode();
+    }
+    
     // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AnalyticsController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AnalyticsController.java	2014-06-11 09:26:41 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AnalyticsController.java	2014-07-10 10:27:53 +0000
@@ -28,11 +28,18 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.analytics.AnalyticsService.NAMES_META_KEY;
+import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionsFromParam;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletResponse;
+
 import org.hisp.dhis.analytics.AggregationType;
 import org.hisp.dhis.analytics.AnalyticsService;
 import org.hisp.dhis.analytics.DataQueryParams;
 import org.hisp.dhis.common.Grid;
-import org.hisp.dhis.common.IllegalQueryException;
 import org.hisp.dhis.i18n.I18nManager;
 import org.hisp.dhis.system.grid.GridUtils;
 import org.hisp.dhis.webapi.utils.ContextUtils;
@@ -40,18 +47,10 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
-import java.util.Set;
-
-import static org.hisp.dhis.analytics.AnalyticsService.NAMES_META_KEY;
-import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionsFromParam;
-
 /**
  * @author Lars Helge Overland
  */
@@ -233,22 +232,6 @@
     }
 
     // -------------------------------------------------------------------------
-    // Exception handling
-    // -------------------------------------------------------------------------
-
-    @ExceptionHandler( IllegalQueryException.class )
-    public void handleError( IllegalQueryException ex, HttpServletResponse response )
-    {
-        ContextUtils.conflictResponse( response, ex.getMessage() );
-    }
-
-    @ExceptionHandler( IllegalArgumentException.class )
-    public void handleError( IllegalArgumentException ex, HttpServletResponse response )
-    {
-        ContextUtils.conflictResponse( response, ex.getMessage() );
-    }
-
-    // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------
 

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CrudControllerAdvice.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CrudControllerAdvice.java	2014-06-12 09:41:31 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CrudControllerAdvice.java	2014-07-10 10:27:53 +0000
@@ -28,8 +28,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import javax.validation.ConstraintViolationException;
+
 import org.hisp.dhis.common.DeleteNotAllowedException;
 import org.hisp.dhis.common.IllegalQueryException;
+import org.hisp.dhis.common.MaintenanceModeException;
 import org.hisp.dhis.webapi.controller.exception.NotAuthenticatedException;
 import org.hisp.dhis.webapi.controller.exception.NotFoundException;
 import org.springframework.http.HttpHeaders;
@@ -42,8 +45,6 @@
 import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.HttpStatusCodeException;
 
-import javax.validation.ConstraintViolationException;
-
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
@@ -53,54 +54,51 @@
     @ExceptionHandler
     public ResponseEntity<String> notAuthenticatedExceptionHandler( NotAuthenticatedException ex )
     {
-        HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getMessage(), headers, HttpStatus.UNAUTHORIZED );
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.UNAUTHORIZED );
     }
 
     @ExceptionHandler( { NotFoundException.class } )
     public ResponseEntity<String> notFoundExceptionHandler( Exception ex )
     {
-        HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getMessage(), headers, HttpStatus.NOT_FOUND );
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.NOT_FOUND );
     }
 
     @ExceptionHandler( { HttpClientErrorException.class, HttpServerErrorException.class } )
     public ResponseEntity<String> httpClient( HttpStatusCodeException ex )
     {
-        HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getStatusText(), headers, ex.getStatusCode() );
+        return new ResponseEntity<>( ex.getStatusText(), getHeaders(), ex.getStatusCode() );
     }
 
     @ExceptionHandler( ConstraintViolationException.class )
     public ResponseEntity<String> constraintViolationExceptionHandler( ConstraintViolationException ex )
     {
-        HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getMessage(), headers, HttpStatus.UNPROCESSABLE_ENTITY );
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.UNPROCESSABLE_ENTITY );
     }
 
     @ExceptionHandler( DeleteNotAllowedException.class )
     public ResponseEntity<String> deleteNotAllowedExceptionHandler( DeleteNotAllowedException ex )
     {
-        HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getMessage(), headers, HttpStatus.CONFLICT );
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.CONFLICT );
     }
 
     @ExceptionHandler( { IllegalQueryException.class, IllegalArgumentException.class } )
-    public ResponseEntity<String> handleError( IllegalQueryException ex )
+    public ResponseEntity<String> illegalQueryArgumentExceptionHandler( IllegalQueryException ex )
+    {
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.CONFLICT );
+    }
+    
+    @ExceptionHandler( { MaintenanceModeException.class } )
+    public ResponseEntity<String> maintenanceModeExceptionHandler( MaintenanceModeException ex )
+    {
+        return new ResponseEntity<>( ex.getMessage(), getHeaders(), HttpStatus.SERVICE_UNAVAILABLE );
+    }
+    
+    private HttpHeaders getHeaders()
     {
         HttpHeaders headers = new HttpHeaders();
-        headers.add( "Content-Type", MediaType.TEXT_PLAIN_VALUE );
-
-        return new ResponseEntity<>( ex.getMessage(), headers, HttpStatus.CONFLICT );
+        headers.setContentType( MediaType.TEXT_PLAIN );
+        headers.setCacheControl( "max-age=0, no-cache, no-store" );
+        return headers;        
     }
 }
+

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAnalyticsController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAnalyticsController.java	2014-06-11 19:35:22 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/EventAnalyticsController.java	2014-07-10 10:27:53 +0000
@@ -28,11 +28,17 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.analytics.AnalyticsService.NAMES_META_KEY;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletResponse;
+
 import org.hisp.dhis.analytics.SortOrder;
 import org.hisp.dhis.analytics.event.EventAnalyticsService;
 import org.hisp.dhis.analytics.event.EventQueryParams;
 import org.hisp.dhis.common.Grid;
-import org.hisp.dhis.common.IllegalQueryException;
 import org.hisp.dhis.i18n.I18nManager;
 import org.hisp.dhis.system.grid.GridUtils;
 import org.hisp.dhis.webapi.utils.ContextUtils;
@@ -40,18 +46,11 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
-import java.util.Set;
-
-import static org.hisp.dhis.analytics.AnalyticsService.NAMES_META_KEY;
-
 /**
  * @author Lars Helge Overland
  */
@@ -337,22 +336,6 @@
     }
 
     // -------------------------------------------------------------------------
-    // Exception handling
-    // -------------------------------------------------------------------------
-
-    @ExceptionHandler( IllegalQueryException.class )
-    public void handleError( IllegalQueryException ex, HttpServletResponse response )
-    {
-        ContextUtils.conflictResponse( response, ex.getMessage() );
-    }
-
-    @ExceptionHandler( IllegalArgumentException.class )
-    public void handleError( IllegalArgumentException ex, HttpServletResponse response )
-    {
-        ContextUtils.conflictResponse( response, ex.getMessage() );
-    }
-
-    // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------
 

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/utils/ContextUtils.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/utils/ContextUtils.java	2014-07-08 19:02:06 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/utils/ContextUtils.java	2014-07-10 10:27:53 +0000
@@ -191,7 +191,7 @@
     {
         setResponse( response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message );
     }
-
+    
     private static void setResponse( HttpServletResponse response, int statusCode, String message )
     {
         response.setStatus( statusCode );

=== modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java'
--- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java	2014-06-26 14:38:54 +0000
+++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/interceptor/SystemSettingInterceptor.java	2014-07-10 10:27:53 +0000
@@ -117,6 +117,7 @@
         map.put( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, systemSettingManager.getSystemSetting( KEY_ONLY_MANAGE_WITHIN_USER_GROUPS, false ) );
         map.put( KEY_CUSTOM_LOGIN_PAGE_LOGO, systemSettingManager.getSystemSetting( KEY_CUSTOM_LOGIN_PAGE_LOGO, false ) );
         map.put( KEY_CUSTOM_TOP_MENU_LOGO, systemSettingManager.getSystemSetting( KEY_CUSTOM_TOP_MENU_LOGO, false ) );
+        map.put( KEY_ANALYTICS_MAINTENANCE_MODE, systemSettingManager.getSystemSetting( KEY_ANALYTICS_MAINTENANCE_MODE, false ) );
         map.put( SYSPROP_PORTAL, defaultIfEmpty( System.getProperty( SYSPROP_PORTAL ), String.valueOf( false ) ) );
 
         invocation.getStack().push( map );

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetGeneralSettingsAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetGeneralSettingsAction.java	2014-07-07 08:05:58 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/SetGeneralSettingsAction.java	2014-07-10 10:27:53 +0000
@@ -175,6 +175,13 @@
         this.multiOrganisationUnitForms = multiOrganisationUnitForms;
     }
 
+    private boolean analyticsMaintenanceMode;
+    
+    public void setAnalyticsMaintenanceMode( boolean analyticsMaintenanceMode )
+    {
+        this.analyticsMaintenanceMode = analyticsMaintenanceMode;
+    }
+    
     private String calendar;
 
     public void setCalendar( String calendar )
@@ -218,6 +225,7 @@
         systemSettingManager.saveSystemSetting( KEY_GOOGLE_ANALYTICS_UA, googleAnalyticsUA );
         systemSettingManager.saveSystemSetting( KEY_CALENDAR, calendar );
         systemSettingManager.saveSystemSetting( KEY_DATE_FORMAT, dateFormat );
+        systemSettingManager.saveSystemSetting( KEY_ANALYTICS_MAINTENANCE_MODE, analyticsMaintenanceMode );
 
         Configuration configuration = configurationService.getConfiguration();
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties	2014-07-08 16:14:10 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/org/hisp/dhis/settings/i18n_module.properties	2014-07-10 10:27:53 +0000
@@ -112,4 +112,6 @@
 remote_server_username=Remote server username
 remote_server_password=Remote server password
 intro_data_synchronization = A data synchronization with remote server functionality
-recommended=recommended
\ No newline at end of file
+recommended=recommended
+put_analytics_in_maintenance_mode=Put analytics in maintenance mode
+returns=returns

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemGeneralSettings.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemGeneralSettings.vm	2014-05-13 11:15:35 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemGeneralSettings.vm	2014-07-10 10:27:53 +0000
@@ -12,7 +12,8 @@
         factorDeviation: getFieldValue('factorDeviation'),
         phoneNumberAreaCode: getFieldValue('phoneNumberAreaCode'),
         googleAnalyticsUA: getFieldValue('googleAnalyticsUA'),
-        multiOrganisationUnitForms: jQuery('#multiOrganisationUnitForms').is(':checked')
+        multiOrganisationUnitForms: jQuery('#multiOrganisationUnitForms').is(':checked'),
+        analyticsMaintenanceMode: jQuery('#analyticsMaintenanceMode').is(':checked')
       }, function( json ) {
         if( json.response == "success" ) {
           setHeaderDelayMessage(json.message);
@@ -116,4 +117,9 @@
     <label for="omitIndicatorsZeroNumeratorDataMart">$i18n.getString( "omit_indicators_zero_numerator_data_mart" )</label>
 </div>
 
+<div class="setting">
+    <input type="checkbox" id="analyticsMaintenanceMode" name="analyticsMaintenanceMode" #if( $keyAnalyticsMaintenanceMode )checked="checked"#end>
+    <label for="analyticsMaintenanceMode">$i18n.getString( "put_analytics_in_maintenance_mode" ) <span class="tipText">($i18n.getString( "returns" ) 503)</span></label>
+</div>
+
 <div class="setting"><input type="button" value="$i18n.getString( 'save' )" style="width:10em"/></div>