You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by am...@apache.org on 2017/07/01 01:39:58 UTC

incubator-unomi git commit: UNOMI-102 : Add oneshot export, improve camel osgi behaviour

Repository: incubator-unomi
Updated Branches:
  refs/heads/master 46900c554 -> 9794636f1


UNOMI-102 : Add oneshot export, improve camel osgi behaviour


Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/9794636f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/9794636f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/9794636f

Branch: refs/heads/master
Commit: 9794636f1433da34c88a0d98b22423d5593e20f3
Parents: 46900c5
Author: Abdelkader Midani <am...@apache.org>
Authored: Sat Jul 1 03:39:07 2017 +0200
Committer: Abdelkader Midani <am...@apache.org>
Committed: Sat Jul 1 03:39:48 2017 +0200

----------------------------------------------------------------------
 extensions/router/pom.xml                       |  2 +-
 .../unomi/router/api/RouterConstants.java       |  6 ++
 .../apache/unomi/router/api/RouterUtils.java    | 42 ++++++++++
 .../api/services/ProfileExportService.java      | 33 ++++++++
 extensions/router/router-core/pom.xml           | 18 ++++-
 .../router/core/context/RouterCamelContext.java | 23 +++++-
 .../ExportRouteCompletionProcessor.java         | 19 +----
 .../ImportRouteCompletionProcessor.java         | 17 +---
 .../core/processor/LineBuildProcessor.java      | 20 ++---
 .../route/ProfileExportCollectRouteBuilder.java |  4 +-
 .../ProfileExportProducerRouteBuilder.java      |  9 ++-
 .../ProfileImportFromSourceRouteBuilder.java    |  2 +-
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  3 +
 .../main/resources/org.apache.unomi.router.cfg  |  2 +-
 extensions/router/router-karaf-feature/pom.xml  |  7 +-
 extensions/router/router-rest/pom.xml           |  6 ++
 .../ExportConfigurationServiceEndPoint.java     | 31 ++++++++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  2 +
 .../services/AbstractCustomServiceImpl.java     | 76 ++++++++++++++++++
 .../services/ProfileExportServiceImpl.java      | 83 ++++++++++++++++++++
 .../services/ProfileImportServiceImpl.java      | 65 ++-------------
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  9 +++
 kar/src/main/feature/feature.xml                |  1 +
 23 files changed, 369 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/router/pom.xml b/extensions/router/pom.xml
index f6f80eb..d45fd05 100644
--- a/extensions/router/pom.xml
+++ b/extensions/router/pom.xml
@@ -29,7 +29,7 @@
     <packaging>pom</packaging>
 
     <properties>
-        <camel.version>2.18.3</camel.version>
+        <camel.version>2.19.1</camel.version>
     </properties>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterConstants.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterConstants.java b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterConstants.java
