← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15995: WIP on data synchronization feature. Impl configuration for remote server url and credentials. Im...

 

------------------------------------------------------------
revno: 15995
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2014-07-07 12:06:36 +0200
message:
  WIP on data synchronization feature. Impl configuration for remote server url and credentials. Impl function for checking if remote server isa available / system is online. Impl function for basic authentication with rest template.
added:
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/AvailabilityStatus.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/DefaultSynchronizationManager.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/SynchronizationManager.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/SynchronizationController.java
modified:
  dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/CodecUtils.java
  dhis-2/dhis-support/dhis-support-system/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.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 directory 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch'
=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/AvailabilityStatus.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/AvailabilityStatus.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/AvailabilityStatus.java	2014-07-07 10:06:36 +0000
@@ -0,0 +1,72 @@
+package org.hisp.dhis.dxf2.synch;
+
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author Lars Helge Overland
+ */
+@XmlRootElement(name = "availabilityStatus")
+public class AvailabilityStatus
+{
+    private boolean available;
+    
+    private String message;
+    
+    protected AvailabilityStatus()
+    {
+    }
+    
+    public AvailabilityStatus( boolean available, String message )
+    {
+        this.available = available;
+        this.message = message;
+    }
+    
+    @JsonProperty
+    public boolean isAvailable()
+    {
+        return available;
+    }
+
+    @JsonProperty
+    public String getMessage()
+    {
+        return message;
+    }
+    
+    @Override
+    public String toString()
+    {
+        return "[Available: " + available + ", message: " + message + "]";
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/DefaultSynchronizationManager.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/DefaultSynchronizationManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/DefaultSynchronizationManager.java	2014-07-07 10:06:36 +0000
@@ -0,0 +1,231 @@
+package org.hisp.dhis.dxf2.synch;
+
+/*
+ * 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 static org.apache.commons.lang.StringUtils.trimToNull;
+
+import java.util.Date;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.configuration.Configuration;
+import org.hisp.dhis.configuration.ConfigurationService;
+import org.hisp.dhis.dxf2.datavalueset.DataValueSetService;
+import org.hisp.dhis.period.Cal;
+import org.hisp.dhis.setting.SystemSettingManager;
+import org.hisp.dhis.system.util.CodecUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.support.CronTrigger;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.ResourceAccessException;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Lars Helge Overland
+ */
+public class DefaultSynchronizationManager
+    implements SynchronizationManager
+{
+    private static final Log log = LogFactory.getLog( DefaultSynchronizationManager.class );
+    
+    private static final String KEY_LAST_SUCCESSFUL_SYNC = "keyLastSuccessfulSynch";
+    
+    private static CronTrigger CRON = new CronTrigger( "5 * * * * *" ); // Every 5 minutes
+    
+    private static final String PING_PATH = "/api/system/ping";
+    private static final String HEADER_AUTHORIZATION = "Authorization";
+    
+    @Autowired
+    private DataValueSetService dataValueSetService;
+    
+    @Autowired
+    private ConfigurationService configurationService;
+    
+    @Autowired
+    private SystemSettingManager systemSettingManager;
+    
+    @Autowired
+    private RestTemplate restTemplate;
+    
+    @Autowired
+    private TaskScheduler taskScheduler;
+
+    // -------------------------------------------------------------------------
+    // SynchronizatonManager implementation
+    // -------------------------------------------------------------------------
+
+    public AvailabilityStatus isRemoteServerAvailable()
+    {
+        Configuration config = configurationService.getConfiguration();
+        
+        if ( !isRemoteServerConfigured( config ) )
+        {
+            return new AvailabilityStatus( false, "Remote server is not configured" );
+        }        
+        
+        String url = config.getRemoteServerUrl() + PING_PATH;
+        
+        log.info( "Remote server ping URL: " + url + ", username: " + config.getRemoteServerUsername() );
+        
+        HttpEntity<String> request = getBasicAuthRequestEntity( config.getRemoteServerUsername(), config.getRemoteServerPassword() );
+        
+        ResponseEntity<String> response = null;
+        HttpStatus sc = null;
+        AvailabilityStatus status = null;
+        
+        try
+        {
+            response = restTemplate.exchange( url, HttpMethod.GET, request, String.class );
+            sc = response.getStatusCode();
+        }
+        catch ( HttpClientErrorException ex )
+        {
+            sc = ex.getStatusCode();
+        }
+        catch ( HttpServerErrorException ex )
+        {
+            sc = ex.getStatusCode();
+        }
+        catch( ResourceAccessException ex )
+        {
+            return new AvailabilityStatus( false, "Network is unreachable" );
+        }
+        
+        log.info( "Response: " + response + ", status code: " + sc );
+        
+        if ( HttpStatus.FOUND.equals( sc ) )
+        {
+            status = new AvailabilityStatus( false, "Server is available but no authentication was provided" );
+        }
+        else if ( HttpStatus.UNAUTHORIZED.equals( sc ) )
+        {
+            status = new AvailabilityStatus( false, "Server is available but authentication failed" );
+        }
+        else if ( HttpStatus.INTERNAL_SERVER_ERROR.equals( sc ) )
+        {
+            status = new AvailabilityStatus( false, "Server is available but experienced an internal error" );
+        }        
+        else if ( HttpStatus.OK.equals( sc ) )
+        {
+            status = new AvailabilityStatus( true, "Server is available and authentication was successful" );
+        }
+        else
+        {
+            status = new AvailabilityStatus( false, "Server is not available for unknown reason: " + sc );
+        }
+        
+        log.info( status );
+        
+        return status;        
+    }
+    
+    public void enableDataSynch()
+    {        
+    }
+    
+    public void disableDataSynch()
+    {        
+    }
+    
+    public boolean isDataSyncEnabled()
+    {
+        return false;
+    }
+    
+    public boolean executeDataSynch()
+    {
+        Date now = new Date();
+        
+        Date date = getLastSynchSuccess();
+        
+        setLastSynchSuccess( now );
+        
+        return true;
+    }
+    
+    // -------------------------------------------------------------------------
+    // Supportive methods
+    // -------------------------------------------------------------------------
+
+    /**
+     * Gets the time of the last successful synchronization operation.
+     */
+    private Date getLastSynchSuccess()
+    {
+        Date date = (Date) systemSettingManager.getSystemSetting( KEY_LAST_SUCCESSFUL_SYNC );
+        
+        return date != null ? date : new Cal().set( 0, 1, 1 ).time();
+    }
+
+    /**
+     * Sets the time of the last successful synchronization operation.
+     */
+    private void setLastSynchSuccess( Date date )
+    {
+        systemSettingManager.saveSystemSetting( KEY_LAST_SUCCESSFUL_SYNC, date );
+    }
+
+    /**
+     * Indicates whether a remote server has been properly configured.
+     */
+    private boolean isRemoteServerConfigured( Configuration config )
+    {
+        if ( trimToNull( config.getRemoteServerUrl() ) == null )
+        {
+            log.info( "Remote server URL not set" );
+            return false;
+        }
+        
+        if ( trimToNull( config.getRemoteServerUsername() ) == null || trimToNull( config.getRemoteServerPassword() ) == null )
+        {
+            log.info( "Remote server username or password not set" );
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Creates an HTTP entity for requests with appropriate header for basic 
+     * authentication.
+     */
+    private <T> HttpEntity<T> getBasicAuthRequestEntity( String username, String password )
+    {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set( HEADER_AUTHORIZATION, CodecUtils.getBasicAuthString( username, password ) ); 
+        return new HttpEntity<T>( headers );
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/SynchronizationManager.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/SynchronizationManager.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/synch/SynchronizationManager.java	2014-07-07 10:06:36 +0000
@@ -0,0 +1,12 @@
+package org.hisp.dhis.dxf2.synch;
+
+public interface SynchronizationManager
+{
+    AvailabilityStatus isRemoteServerAvailable();
+    
+    boolean executeDataSynch();
+    
+    void enableDataSynch();
+    
+    void disableDataSynch();
+}

=== 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-06-20 11:14:18 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/resources/META-INF/dhis/beans.xml	2014-07-07 10:06:36 +0000
@@ -37,6 +37,8 @@
   <bean id="org.hisp.dhis.dxf2.metadata.MetaDataDependencyService" class="org.hisp.dhis.dxf2.metadata.DefaultMetaDataDependencyService"
     scope="prototype" />
 
+  <bean id="org.hisp.dhis.dxf2.synch.SynchronizationManager" class="org.hisp.dhis.dxf2.synch.DefaultSynchronizationManager" />
+
   <!-- register idObject handlers -->
 
   <bean id="organisationUnitObjectHandler"

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/CodecUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/CodecUtils.java	2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/CodecUtils.java	2014-07-07 10:06:36 +0000
@@ -38,7 +38,6 @@
 
 /**
  * @author Lars Helge Overland
- * @version $Id$
  */
 public class CodecUtils
 {
@@ -163,5 +162,12 @@
         
         return string;
     }
+    
+    public static String getBasicAuthString( String username, String password )
+    {        
+        String string = username + ":" + password;
+        
+        return "Basic " + Base64.encodeBase64String( string.getBytes() );
+    }    
 }
 

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-support/dhis-support-system/src/main/resources/META-INF/dhis/beans.xml	2013-12-17 17:58:55 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/resources/META-INF/dhis/beans.xml	2014-07-07 10:06:36 +0000
@@ -25,6 +25,8 @@
     <property name="taskExecutor" ref="taskScheduler" />
   </bean>
 
+  <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
+  
   <bean id="org.hisp.dhis.system.velocity.VelocityManager" class="org.hisp.dhis.system.velocity.VelocityManager" />
 
   <bean id="notifier" class="org.hisp.dhis.system.notification.InMemoryNotifier" />

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/SynchronizationController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/SynchronizationController.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/SynchronizationController.java	2014-07-07 10:06:36 +0000
@@ -0,0 +1,60 @@
+package org.hisp.dhis.webapi.controller;
+
+/*
+ * 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.dxf2.synch.AvailabilityStatus;
+import org.hisp.dhis.dxf2.synch.SynchronizationManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Lars Helge Overland
+ */
+@Controller
+@RequestMapping( value = SynchronizationController.RESOURCE_PATH )
+public class SynchronizationController
+{
+    public static final String RESOURCE_PATH = "/synchronization";
+    
+    @Autowired
+    private RestTemplate restTemplate;
+    
+    @Autowired
+    private SynchronizationManager synchronizationManager;
+
+    @RequestMapping( value = "/availability", method = RequestMethod.GET, produces = "application/json" )
+    public @ResponseBody AvailabilityStatus isRemoteServerAvailable()
+    {
+        return synchronizationManager.isRemoteServerAvailable();
+    }    
+}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml	2014-05-22 12:40:24 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/beans.xml	2014-07-07 10:06:36 +0000
@@ -5,6 +5,5 @@
 	
   <bean id="contextUtils" class="org.hisp.dhis.webapi.utils.ContextUtils"/>
   <bean id="inputUtils" class="org.hisp.dhis.webapi.utils.InputUtils" />
-  <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
 
 </beans>