use osgi-ds for ApplicationPersistenceServices

Change-Id: Ia81c60745b14f04bd53254e8c6814cecd65a1614
diff --git a/distribution/template/cfgs-template/application-manager.config b/distribution/template/cfgs-template/application-manager.config
index b8ae52a..32b2856 100644
--- a/distribution/template/cfgs-template/application-manager.config
+++ b/distribution/template/cfgs-template/application-manager.config
@@ -1,8 +1,6 @@
 #the directory that should be read to look for applications
 directory=application
-#if the application should be persisted on the disk
-applicationPersist=true
 #in miliseconds
-updateFileCheck=2000
+readingDelay=2000
 #The extension to be considered as an application
-applicationFileExtension=json
+fileExtention=json
diff --git a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/api/persistence/ApplicationPersistenceService.java b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/api/persistence/ApplicationPersistenceService.java
index c76a892..d489160 100644
--- a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/api/persistence/ApplicationPersistenceService.java
+++ b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/api/persistence/ApplicationPersistenceService.java
@@ -17,7 +17,7 @@
 
 import java.util.Collection;
 
-public interface ApplicationPersistenceService extends Runnable {
+public interface ApplicationPersistenceService{
     void persist(Application application) throws ApplicationPersistenceException;
 
     void delete(String applicationName) throws ApplicationPersistenceException;
diff --git a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationFileSystem.java b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/FileSystemApplicationPersistenceService.java
similarity index 60%
rename from platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationFileSystem.java
rename to platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/FileSystemApplicationPersistenceService.java
index 2af659d..c34eae7 100644
--- a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationFileSystem.java
+++ b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/FileSystemApplicationPersistenceService.java
@@ -10,15 +10,6 @@
  */
 package org.eclipse.sensinact.gateway.app.manager.application.persistence;
 
-import org.eclipse.sensinact.gateway.app.api.persistence.ApplicationPersistenceService;
-import org.eclipse.sensinact.gateway.app.api.persistence.dao.Application;
-import org.eclipse.sensinact.gateway.app.api.persistence.exception.ApplicationPersistenceException;
-import org.eclipse.sensinact.gateway.app.api.persistence.listener.ApplicationAvailabilityListener;
-import org.eclipse.sensinact.gateway.app.manager.application.persistence.exception.ApplicationParseException;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FilenameFilter;
@@ -32,26 +23,118 @@
 import java.util.Map;
 import java.util.Set;
 
-public class SNAPersistApplicationFileSystem implements ApplicationPersistenceService {
-    private final Logger LOG = LoggerFactory.getLogger(SNAPersistApplicationFileSystem.class);
-    private final File directoryMonitor;
+import org.eclipse.sensinact.gateway.app.api.persistence.ApplicationPersistenceService;
+import org.eclipse.sensinact.gateway.app.api.persistence.dao.Application;
+import org.eclipse.sensinact.gateway.app.api.persistence.exception.ApplicationPersistenceException;
+import org.eclipse.sensinact.gateway.app.api.persistence.listener.ApplicationAvailabilityListener;
+import org.eclipse.sensinact.gateway.app.manager.application.persistence.exception.ApplicationParseException;
+import org.json.JSONObject;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.ServiceScope;
+import org.osgi.service.component.propertytypes.ServiceRanking;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = ApplicationPersistenceService.class,scope = ServiceScope.SINGLETON)
+@ServiceRanking(100)
+@Designate(ocd = FileSystemApplicationPersistenceService.Config.class)
+public class FileSystemApplicationPersistenceService implements ApplicationPersistenceService {
+    private final Logger LOG = LoggerFactory.getLogger(FileSystemApplicationPersistenceService.class);
+    @ObjectClassDefinition
+	@interface Config {
+		String directory() default "application";
+		long readingDelay() default 0;
+		String fileExtention() default "json";
+	}
+	
+    private File directory;
+    private long readingDelay;
+    private String fileExtention;
     private final List<String> files = new ArrayList<>();
     private final Map<String, Application> filesPath = new HashMap<>();
     private final Set<ApplicationAvailabilityListener> listener = new HashSet<ApplicationAvailabilityListener>();
-    private final Long readingDelay;
-    private final String fileExtention;
     private Boolean active = Boolean.TRUE;
+	private Thread persistenceThread;
     private static final Object lock = new Object();
 
-    public SNAPersistApplicationFileSystem(File directoryMonitor, Long readingDelay, String fileExtention) {
-        this.directoryMonitor = directoryMonitor;
-        this.readingDelay = readingDelay;
-        this.fileExtention = fileExtention;
-    }
+	@Activate
+	public void activate(Config config) {
+		this.directory = new File(config.directory());
+		this.readingDelay = config.readingDelay();
+		this.fileExtention = config.fileExtention();
+		
+        persistenceThread = new Thread(() ->{
+        	
+        	 notifyServiceAvailable();
+             while (active) {
+                 try {
+                     //Thread.sleep(readingDelay);
+                     synchronized (lock) {
+                         List<String> filesToBeProcessed = new ArrayList<>();
+                         for (File applicationFile : directory.listFiles(new FilenameFilter() {
+                             @Override
+                             public boolean accept(File dir, String name) {
+                                 return name.endsWith("." + fileExtention);
+                             }
+                         })) {
+                             filesToBeProcessed.add(applicationFile.getAbsolutePath());
+                         }
+                         List<String> filesRemoved = new ArrayList<>(files);
+                         filesRemoved.removeAll(filesToBeProcessed);
+                         //Remove old application files
+                         for (String fileRemoved : filesRemoved) {
+                             notifyRemoval(fileRemoved);
+                         }
+                         //Process (new files or already installed) files
+                         for (String toprocess : filesToBeProcessed) {
+                             try {
+                                 Boolean fileManaged = filesPath.containsKey(toprocess);
+                                 if (!fileManaged) { //new file
+                                     LOG.info("Application file {} will be loaded.", toprocess);
+                                     notifyInclusion(toprocess);
+                                 } else {
+                                     Application applicationManaged = filesPath.get(toprocess);
+                                     Application applicationInFs = FileToApplicationParser.parse(toprocess);
+                                     //taken into account modified files
+                                     if (!applicationManaged.getDiggest().equals(applicationInFs.getDiggest())) {
+                                         LOG.info("Application file {} was already loaded but its content changed, dispatching update.", toprocess);
+                                         notifyModification(toprocess);
+                                         LOG.info("Application file {}, update procedure finished.", toprocess);
+                                     } else {
+                                         //Dont do anything, file already taken into account
+                                     }
+                                 }
+                             } catch (Exception e) {
+                                 LOG.warn("Failed to process application description file {}", toprocess, e);
+                             }
+                         }
+                     }
+                     Thread.sleep(readingDelay);
+                 } catch (Exception e) {
+                     LOG.error("Application persistency system failed", e);
+                 }
+             }
+             notifyServiceUnavailable();
+             LOG.error("Application persistency system is exiting");
+        });
+        persistenceThread.setDaemon(true);
+        persistenceThread.setPriority(Thread.MIN_PRIORITY);
+        persistenceThread.start();
+	}
 
+	@Deactivate
+	public void deactivate() {
+        if (persistenceThread != null) {
+        	persistenceThread.interrupt();
+        }
+	}
     @Override
     public void persist(Application application) throws ApplicationPersistenceException {
-        final String filename = directoryMonitor + File.separator + application.getName() + "." + fileExtention;
+        final String filename = directory + File.separator + application.getName() + "." + fileExtention;
         synchronized (lock) {
             File file = new File(filename);
             try {
@@ -69,7 +152,7 @@
 
     @Override
     public void delete(String applicationName) throws ApplicationPersistenceException {
-        final String filename = directoryMonitor + File.separator + applicationName + "." + fileExtention;
+        final String filename = directory + File.separator + applicationName + "." + fileExtention;
         synchronized (lock) {
             File file = new File(filename);
             try {
@@ -104,59 +187,7 @@
         }
     }
 
-    public void run() {
-        notifyServiceAvailable();
-        while (active) {
-            try {
-                //Thread.sleep(readingDelay);
-                synchronized (lock) {
-                    List<String> filesToBeProcessed = new ArrayList<>();
-                    for (File applicationFile : directoryMonitor.listFiles(new FilenameFilter() {
-                        @Override
-                        public boolean accept(File dir, String name) {
-                            return name.endsWith("." + fileExtention);
-                        }
-                    })) {
-                        filesToBeProcessed.add(applicationFile.getAbsolutePath());
-                    }
-                    List<String> filesRemoved = new ArrayList<>(files);
-                    filesRemoved.removeAll(filesToBeProcessed);
-                    //Remove old application files
-                    for (String fileRemoved : filesRemoved) {
-                        notifyRemoval(fileRemoved);
-                    }
-                    //Process (new files or already installed) files
-                    for (String toprocess : filesToBeProcessed) {
-                        try {
-                            Boolean fileManaged = filesPath.containsKey(toprocess);
-                            if (!fileManaged) { //new file
-                                LOG.info("Application file {} will be loaded.", toprocess);
-                                notifyInclusion(toprocess);
-                            } else {
-                                Application applicationManaged = filesPath.get(toprocess);
-                                Application applicationInFs = FileToApplicationParser.parse(toprocess);
-                                //taken into account modified files
-                                if (!applicationManaged.getDiggest().equals(applicationInFs.getDiggest())) {
-                                    LOG.info("Application file {} was already loaded but its content changed, dispatching update.", toprocess);
-                                    notifyModification(toprocess);
-                                    LOG.info("Application file {}, update procedure finished.", toprocess);
-                                } else {
-                                    //Dont do anything, file already taken into account
-                                }
-                            }
-                        } catch (Exception e) {
-                            LOG.warn("Failed to process application description file {}", toprocess, e);
-                        }
-                    }
-                }
-                Thread.sleep(readingDelay);
-            } catch (Exception e) {
-                LOG.error("Application persistency system failed", e);
-            }
-        }
-        notifyServiceUnavailable();
-        LOG.error("Application persistency system is exiting");
-    }
+
 
     private void notifyInclusion(String filepath) {
         try {
diff --git a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationInMemory.java b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/InMemoryApplicationPersistenceService.java
similarity index 74%
rename from platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationInMemory.java
rename to platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/InMemoryApplicationPersistenceService.java
index e64c8a0..0850fbe 100644
--- a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/SNAPersistApplicationInMemory.java
+++ b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/application/persistence/InMemoryApplicationPersistenceService.java
@@ -15,6 +15,11 @@
 import org.eclipse.sensinact.gateway.app.api.persistence.exception.ApplicationPersistenceException;
 import org.eclipse.sensinact.gateway.app.api.persistence.listener.ApplicationAvailabilityListener;
 import org.json.JSONObject;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.ServiceScope;
+import org.osgi.service.component.propertytypes.ServiceRanking;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -24,13 +29,21 @@
 import java.util.List;
 import java.util.Set;
 
-public class SNAPersistApplicationInMemory implements ApplicationPersistenceService {
-    private static Logger LOG = LoggerFactory.getLogger(SNAPersistApplicationInMemory.class);
-    private List<Application> applicationList = new ArrayList<Application>();
-    private final Set<ApplicationAvailabilityListener> listener = new HashSet<ApplicationAvailabilityListener>();
+@Component(service = ApplicationPersistenceService.class,scope = ServiceScope.SINGLETON,configurationPolicy = ConfigurationPolicy.REQUIRE)
+@ServiceRanking(500)
+public class InMemoryApplicationPersistenceService implements ApplicationPersistenceService {
+    private static Logger LOG = LoggerFactory.getLogger(InMemoryApplicationPersistenceService.class);
+    private List<Application> applications = new ArrayList<Application>();
+    private final Set<ApplicationAvailabilityListener> listeners = new HashSet<ApplicationAvailabilityListener>();
 
-    private Application findApplication(String name) {
-        for (Application application : applicationList) {
+    
+	@Activate
+	public void activate() {
+		notifyServiceAvailable();
+	}
+
+	private Application findApplication(String name) {
+        for (Application application : applications) {
             if (application.getName().equals(name)) return application;
         }
         return null;
@@ -41,11 +54,11 @@
         //Not implemented
         Application applicationStored = findApplication(application.getName());
         if (applicationStored == null) {
-            applicationList.add(application);
+            applications.add(application);
             notifyInclusion(application);
         } else if (!application.getDiggest().equals(applicationStored.getDiggest())) {
-            applicationList.remove(applicationStored);
-            applicationList.add(application);
+            applications.remove(applicationStored);
+            applications.add(application);
             notifyModification(application);
         }
     }
@@ -53,7 +66,7 @@
     @Override
     public void delete(String applicationName) throws ApplicationPersistenceException {
         notifyRemoval(findApplication(applicationName));
-        applicationList.remove(findApplication(applicationName));
+        applications.remove(findApplication(applicationName));
     }
 
     @Override
@@ -63,20 +76,20 @@
 
     @Override
     public Collection<Application> list() {
-        return applicationList;
+        return applications;
     }
 
     @Override
     public void registerServiceAvailabilityListener(ApplicationAvailabilityListener listenerClient) {
-        synchronized (this.listener) {
-            this.listener.add(listenerClient);
+        synchronized (this.listeners) {
+            this.listeners.add(listenerClient);
         }
     }
 
     @Override
     public void unregisterServiceAvailabilityListener(ApplicationAvailabilityListener listenerClient) {
-        synchronized (this.listener) {
-            this.listener.remove(listenerClient);
+        synchronized (this.listeners) {
+            this.listeners.remove(listenerClient);
         }
     }
 
@@ -85,7 +98,7 @@
     		return;
         try {
             LOG.info("Notifying application '{}' inclusion ", application.getName());
-            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listener)) {
+            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listeners)) {
                 try {
                     synchronized (list) {
                         list.applicationFound(application.getName(), application.getContent().toString());
@@ -104,7 +117,7 @@
     		return;
         try {
             LOG.info("Notifying application '{}' modification ", application.getName());
-            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listener)) {
+            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listeners)) {
                 try {
                     synchronized (list) {
                         list.applicationChanged(application.getName(), application.getContent().toString());
@@ -123,7 +136,7 @@
     		return;
         try {
             LOG.info("Notifying application '{}' removal ", application.getName());
-            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listener)) {
+            for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listeners)) {
                 try {
                     synchronized (list) {
                         list.applicationRemoved(application.getName());
@@ -139,7 +152,7 @@
 
     private void notifyServiceUnavailable() {
         LOG.debug("Memory Persistence service is going offline");
-        for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listener)) {
+        for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listeners)) {
             try {
                 list.serviceOffline();
             } catch (Exception e) {
@@ -150,17 +163,12 @@
 
     private void notifyServiceAvailable() {
         LOG.debug("Memory Persistence service is going online");
-        for (ApplicationAvailabilityListener list : new HashSet<ApplicationAvailabilityListener>(listener)) {
+        for (ApplicationAvailabilityListener listener : new HashSet<ApplicationAvailabilityListener>(listeners)) {
             try {
-                list.serviceOnline();
+                listener.serviceOnline();
             } catch (Exception e) {
                 LOG.error("Memory Persistence service is going online", e);
             }
         }
     }
-
-    @Override
-    public void run() {
-        notifyServiceAvailable();
-    }
 }
diff --git a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/osgi/ApplicationManagerConfigurator.java b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/osgi/ApplicationManagerConfigurator.java
index 7f5da1e..590533c 100644
--- a/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/osgi/ApplicationManagerConfigurator.java
+++ b/platform/sensinact-application/application-manager/src/main/java/org/eclipse/sensinact/gateway/app/manager/osgi/ApplicationManagerConfigurator.java
@@ -10,19 +10,13 @@
  */
 package org.eclipse.sensinact.gateway.app.manager.osgi;
 
-import java.io.File;
-import java.util.Map;
-
 import org.eclipse.sensinact.gateway.app.api.persistence.ApplicationPersistenceService;
-import org.eclipse.sensinact.gateway.app.manager.application.persistence.SNAPersistApplicationFileSystem;
-import org.eclipse.sensinact.gateway.app.manager.application.persistence.SNAPersistApplicationInMemory;
 import org.eclipse.sensinact.gateway.app.manager.internal.AppManagerFactory;
-import org.eclipse.sensinact.gateway.common.annotation.Property;
-import org.eclipse.sensinact.gateway.common.interpolator.Interpolator;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,61 +26,26 @@
 @Component(immediate=true)
 public class ApplicationManagerConfigurator  {
 	
-    private static Logger LOG = LoggerFactory.getLogger(ApplicationManagerConfigurator.class);
-    
+	private static Logger LOG = LoggerFactory.getLogger(ApplicationManagerConfigurator.class);
     private AppManagerFactory appManagerFactory;
-    private Thread persistenceThread;
-    
-    @Property(defaultValue = "application")
-    private String directory;
-    
-    @Property(validationRegex = Property.INTEGER, mandatory=false, defaultValue="0")
-    private Long updateFileCheck;
-    
-    @Property(mandatory = false, defaultValue="false")
-    private Boolean applicationPersist;
-    
-    @Property(defaultValue = "json", validationRegex = Property.ALPHANUMERIC)
-    private String applicationFileExtension;
 
 	private AppServiceMediator mediator;
 
-    protected void injectPropertyFields() throws Exception {
-        LOG.debug("Starting introspection in bundle %s", mediator.getContext().getBundle().getSymbolicName());
-        Interpolator interpolator = new Interpolator(this.mediator);
-        interpolator.getInstance(this);
-        for(Map.Entry<String,String> entry:interpolator.getPropertiesInjected().entrySet()){
-            if(!this.mediator.getProperties().containsKey(entry.getKey()))
-                mediator.setProperty(entry.getKey(),entry.getValue());
-        }
-    }
+	@Reference
+	private ApplicationPersistenceService applicationPersistenceService;
     
     @Activate
 	public void activate(ComponentContext componentContext) throws Exception {
     	
     	this.mediator = new AppServiceMediator(componentContext.getBundleContext());
-        injectPropertyFields();
-        
-        ApplicationPersistenceService directoryMonitor = null;
-        if (applicationPersist) {
-            LOG.info("Filesystem Persistence mechanism is ON");
-            directoryMonitor = new SNAPersistApplicationFileSystem(new File(directory), updateFileCheck, applicationFileExtension);
-            ;
-        } else {
-            LOG.info("Filesystem Persistence mechanism is OFF");
-            directoryMonitor = new SNAPersistApplicationInMemory();
-        }
-        this.appManagerFactory = new AppManagerFactory(mediator, directoryMonitor);
-        directoryMonitor.registerServiceAvailabilityListener(appManagerFactory);
-        persistenceThread = new Thread(directoryMonitor);
-        persistenceThread.setDaemon(true);
-        persistenceThread.setPriority(Thread.MIN_PRIORITY);
-        persistenceThread.start();
+
+        this.appManagerFactory = new AppManagerFactory(mediator, applicationPersistenceService);
+        applicationPersistenceService.registerServiceAvailabilityListener(appManagerFactory);
     }
 
     @Deactivate
     public void deactivate() throws Exception {
-        if (persistenceThread != null) persistenceThread.interrupt();
+
         this.appManagerFactory.deleteAppManager();
     }
 }