index 7f45228..6f6d5f5 100644
--- a/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterConstants.java
+++ b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterConstants.java
@@ -48,4 +48,10 @@ public interface RouterConstants {
     String DEFAULT_FILE_COLUMN_SEPARATOR = ",";
 
     String DEFAULT_FILE_LINE_SEPARATOR = "\n";
+
+    String KEY_HISTORY_SIZE = "historySize";
+    String KEY_CSV_CONTENT = "csvContent";
+    String KEY_EXECS = "execs";
+    Object KEY_EXECS_DATE = "date";
+    Object KEY_EXECS_EXTRACTED = "extractedProfiles";
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterUtils.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterUtils.java b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterUtils.java
new file mode 100644
index 0000000..ebfdabf
--- /dev/null
+++ b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/RouterUtils.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.router.api;
+
+import java.util.Map;
+
+/**
+ * Created by amidani on 30/06/2017.
+ */
+public class RouterUtils {
+
+    public static ImportExportConfiguration addExecutionEntry(ImportExportConfiguration configuration, Map execution, int executionsHistorySize) {
+        if (configuration.getExecutions().size() >= executionsHistorySize) {
+            int oldestExecIndex = 0;
+            long oldestExecDate = (Long) configuration.getExecutions().get(0).get(RouterConstants.KEY_EXECS_DATE);
+            for (int i = 1; i < configuration.getExecutions().size(); i++) {
+                if ((Long) configuration.getExecutions().get(i).get(RouterConstants.KEY_EXECS_DATE) < oldestExecDate) {
+                    oldestExecDate = (Long) configuration.getExecutions().get(i).get(RouterConstants.KEY_EXECS_DATE);
+                    oldestExecIndex = i;
+                }
+            }
+            configuration.getExecutions().remove(oldestExecIndex);
+        }
+
+        configuration.getExecutions().add(execution);
+        return configuration;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/services/ProfileExportService.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/services/ProfileExportService.java b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/services/ProfileExportService.java
new file mode 100644
index 0000000..8f2e51b
--- /dev/null
+++ b/extensions/router/router-api/src/main/java/org/apache/unomi/router/api/services/ProfileExportService.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.router.api.services;
+
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.router.api.ExportConfiguration;
+
+import java.util.List;
+
+/**
+ * Created by amidani on 30/06/2017.
+ */
+public interface ProfileExportService {
+
+    String extractProfilesBySegment(ExportConfiguration exportConfiguration);
+
+    String convertProfileToCSVLine(Profile profile, ExportConfiguration exportConfiguration);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/pom.xml b/extensions/router/router-core/pom.xml
index 6d80be2..34550d7 100644
--- a/extensions/router/router-core/pom.xml
+++ b/extensions/router/router-core/pom.xml
@@ -70,6 +70,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core-osgi</artifactId>
+            <version>${camel.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-jackson</artifactId>
             <version>${camel.version}</version>
             <scope>provided</scope>
@@ -88,6 +94,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-ftp</artifactId>
+            <version>${camel.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-kafka</artifactId>
             <version>${camel.version}</version>
             <scope>provided</scope>
@@ -100,7 +111,6 @@
             <groupId>commons-net</groupId>
             <artifactId>commons-net</artifactId>
             <version>3.5</version>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.servicemix.bundles</groupId>
@@ -126,7 +136,7 @@
                     <instructions>
                         <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                         <Import-Package>
-                            org.osgi.service.event;resolution:=optional,
+                            org.osgi.service.event*;resolution:=optional,
                             org.apache.camel,
                             org.apache.camel.builder,
                             org.apache.camel.component.file.remote,
@@ -135,6 +145,7 @@
                             org.apache.camel.component.kafka,
                             org.apache.camel.component.servlet,
                             org.apache.camel.component.servlet.osgi,
+                            org.apache.camel.core.osgi,
                             org.apache.camel.impl,
                             org.apache.camel.model,
                             org.apache.camel.model.dataformat,
@@ -151,7 +162,8 @@
                             com.jcraft.jsch,
                             org.osgi.framework,
                             org.osgi.service.http,
-                            org.slf4j
+                            org.slf4j,
+                            *
                         </Import-Package>
                     </instructions>
                 </configuration>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/context/RouterCamelContext.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/context/RouterCamelContext.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/context/RouterCamelContext.java
index d6ca24b..228dc71 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/context/RouterCamelContext.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/context/RouterCamelContext.java
@@ -18,7 +18,9 @@ package org.apache.unomi.router.core.context;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Route;
+import org.apache.camel.component.file.remote.FtpComponent;
 import org.apache.camel.component.jackson.JacksonDataFormat;
+import org.apache.camel.core.osgi.OsgiDefaultCamelContext;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.unomi.api.services.ConfigSharingService;
@@ -27,6 +29,7 @@ import org.apache.unomi.router.api.ExportConfiguration;
 import org.apache.unomi.router.api.ImportConfiguration;
 import org.apache.unomi.router.api.RouterConstants;
 import org.apache.unomi.router.api.services.ImportExportConfigurationService;
+import org.apache.unomi.router.api.services.ProfileExportService;
 import org.apache.unomi.router.core.processor.ExportRouteCompletionProcessor;
 import org.apache.unomi.router.core.processor.ImportConfigByFileNameProcessor;
 import org.apache.unomi.router.core.processor.ImportRouteCompletionProcessor;
@@ -57,14 +60,20 @@ public class RouterCamelContext implements SynchronousBundleListener {
     private ImportExportConfigurationService<ImportConfiguration> importConfigurationService;
     private ImportExportConfigurationService<ExportConfiguration> exportConfigurationService;
     private PersistenceService persistenceService;
+    private ProfileExportService profileExportService;
     private JacksonDataFormat jacksonDataFormat;
     private String uploadDir;
+    private String execHistorySize;
     private Map<String, String> kafkaProps;
     private String configType;
     private String allowedEndpoints;
     private BundleContext bundleContext;
     private ConfigSharingService configSharingService;
 
+    public void setExecHistorySize(String execHistorySize) {
+        this.execHistorySize = execHistorySize;
+    }
+
     public void setBundleContext(BundleContext bundleContext) {
         this.bundleContext = bundleContext;
     }
@@ -77,8 +86,9 @@ public class RouterCamelContext implements SynchronousBundleListener {
         logger.info("Initialize Camel Context...");
 
         configSharingService.setProperty("oneshotImportUploadDir", uploadDir);
+        configSharingService.setProperty(RouterConstants.KEY_HISTORY_SIZE, execHistorySize);
 
-        camelContext = new DefaultCamelContext();
+        camelContext = new OsgiDefaultCamelContext(bundleContext);
 
         //--IMPORT ROUTES
 
@@ -107,6 +117,8 @@ public class RouterCamelContext implements SynchronousBundleListener {
         camelContext.addRoutes(builderProcessor);
 
         //--EXPORT ROUTES
+
+        //Profiles collect
         ProfileExportCollectRouteBuilder profileExportCollectRouteBuilder = new ProfileExportCollectRouteBuilder(kafkaProps, configType);
         profileExportCollectRouteBuilder.setExportConfigurationService(exportConfigurationService);
         profileExportCollectRouteBuilder.setPersistenceService(persistenceService);
@@ -115,7 +127,9 @@ public class RouterCamelContext implements SynchronousBundleListener {
         profileExportCollectRouteBuilder.setContext(camelContext);
         camelContext.addRoutes(profileExportCollectRouteBuilder);
 
+        //Write to destination
         ProfileExportProducerRouteBuilder profileExportProducerRouteBuilder = new ProfileExportProducerRouteBuilder(kafkaProps, configType);
+        profileExportProducerRouteBuilder.setProfileExportService(profileExportService);
         profileExportProducerRouteBuilder.setExportRouteCompletionProcessor(exportRouteCompletionProcessor);
         profileExportProducerRouteBuilder.setAllowedEndpoints(allowedEndpoints);
         profileExportProducerRouteBuilder.setJacksonDataFormat(jacksonDataFormat);
@@ -163,7 +177,7 @@ public class RouterCamelContext implements SynchronousBundleListener {
     }
 
     private void updateProfileImportReaderRoute(ImportConfiguration importConfiguration) throws Exception {
-
+        killExistingRoute(importConfiguration.getItemId());
         //Handle transforming an import config oneshot <--> recurrent
         if (RouterConstants.IMPORT_EXPORT_CONFIG_TYPE_RECURRENT.equals(importConfiguration.getConfigType())) {
             ProfileImportFromSourceRouteBuilder builder = new ProfileImportFromSourceRouteBuilder(kafkaProps, configType);
@@ -181,6 +195,7 @@ public class RouterCamelContext implements SynchronousBundleListener {
         //Handle transforming an import config oneshot <--> recurrent
         if (RouterConstants.IMPORT_EXPORT_CONFIG_TYPE_RECURRENT.equals(exportConfiguration.getConfigType())) {
             ProfileExportCollectRouteBuilder profileExportCollectRouteBuilder = new ProfileExportCollectRouteBuilder(kafkaProps, configType);
+            profileExportCollectRouteBuilder.setExportConfigurationList(Arrays.asList(exportConfiguration));
             profileExportCollectRouteBuilder.setExportConfigurationService(exportConfigurationService);
             profileExportCollectRouteBuilder.setPersistenceService(persistenceService);
             profileExportCollectRouteBuilder.setAllowedEndpoints(allowedEndpoints);
@@ -222,6 +237,10 @@ public class RouterCamelContext implements SynchronousBundleListener {
         this.persistenceService = persistenceService;
     }
 
+    public void setProfileExportService(ProfileExportService profileExportService) {
+        this.profileExportService = profileExportService;
+    }
+
     public void setJacksonDataFormat(JacksonDataFormat jacksonDataFormat) {
         this.jacksonDataFormat = jacksonDataFormat;
     }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ExportRouteCompletionProcessor.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ExportRouteCompletionProcessor.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ExportRouteCompletionProcessor.java
index 1b4d1da..89910b5 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ExportRouteCompletionProcessor.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ExportRouteCompletionProcessor.java
@@ -20,6 +20,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.unomi.router.api.ExportConfiguration;
 import org.apache.unomi.router.api.RouterConstants;
+import org.apache.unomi.router.api.RouterUtils;
 import org.apache.unomi.router.api.services.ImportExportConfigurationService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,28 +40,16 @@ public class ExportRouteCompletionProcessor implements Processor {
 
     @Override
     public void process(Exchange exchange) throws Exception {
-        String importConfigId = null;
         ExportConfiguration exportConfig = (ExportConfiguration) exchange.getIn().getHeader(RouterConstants.HEADER_EXPORT_CONFIG);
 
         Map execution = new HashMap();
-        execution.put("date", ((Date) exchange.getProperty("CamelCreatedTimestamp")).getTime());
-        execution.put("extractedProfiles", exchange.getProperty("CamelSplitSize"));
+        execution.put(RouterConstants.KEY_EXECS_DATE, ((Date) exchange.getProperty("CamelCreatedTimestamp")).getTime());
+        execution.put(RouterConstants.KEY_EXECS_EXTRACTED, exchange.getProperty("CamelSplitSize"));
 
         ExportConfiguration exportConfiguration = exportConfigurationService.load(exportConfig.getItemId());
 
-        if (exportConfiguration.getExecutions().size() >= executionsHistorySize) {
-            int oldestExecIndex = 0;
-            long oldestExecDate = (Long) exportConfiguration.getExecutions().get(0).get("date");
-            for (int i = 1; i < exportConfiguration.getExecutions().size(); i++) {
-                if ((Long) exportConfiguration.getExecutions().get(i).get("date") < oldestExecDate) {
-                    oldestExecDate = (Long) exportConfiguration.getExecutions().get(i).get("date");
-                    oldestExecIndex = i;
-                }
-            }
-            exportConfiguration.getExecutions().remove(oldestExecIndex);
-        }
+        exportConfiguration = (ExportConfiguration) RouterUtils.addExecutionEntry(exportConfiguration, execution, executionsHistorySize);
 
-        exportConfiguration.getExecutions().add(execution);
         exportConfigurationService.save(exportConfiguration);
 
         logger.info("Processing route {} completed.", exchange.getFromRouteId());

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ImportRouteCompletionProcessor.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ImportRouteCompletionProcessor.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ImportRouteCompletionProcessor.java
index edb7391..8323879 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ImportRouteCompletionProcessor.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/ImportRouteCompletionProcessor.java
@@ -18,10 +18,7 @@ package org.apache.unomi.router.core.processor;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
-import org.apache.unomi.router.api.ImportConfiguration;
-import org.apache.unomi.router.api.ImportLineError;
-import org.apache.unomi.router.api.ProfileToImport;
-import org.apache.unomi.router.api.RouterConstants;
+import org.apache.unomi.router.api.*;
 import org.apache.unomi.router.api.services.ImportExportConfigurationService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,17 +67,7 @@ public class ImportRouteCompletionProcessor implements Processor {
         execution.put("failureCount", failureCount);
         execution.put("errors", errors);
 
-        if (importConfiguration.getExecutions().size() >= executionsHistorySize) {
-            int oldestExecIndex = 0;
-            long oldestExecDate = (Long) importConfiguration.getExecutions().get(0).get("date");
-            for (int i = 1; i < importConfiguration.getExecutions().size(); i++) {
-                if ((Long) importConfiguration.getExecutions().get(i).get("date") < oldestExecDate) {
-                    oldestExecDate = (Long) importConfiguration.getExecutions().get(i).get("date");
-                    oldestExecIndex = i;
-                }
-            }
-            importConfiguration.getExecutions().remove(oldestExecIndex);
-        }
+        importConfiguration = (ImportConfiguration) RouterUtils.addExecutionEntry(importConfiguration, execution,executionsHistorySize);
 
         importConfiguration.getExecutions().add(execution);
         //Set running to false, route is complete

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/LineBuildProcessor.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/LineBuildProcessor.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/LineBuildProcessor.java
index 6f83741..b640405 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/LineBuildProcessor.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/processor/LineBuildProcessor.java
@@ -20,11 +20,10 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.router.api.ExportConfiguration;
+import org.apache.unomi.router.api.services.ProfileExportService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Map;
-
 /**
  * Created by amidani on 28/06/2017.
  */
@@ -32,21 +31,18 @@ public class LineBuildProcessor implements Processor {
 
     private static final Logger logger = LoggerFactory.getLogger(LineBuildProcessor.class);
 
+    private ProfileExportService profileExportService;
+
+    public LineBuildProcessor(ProfileExportService profileExportService) {
+        this.profileExportService = profileExportService;
+    }
+
     @Override
     public void process(Exchange exchange) throws Exception {
         ExportConfiguration exportConfiguration = (ExportConfiguration) exchange.getIn().getHeader("exportConfig");
-        exchange.getIn().setHeader("destination", exportConfiguration.getProperty("destination"));
         Profile profile = exchange.getIn().getBody(Profile.class);
 
-        Map<String, String> mapping = (Map<String, String>) exportConfiguration.getProperty("mapping");
-        String lineToWrite = "";
-        for (int i = 0; i < mapping.size(); i++) {
-            String propertyName = mapping.get(String.valueOf(i));
-            lineToWrite += profile.getProperty(propertyName) != null ? profile.getProperty(propertyName) : "";
-            if (i + 1 < mapping.size()) {
-                lineToWrite += exportConfiguration.getColumnSeparator();
-            }
-        }
+        String lineToWrite = profileExportService.convertProfileToCSVLine(profile, exportConfiguration);
 
         exchange.getIn().setBody(lineToWrite, String.class);
     }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportCollectRouteBuilder.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportCollectRouteBuilder.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportCollectRouteBuilder.java
index b67859a..4b6a34e 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportCollectRouteBuilder.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportCollectRouteBuilder.java
@@ -60,11 +60,13 @@ public class ProfileExportCollectRouteBuilder extends RouterAbstractRouteBuilder
 
         //Loop on multiple export configuration
         for (final ExportConfiguration exportConfiguration : exportConfigurationList) {
-            if (exportConfiguration.getProperties() != null && exportConfiguration.getProperties().size() > 0) {
+            if (RouterConstants.IMPORT_EXPORT_CONFIG_TYPE_RECURRENT.equals(exportConfiguration.getConfigType()) &&
+                    exportConfiguration.getProperties() != null && exportConfiguration.getProperties().size() > 0) {
                 if ((Map<String, String>) exportConfiguration.getProperties().get("mapping") != null) {
                     String destinationEndpoint = (String) exportConfiguration.getProperties().get("destination");
                     if (StringUtils.isNotBlank(destinationEndpoint) && allowedEndpoints.contains(destinationEndpoint.substring(0, destinationEndpoint.indexOf(':')))) {
                         ProcessorDefinition prDef = from("timer://collectProfile?fixedRate=true&period=" + (String) exportConfiguration.getProperties().get("period"))
+                                .routeId(exportConfiguration.getItemId())// This allow identification of the route for manual start/stop
                                 .autoStartup(exportConfiguration.isActive())
                                 .bean(collectProfileBean, "extractProfileBySegment(" + exportConfiguration.getProperties().get("segment") + ")")
                                 .split(body())

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportProducerRouteBuilder.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportProducerRouteBuilder.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportProducerRouteBuilder.java
index 0b0b60a..bfcd8ae 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportProducerRouteBuilder.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileExportProducerRouteBuilder.java
@@ -19,6 +19,7 @@ package org.apache.unomi.router.core.route;
 import org.apache.camel.component.kafka.KafkaEndpoint;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.unomi.router.api.RouterConstants;
+import org.apache.unomi.router.api.services.ProfileExportService;
 import org.apache.unomi.router.core.processor.ExportRouteCompletionProcessor;
 import org.apache.unomi.router.core.processor.LineBuildProcessor;
 import org.apache.unomi.router.core.strategy.StringLinesAggregationStrategy;
@@ -36,10 +37,16 @@ public class ProfileExportProducerRouteBuilder extends RouterAbstractRouteBuilde
 
     private ExportRouteCompletionProcessor exportRouteCompletionProcessor;
 
+    private ProfileExportService profileExportService;
+
     public ProfileExportProducerRouteBuilder(Map<String, String> kafkaProps, String configType) {
         super(kafkaProps, configType);
     }
 
+    public void setProfileExportService(ProfileExportService profileExportService) {
+        this.profileExportService = profileExportService;
+    }
+
     @Override
     public void configure() throws Exception {
 
@@ -53,7 +60,7 @@ public class ProfileExportProducerRouteBuilder extends RouterAbstractRouteBuilde
         }
 
         rtDef.unmarshal(jacksonDataFormat)
-                .process(new LineBuildProcessor())
+                .process(new LineBuildProcessor(profileExportService))
                 .aggregate(constant(true), new StringLinesAggregationStrategy())
                 .completionPredicate(exchangeProperty("CamelSplitSize").isEqualTo(exchangeProperty("CamelAggregatedSize")))
                 .eagerCheckCompletion()

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileImportFromSourceRouteBuilder.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileImportFromSourceRouteBuilder.java b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileImportFromSourceRouteBuilder.java
index 2dc87f3..e3ec8bd 100644
--- a/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileImportFromSourceRouteBuilder.java
+++ b/extensions/router/router-core/src/main/java/org/apache/unomi/router/core/route/ProfileImportFromSourceRouteBuilder.java
@@ -73,7 +73,7 @@ public class ProfileImportFromSourceRouteBuilder extends RouterAbstractRouteBuil
         //Loop on multiple import configuration
         for (final ImportConfiguration importConfiguration : importConfigurationList) {
             if (RouterConstants.IMPORT_EXPORT_CONFIG_TYPE_RECURRENT.equals(importConfiguration.getConfigType()) &&
-                    importConfiguration.getProperties().size() > 0) {
+                    importConfiguration.getProperties() != null && importConfiguration.getProperties().size() > 0) {
                 //Prepare Split Processor
                 LineSplitProcessor lineSplitProcessor = new LineSplitProcessor();
                 lineSplitProcessor.setFieldsMapping((Map<String, Integer>) importConfiguration.getProperties().get("mapping"));

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/extensions/router/router-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 3b155b2..7ea578b 100644
--- a/extensions/router/router-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/extensions/router/router-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -93,6 +93,7 @@
         <property name="configType" value="${config.type}"/>
         <property name="allowedEndpoints" value="${config.allowedEndpoints}"/>
         <property name="uploadDir" value="${import.oneshot.uploadDir}"/>
+        <property name="execHistorySize" value="${executionsHistory.size}"/>
         <property name="bundleContext" ref="blueprintBundleContext"/>
         <property name="jacksonDataFormat" ref="jacksonDataFormat"/>
         <property name="kafkaProps">
@@ -115,6 +116,7 @@
         <property name="exportConfigurationService" ref="exportConfigurationService"/>
         <property name="importConfigurationService" ref="importConfigurationService"/>
         <property name="persistenceService" ref="persistenceService"/>
+        <property name="profileExportService" ref="profileExportService"/>
     </bean>
 
     <camel:camelContext id="httpEndpoint" xmlns="http://camel.apache.org/schema/blueprint">
@@ -132,6 +134,7 @@
     <reference id="configSharingService" interface="org.apache.unomi.api.services.ConfigSharingService" />
     <reference id="httpService" interface="org.osgi.service.http.HttpService"/>
     <reference id="profileImportService" interface="org.apache.unomi.router.api.services.ProfileImportService"/>
+    <reference id="profileExportService" interface="org.apache.unomi.router.api.services.ProfileExportService"/>
     <reference id="persistenceService" interface="org.apache.unomi.persistence.spi.PersistenceService"/>
     <reference id="importConfigurationService" interface="org.apache.unomi.router.api.services.ImportExportConfigurationService" filter="(configDiscriminator=IMPORT)"/>
     <reference id="exportConfigurationService" interface="org.apache.unomi.router.api.services.ImportExportConfigurationService" filter="(configDiscriminator=EXPORT)"/>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-core/src/main/resources/org.apache.unomi.router.cfg
----------------------------------------------------------------------
diff --git a/extensions/router/router-core/src/main/resources/org.apache.unomi.router.cfg b/extensions/router/router-core/src/main/resources/org.apache.unomi.router.cfg
index 8f29d65..22d7496 100644
--- a/extensions/router/router-core/src/main/resources/org.apache.unomi.router.cfg
+++ b/extensions/router/router-core/src/main/resources/org.apache.unomi.router.cfg
@@ -37,4 +37,4 @@ import.oneshot.uploadDir=${karaf.data}/tmp/unomi_oneshot_import_configs/
 executionsHistory.size=5
 
 #Allowed source endpoints
-config.allowedEndpoints=file,ftp
\ No newline at end of file
+config.allowedEndpoints=file,ftp,sftp,ftps
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-karaf-feature/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-karaf-feature/pom.xml b/extensions/router/router-karaf-feature/pom.xml
index de8e1d9..6aa6d49 100644
--- a/extensions/router/router-karaf-feature/pom.xml
+++ b/extensions/router/router-karaf-feature/pom.xml
@@ -50,6 +50,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core-osgi</artifactId>
+            <version>${camel.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-blueprint</artifactId>
             <version>${camel.version}</version>
         </dependency>
@@ -147,7 +152,7 @@
                 <groupId>org.apache.karaf.tooling</groupId>
                 <artifactId>karaf-maven-plugin</artifactId>
                 <configuration>
-                    <startLevel>77</startLevel>
+                    <startLevel>90</startLevel>
                 </configuration>
             </plugin>
         </plugins>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-rest/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-rest/pom.xml b/extensions/router/router-rest/pom.xml
index 3d7b411..d3528ba 100644
--- a/extensions/router/router-rest/pom.xml
+++ b/extensions/router/router-rest/pom.xml
@@ -42,6 +42,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.unomi</groupId>
+            <artifactId>unomi-persistence-spi</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>javax.ws.rs</groupId>
             <artifactId>javax.ws.rs-api</artifactId>
             <version>2.0.1</version>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ExportConfigurationServiceEndPoint.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ExportConfigurationServiceEndPoint.java b/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ExportConfigurationServiceEndPoint.java
index b3bcf65..98dbe18 100644
--- a/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ExportConfigurationServiceEndPoint.java
+++ b/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ExportConfigurationServiceEndPoint.java
@@ -26,13 +26,18 @@ import org.apache.http.impl.client.HttpClients;
 import org.apache.unomi.router.api.ExportConfiguration;
 import org.apache.unomi.router.api.RouterConstants;
 import org.apache.unomi.router.api.services.ImportExportConfigurationService;
+import org.apache.unomi.router.api.services.ProfileExportService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.jws.WebMethod;
 import javax.jws.WebService;
+import javax.ws.rs.*;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 /**
  * A JAX-RS endpoint to manage {@link ExportConfiguration}s.
@@ -46,6 +51,8 @@ public class ExportConfigurationServiceEndPoint extends AbstractConfigurationSer
 
     private static final Logger logger = LoggerFactory.getLogger(ExportConfigurationServiceEndPoint.class.getName());
 
+    private ProfileExportService profileExportService;
+
     public ExportConfigurationServiceEndPoint() {
         logger.info("Initializing export configuration service endpoint...");
     }
@@ -55,6 +62,11 @@ public class ExportConfigurationServiceEndPoint extends AbstractConfigurationSer
         configurationService = exportConfigurationService;
     }
 
+    @WebMethod(exclude = true)
+    public void setProfileExportService(ProfileExportService profileExportService) {
+        this.profileExportService = profileExportService;
+    }
+
     /**
      * Save the given export configuration.
      *
@@ -83,4 +95,23 @@ public class ExportConfigurationServiceEndPoint extends AbstractConfigurationSer
 
         return exportConfigSaved;
     }
+
+    /**
+     * Save/Update the given import configuration.
+     * Prepare the file to be processed with Camel routes
+     *
+     * @return OK / NOK Http Code.
+     */
+    @POST
+    @Path("/oneshot")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces("text/csv")
+    public Response processOneshotImportConfigurationCSV(ExportConfiguration exportConfiguration) {
+        ExportConfiguration exportConfigSaved = configurationService.save(exportConfiguration);
+        String csvContent = profileExportService.extractProfilesBySegment(exportConfigSaved);
+        Response.ResponseBuilder response = Response.ok(csvContent);
+        response.header("Content-Disposition",
+                "attachment; filename=Profiles_export_" + new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(new Date()) + ".csv");
+        return response.build();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-rest/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-rest/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/extensions/router/router-rest/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 6c3c367..9be4a07 100644
--- a/extensions/router/router-rest/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/extensions/router/router-rest/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -67,6 +67,7 @@
                filter="(configDiscriminator=EXPORT)"/>
 
     <reference id="configSharingService" interface="org.apache.unomi.api.services.ConfigSharingService"/>
+    <reference id="profileExportService" interface="org.apache.unomi.router.api.services.ProfileExportService"/>
 
     <bean id="importConfigurationServiceEndPoint" class="org.apache.unomi.router.rest.ImportConfigurationServiceEndPoint">
         <property name="importConfigurationService" ref="importConfigurationService"/>
@@ -76,6 +77,7 @@
     <bean id="exportConfigurationServiceEndPoint" class="org.apache.unomi.router.rest.ExportConfigurationServiceEndPoint">
         <property name="exportConfigurationService" ref="exportConfigurationService"/>
         <property name="configSharingService" ref="configSharingService"/>
+        <property name="profileExportService" ref="profileExportService"/>
     </bean>
 
 </blueprint>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/AbstractCustomServiceImpl.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/AbstractCustomServiceImpl.java b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/AbstractCustomServiceImpl.java
new file mode 100644
index 0000000..4e36141
--- /dev/null
+++ b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/AbstractCustomServiceImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.router.services;
+
+import org.apache.unomi.persistence.spi.PersistenceService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by amidani on 30/06/2017.
+ */
+public class AbstractCustomServiceImpl implements SynchronousBundleListener {
+
+    private static final Logger logger = LoggerFactory.getLogger(AbstractCustomServiceImpl.class);
+
+    protected PersistenceService persistenceService;
+    protected BundleContext bundleContext;
+
+    public void setPersistenceService(PersistenceService persistenceService) {
+        this.persistenceService = persistenceService;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void postConstruct() {
+        logger.debug("postConstruct {" + bundleContext.getBundle() + "}");
+
+        processBundleStartup(bundleContext);
+        for (Bundle bundle : bundleContext.getBundles()) {
+            if (bundle.getBundleContext() != null) {
+                processBundleStartup(bundle.getBundleContext());
+            }
+        }
+        bundleContext.addBundleListener(this);
+        logger.info("Import configuration service initialized.");
+    }
+
+    public void preDestroy() {
+        bundleContext.removeBundleListener(this);
+        logger.info("Import configuration service shutdown.");
+    }
+
+    private void processBundleStartup(BundleContext bundleContext) {
+        if (bundleContext == null) {
+            return;
+        }
+    }
+
+    private void processBundleStop(BundleContext bundleContext) {
+    }
+
+    @Override
+    public void bundleChanged(BundleEvent bundleEvent) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileExportServiceImpl.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileExportServiceImpl.java b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileExportServiceImpl.java
new file mode 100644
index 0000000..0713050
--- /dev/null
+++ b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileExportServiceImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.router.services;
+
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.services.ConfigSharingService;
+import org.apache.unomi.router.api.ExportConfiguration;
+import org.apache.unomi.router.api.RouterConstants;
+import org.apache.unomi.router.api.RouterUtils;
+import org.apache.unomi.router.api.services.ImportExportConfigurationService;
+import org.apache.unomi.router.api.services.ProfileExportService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by amidani on 30/06/2017.
+ */
+public class ProfileExportServiceImpl extends AbstractCustomServiceImpl implements ProfileExportService {
+
+    private static final Logger logger = LoggerFactory.getLogger(ProfileExportServiceImpl.class.getName());
+
+    private ConfigSharingService configSharingService;
+
+    public String extractProfilesBySegment(ExportConfiguration exportConfiguration) {
+        List<Profile> profileList = persistenceService.query("segments", (String) exportConfiguration.getProperty("segment"), null, Profile.class);
+        String csvContent = "";
+        for (Profile profile : profileList) {
+            csvContent += convertProfileToCSVLine(profile, exportConfiguration);
+            csvContent += exportConfiguration.getLineSeparator();
+        }
+        logger.debug("Exporting {} extracted profiles.", profileList.size());
+        Map<String, Object> returnMap = new HashMap();
+
+        Map execution = new HashMap();
+        execution.put(RouterConstants.KEY_EXECS_DATE, new Date().getTime());
+        execution.put(RouterConstants.KEY_EXECS_EXTRACTED, profileList.size());
+
+        exportConfiguration = (ExportConfiguration) RouterUtils.addExecutionEntry(exportConfiguration, execution, Integer.parseInt((String) configSharingService.getProperty(RouterConstants.KEY_HISTORY_SIZE)));
+        persistenceService.save(exportConfiguration);
+
+        returnMap.put(RouterConstants.KEY_CSV_CONTENT, csvContent);
+        returnMap.put(RouterConstants.KEY_EXECS, execution);
+
+        return csvContent;
+    }
+
+    public String convertProfileToCSVLine(Profile profile, ExportConfiguration exportConfiguration) {
+        Map<String, String> mapping = (Map<String, String>) exportConfiguration.getProperty("mapping");
+        String lineToWrite = "";
+        for (int i = 0; i < mapping.size(); i++) {
+            String propertyName = mapping.get(String.valueOf(i));
+            lineToWrite += profile.getProperty(propertyName) != null ? profile.getProperty(propertyName) : "";
+            if (i + 1 < mapping.size()) {
+                lineToWrite += exportConfiguration.getColumnSeparator();
+            }
+        }
+        return lineToWrite;
+    }
+
+    public void setConfigSharingService(ConfigSharingService configSharingService) {
+        this.configSharingService = configSharingService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileImportServiceImpl.java
----------------------------------------------------------------------
diff --git a/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileImportServiceImpl.java b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileImportServiceImpl.java
index cb1d706..aad6782 100644
--- a/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileImportServiceImpl.java
+++ b/extensions/router/router-service/src/main/java/org/apache/unomi/router/services/ProfileImportServiceImpl.java
@@ -18,14 +18,8 @@ package org.apache.unomi.router.services;
 
 import org.apache.commons.beanutils.BeanUtils;
 import org.apache.unomi.api.Profile;
-import org.apache.unomi.api.services.EventListenerService;
-import org.apache.unomi.persistence.spi.PersistenceService;
 import org.apache.unomi.router.api.ProfileToImport;
 import org.apache.unomi.router.api.services.ProfileImportService;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.SynchronousBundleListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,75 +29,35 @@ import java.util.List;
 /**
  * Created by amidani on 18/05/2017.
  */
-public class ProfileImportServiceImpl implements ProfileImportService, SynchronousBundleListener {
+public class ProfileImportServiceImpl extends AbstractCustomServiceImpl implements ProfileImportService {
 
     private static final Logger logger = LoggerFactory.getLogger(ProfileImportServiceImpl.class.getName());
 
-    private PersistenceService persistenceService;
-
-    private BundleContext bundleContext;
-
-    public void setPersistenceService(PersistenceService persistenceService) {
-        this.persistenceService = persistenceService;
-    }
-
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
-
-    public void postConstruct() {
-        logger.debug("postConstruct {" + bundleContext.getBundle() + "}");
-
-        processBundleStartup(bundleContext);
-        for (Bundle bundle : bundleContext.getBundles()) {
-            if (bundle.getBundleContext() != null) {
-                processBundleStartup(bundle.getBundleContext());
-            }
-        }
-        bundleContext.addBundleListener(this);
-        logger.info("Import configuration service initialized.");
-    }
-
-    public void preDestroy() {
-        bundleContext.removeBundleListener(this);
-        logger.info("Import configuration service shutdown.");
-    }
-
-    private void processBundleStartup(BundleContext bundleContext) {
-        if (bundleContext == null) {
-            return;
-        }
-    }
-
-    private void processBundleStop(BundleContext bundleContext) {
-    }
-
-
     public boolean saveMergeDeleteImportedProfile(ProfileToImport profileToImport) throws InvocationTargetException, IllegalAccessException {
         logger.debug("Importing profile with ID : {}", profileToImport.getItemId());
         Profile existingProfile = new Profile();
-        List<Profile> existingProfiles = persistenceService.query("properties."+profileToImport.getMergingProperty(), (String)profileToImport.getProperties().get(profileToImport.getMergingProperty()), null, Profile.class);
+        List<Profile> existingProfiles = persistenceService.query("properties." + profileToImport.getMergingProperty(), (String) profileToImport.getProperties().get(profileToImport.getMergingProperty()), null, Profile.class);
         logger.debug("Query existing profile with mergingProperty: {}. Found: {}", profileToImport.getMergingProperty(), existingProfiles.size());
 
         //Profile already exist, and import config allow to overwrite profiles
-        if(existingProfiles.size() == 1) {
+        if (existingProfiles.size() == 1) {
             existingProfile = existingProfiles.get(0);
-            if(profileToImport.isProfileToDelete()) {
+            if (profileToImport.isProfileToDelete()) {
                 logger.debug("Profile is to delete!");
                 persistenceService.remove(existingProfile.getItemId(), Profile.class);
                 return true;
             }
             List<String> propertiesToOverwrite = profileToImport.getPropertiesToOverwrite();
-            if(profileToImport.isOverwriteExistingProfiles() && propertiesToOverwrite!=null && propertiesToOverwrite.size() > 0) { // We overwrite only properties marked to overwrite
+            if (profileToImport.isOverwriteExistingProfiles() && propertiesToOverwrite != null && propertiesToOverwrite.size() > 0) { // We overwrite only properties marked to overwrite
                 logger.debug("Properties to overwrite: {}", propertiesToOverwrite);
-                for(String propName : propertiesToOverwrite) {
+                for (String propName : propertiesToOverwrite) {
                     existingProfile.getProperties().put(propName, profileToImport.getProperties().get(propName));
                 }
             } else { //If no property is marked to overwrite we replace the whole properties map
                 logger.debug("Overwrite all properties");
                 existingProfile.setProperties(profileToImport.getProperties());
             }
-        } else if(existingProfiles.size() == 0) {
+        } else if (existingProfiles.size() == 0) {
             logger.debug("New profile to add...");
             BeanUtils.copyProperties(existingProfile, profileToImport);
         } else {
@@ -113,9 +67,4 @@ public class ProfileImportServiceImpl implements ProfileImportService, Synchrono
         logger.debug("-------------------------------------");
         return persistenceService.save(existingProfile);
     }
-
-    @Override
-    public void bundleChanged(BundleEvent bundleEvent) {
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/extensions/router/router-service/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/extensions/router/router-service/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/extensions/router/router-service/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index ac66f41..abbc72d 100644
--- a/extensions/router/router-service/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/extensions/router/router-service/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -21,6 +21,7 @@
            xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
 
     <reference id="persistenceService" interface="org.apache.unomi.persistence.spi.PersistenceService"/>
+    <reference id="configSharingService" interface="org.apache.unomi.api.services.ConfigSharingService"/>
 
     <bean id="importConfigurationServiceImpl" class="org.apache.unomi.router.services.ImportConfigurationServiceImpl"
           init-method="postConstruct" destroy-method="preDestroy">
@@ -51,4 +52,12 @@
     </bean>
     <service id="profileImportService" ref="profileImportServiceImpl" auto-export="interfaces"/>
 
+    <bean id="profileExportServiceImpl" class="org.apache.unomi.router.services.ProfileExportServiceImpl"
+          init-method="postConstruct" destroy-method="preDestroy">
+        <property name="persistenceService" ref="persistenceService"/>
+        <property name="configSharingService" ref="configSharingService" />
+        <property name="bundleContext" ref="blueprintBundleContext"/>
+    </bean>
+    <service id="profileExportService" ref="profileExportServiceImpl" auto-export="interfaces"/>
+
 </blueprint>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/9794636f/kar/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/kar/src/main/feature/feature.xml b/kar/src/main/feature/feature.xml
index e3351b7..e541135 100644
--- a/kar/src/main/feature/feature.xml
+++ b/kar/src/main/feature/feature.xml
@@ -22,6 +22,7 @@
         <feature>war</feature>
         <feature>cxf</feature>
         <feature>cellar</feature>
+        <feature>eventadmin</feature>
         <configfile finalname="/etc/org.apache.unomi.web.cfg">mvn:org.apache.unomi/unomi-wab/${project.version}/cfg/unomicfg</configfile>
         <configfile finalname="/etc/org.apache.unomi.persistence.elasticsearch.cfg">mvn:org.apache.unomi/unomi-persistence-elasticsearch-core/${project.version}/cfg/elasticsearchcfg</configfile>
         <configfile finalname="/etc/org.apache.unomi.plugins.request.cfg">mvn:org.apache.unomi/unomi-plugins-request/${project.version}/cfg/requestcfg</configfile>