You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by dg...@apache.org on 2017/10/06 13:33:27 UTC
[03/15] incubator-unomi git commit: UNOMI-117 Create tools package
that contain a shell bundle so we can define our custom shell commands for
unomi, create a migration shell command to ease the migration to a new version
UNOMI-117 Create tools package that contain a shell bundle so we can define our custom shell commands for unomi, create a migration shell command to ease the migration to a new version
Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/f0100317
Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/f0100317
Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/f0100317
Branch: refs/heads/master
Commit: f0100317f5788aa5044f31916ae7d9ad50ebd9c8
Parents: ebfd560
Author: dgaillard <dg...@jahia.com>
Authored: Fri Sep 8 17:50:12 2017 +0200
Committer: dgaillard <dg...@jahia.com>
Committed: Thu Sep 28 10:49:15 2017 +0200
----------------------------------------------------------------------
pom.xml | 1 +
tools/pom.xml | 37 +++++
tools/shell-commands/pom.xml | 108 +++++++++++++
.../org/apache/unomi/shell/actions/Migrate.java | 67 ++++++++
.../org/apache/unomi/shell/actions/Version.java | 29 ++++
.../migrations/AbstractMigrationResource.java | 81 ++++++++++
.../unomi/shell/migrations/MigrationTo200.java | 130 ++++++++++++++++
.../apache/unomi/shell/utils/ConsoleUtils.java | 82 ++++++++++
.../org/apache/unomi/shell/utils/HttpUtils.java | 155 +++++++++++++++++++
.../resources/OSGI-INF/blueprint/blueprint.xml | 32 ++++
10 files changed, 722 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 84b09f5..fefee15 100644
--- a/pom.xml
+++ b/pom.xml
@@ -847,6 +847,7 @@
<module>kar</module>
<module>samples</module>
<module>package</module>
+ <module>tools</module>
</modules>
<dependencies>
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/pom.xml
----------------------------------------------------------------------
diff --git a/tools/pom.xml b/tools/pom.xml
new file mode 100644
index 0000000..9a42616
--- /dev/null
+++ b/tools/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.unomi</groupId>
+ <artifactId>unomi-root</artifactId>
+ <version>1.2.0-incubating-unomi_117-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>unomi-tools</artifactId>
+ <name>Apache Unomi :: Tools</name>
+ <description>Apache Unomi Context Server tools</description>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>shell-commands</module>
+ </modules>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/pom.xml
----------------------------------------------------------------------
diff --git a/tools/shell-commands/pom.xml b/tools/shell-commands/pom.xml
new file mode 100644
index 0000000..51f1f06
--- /dev/null
+++ b/tools/shell-commands/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>unomi-tools</artifactId>
+ <groupId>org.apache.unomi</groupId>
+ <version>1.2.0-incubating-unomi_117-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>shell-commands</artifactId>
+ <name>Apache Unomi :: Tools :: Shell commands</name>
+ <description>Provides the shell commands to interact with Apache Unomi Context Server</description>
+ <version>1.2.0-incubating-unomi_117-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ <version>3.0.8</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient-osgi</artifactId>
+ <version>4.5.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20160212</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>5.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.5.4</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Export-Package>org.apache.unomi*;version=${project.version}</Export-Package>
+ <Import-Package>!org.apache.unomi*,
+ org.apache.aries.blueprint,
+ org.osgi.service.blueprint.container,
+ org.osgi.service.blueprint.reflect,
+ org.apache.felix.service.command,
+ org.apache.karaf.shell.commands,
+ org.apache.karaf.shell.console,
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Migrate.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Migrate.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Migrate.java
new file mode 100644
index 0000000..f24a884
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Migrate.java
@@ -0,0 +1,67 @@
+/*
+ * 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.shell.actions;
+
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.unomi.shell.migrations.MigrationTo200;
+import org.apache.unomi.shell.utils.ConsoleUtils;
+import org.osgi.framework.Version;
+
+import java.util.*;
+
+@Command(scope = "unomi", name = "migrate", description = "This will Migrate your date in ES to be compliant with current version")
+public class Migrate extends OsgiCommandSupport {
+
+ @Argument(name = "fromVersionWithoutSuffix", description = "Origin version without suffix/qualifier (e.g: 1.2.0)", required = true, multiValued = false, valueToShowInHelp = "1.2.0")
+ private String fromVersionWithoutSuffix;
+
+ protected Object doExecute() throws Exception {
+ String confirmation = ConsoleUtils.askUserWithAuthorizedAnswer(session,"[WARNING] You are about to execute a migration, this a very sensitive operation, are you sure? (yes/no): ", Arrays.asList("yes", "no"));
+ if (confirmation.equalsIgnoreCase("no")) {
+ System.out.println("Migration process aborted");
+ return null;
+ }
+
+ System.out.println("Starting migration process from version: " + fromVersionWithoutSuffix);
+
+ Version fromVersion = new Version(fromVersionWithoutSuffix);
+ Version currentVersion = getCurrentVersionWithoutQualifier();
+ System.out.println("current version: " + currentVersion.toString());
+ if (currentVersion.compareTo(fromVersion) <= 0) {
+ System.out.println("From version is same or superior than current version, nothing to migrate.");
+ return null;
+ }
+
+ if (fromVersion.compareTo(new Version("2.0.0")) < 0) {
+ System.out.println("Starting migration to version 2.0.0");
+
+ MigrationTo200 migrationTo200 = new MigrationTo200(session);
+ migrationTo200.execute();
+
+ System.out.println("Migration to version 2.0.0 done successfully");
+ }
+
+ return null;
+ }
+
+ private Version getCurrentVersionWithoutQualifier() {
+ Version currentVersion = bundleContext.getBundle().getVersion();
+ return new Version(currentVersion.getMajor() + "." + currentVersion.getMinor() + "." + currentVersion.getMicro());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Version.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Version.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Version.java
new file mode 100644
index 0000000..50661e0
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Version.java
@@ -0,0 +1,29 @@
+/*
+ * 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.shell.actions;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+
+@Command(scope = "unomi", name = "version", description = "This will print Apache Unomi current version")
+public class Version extends OsgiCommandSupport {
+
+ protected Object doExecute() throws Exception {
+ System.out.println("Apache Unomi version: " + bundleContext.getBundle().getVersion().toString());
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/AbstractMigrationResource.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/AbstractMigrationResource.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/AbstractMigrationResource.java
new file mode 100644
index 0000000..37171a0
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/AbstractMigrationResource.java
@@ -0,0 +1,81 @@
+/*
+ * 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.shell.migrations;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.http.HttpEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.apache.unomi.shell.utils.ConsoleUtils;
+import org.apache.unomi.shell.utils.HttpUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author dgaillard
+ */
+public abstract class AbstractMigrationResource {
+ protected CloseableHttpClient httpClient;
+ protected CommandSession session;
+
+ protected AbstractMigrationResource(CommandSession session) throws IOException {
+ this.session = session;
+ }
+
+ protected void initHttpClient() throws IOException {
+ if (httpClient == null) {
+ String confirmation = ConsoleUtils.askUserWithAuthorizedAnswer(session,"We need to initialize a HttpClient, do we need to trust all certificates? (yes/no):", Arrays.asList("yes", "no"));
+ httpClient = HttpUtils.initHttpClient(confirmation.equalsIgnoreCase("yes"));
+ }
+ }
+
+ protected void closeHttpClient() throws IOException {
+ if (httpClient != null) {
+ httpClient.close();
+ }
+ }
+
+ protected List<JSONArray> getDataToMigrate(String url, int offset, int size) throws IOException {
+ String jsonData = "{\"query\":{\"bool\":{\"should\":[{\"match_all\":{}}]}},\"from\":" + offset + ",\"size\":" + size + "}";
+
+ HttpEntity entity = HttpUtils.executePostRequest(httpClient, url, jsonData, null);
+ JSONObject responseJSON = new JSONObject(EntityUtils.toString(entity));
+ EntityUtils.consumeQuietly(entity);
+
+ List<JSONArray> totalHits = new ArrayList<>();
+ if (responseJSON.has("hits")) {
+ JSONObject hitsObject = responseJSON.getJSONObject("hits");
+ JSONArray hits = hitsObject.getJSONArray("hits");
+ totalHits.add(hits);
+ int newOffset = size + offset;
+ if (newOffset <= hitsObject.getInt("total")) {
+ totalHits.addAll(getDataToMigrate(url, newOffset, size));
+ }
+ }
+
+ return totalHits;
+ }
+
+ protected void bulkUpdate(String url, String jsonData) throws IOException {
+ HttpEntity entity = HttpUtils.executePostRequest(httpClient, url, jsonData, null);
+ JSONObject responseJSON = new JSONObject(EntityUtils.toString(entity));
+ EntityUtils.consumeQuietly(entity);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/MigrationTo200.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/MigrationTo200.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/MigrationTo200.java
new file mode 100644
index 0000000..134db02
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/MigrationTo200.java
@@ -0,0 +1,130 @@
+/*
+ * 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.shell.migrations;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.unomi.shell.utils.ConsoleUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author dgaillard
+ */
+public class MigrationTo200 extends AbstractMigrationResource {
+
+ public MigrationTo200(CommandSession session) throws IOException {
+ super(session);
+ }
+
+ public void execute() throws IOException {
+ try {
+ initHttpClient();
+ migrateTags();
+ } catch (IOException e) {
+ closeHttpClient();
+ throw e;
+ }
+ }
+
+ private void migrateTags() throws IOException {
+ String hostAddress = ConsoleUtils.askUserWithDefaultAnswer(session, "Host address (default = http://localhost:9200): ", "http://localhost:9200");
+
+ List<JSONArray> totalHits = getDataToMigrate(hostAddress + "/context/propertyType/_search", 0, 10);
+
+ StringBuilder updatedHits = new StringBuilder();
+ for (JSONArray hits : totalHits) {
+ Iterator<Object> hitsIterator = hits.iterator();
+ LinkedHashMap<String, List<String>> legacyTags = getTagsStructurePriorTo200();
+ while (hitsIterator.hasNext()) {
+ JSONObject hit = (JSONObject) hitsIterator.next();
+ if (hit.has("_source")) {
+ JSONObject hitSource = hit.getJSONObject("_source");
+ if (hitSource.has("tags")) {
+ JSONArray hitTags = hitSource.getJSONArray("tags");
+ Iterator<Object> tagsIterator = hitTags.iterator();
+ List<String> tagsBeforeMigration = new ArrayList<>();
+ List<String> tagsAfterMigration = new ArrayList<>();
+ while (tagsIterator.hasNext()) {
+ tagsBeforeMigration.add((String) tagsIterator.next());
+ }
+ for (String tag : tagsBeforeMigration) {
+ if (legacyTags.containsKey(tag) && !tagsAfterMigration.containsAll(legacyTags.get(tag))) {
+ tagsAfterMigration.addAll(legacyTags.get(tag));
+ }
+
+ if (!tagsAfterMigration.contains(tag)) {
+ tagsAfterMigration.add(tag);
+ }
+ }
+
+ updatedHits.append("{\"update\":{\"_id\":\"").append(hit.getString("_id")).append("\"}}\n");
+ updatedHits.append("{\"doc\":{\"tags\":").append(new JSONArray(tagsAfterMigration)).append("}}\n");
+ }
+ }
+ }
+ }
+ bulkUpdate(hostAddress + "/context/propertyType/_bulk", updatedHits.toString());
+ }
+
+ private LinkedHashMap<String, List<String>> getTagsStructurePriorTo200() {
+ LinkedHashMap<String, List<String>> tags = new LinkedHashMap<>();
+ tags.put("landing", Collections.singletonList("campaign"));
+ tags.put("parameter", Collections.singletonList("campaign"));
+ tags.put("referrer", Collections.singletonList("campaign"));
+
+ tags.put("eventCondition", Collections.singletonList("condition"));
+ tags.put("profileCondition", Collections.singletonList("condition"));
+ tags.put("sessionCondition", Collections.singletonList("condition"));
+ tags.put("sourceEventCondition", Collections.singletonList("condition"));
+ tags.put("trackedCondition", Collections.singletonList("condition"));
+ tags.put("usableInPastEventCondition", Collections.singletonList("condition"));
+
+ tags.put("formMappingRule", Collections.<String>emptyList());
+
+ tags.put("downloadGoal", Collections.singletonList("goal"));
+ tags.put("formGoal", Collections.singletonList("goal"));
+ tags.put("funnelGoal", Collections.singletonList("goal"));
+ tags.put("landingPageGoal", Collections.singletonList("goal"));
+ tags.put("pageVisitGoal", Collections.singletonList("goal"));
+ tags.put("videoGoal", Collections.singletonList("goal"));
+
+ tags.put("aggregated", Collections.singletonList("profileTags"));
+ tags.put("autocompleted", Collections.singletonList("profileTags"));
+ tags.put("demographic", Collections.singletonList("profileTags"));
+ tags.put("event", Collections.singletonList("profileTags"));
+ tags.put("geographic", Collections.singletonList("profileTags"));
+ tags.put("logical", Collections.singletonList("profileTags"));
+
+ tags.put("profileProperties", Collections.singletonList("properties"));
+ tags.put("systemProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("basicProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("leadProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("contactProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("socialProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("personalProfileProperties", Arrays.asList("properties", "profileProperties"));
+ tags.put("workProfileProperties", Arrays.asList("properties", "profileProperties"));
+
+ tags.put("sessionProperties", Collections.singletonList("properties"));
+ tags.put("geographicSessionProperties", Arrays.asList("properties", "sessionProperties"));
+ tags.put("technicalSessionProperties", Arrays.asList("properties", "sessionProperties"));
+
+ return tags;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/ConsoleUtils.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/ConsoleUtils.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/ConsoleUtils.java
new file mode 100644
index 0000000..b2c6323
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/ConsoleUtils.java
@@ -0,0 +1,82 @@
+/*
+ * 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.shell.utils;
+
+import jline.console.ConsoleReader;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.felix.service.command.CommandSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author dgaillard
+ */
+public class ConsoleUtils {
+ private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
+
+ /**
+ * This will ask a question to the user and return the default answer if the user does not answer.
+ *
+ * @param session CommandSession
+ * @param msg String message to ask
+ * @param defaultAnswer String default answer
+ * @return the user answer
+ * @throws IOException
+ */
+ public static String askUserWithDefaultAnswer(CommandSession session, String msg, String defaultAnswer) throws IOException {
+ String answer = promptMessageToUser(session, msg);
+ if (StringUtils.isBlank(answer)) {
+ return defaultAnswer;
+ }
+ return answer;
+ }
+
+ /**
+ * This method allow you to ask a question to the user.
+ * The answer is controlled before being return so the question will be ask until the user enter one the authorized answer
+ *
+ * @param session CommandSession
+ * @param msg String message to ask
+ * @param authorizedAnswer Array of possible answer, all answer must be in lower case
+ * @return the user answer
+ * @throws IOException
+ */
+ public static String askUserWithAuthorizedAnswer(CommandSession session, String msg, List<String> authorizedAnswer) throws IOException {
+ String answer;
+ do {
+ answer = promptMessageToUser(session,msg);
+ } while (!authorizedAnswer.contains(answer.toLowerCase()));
+ return answer;
+ }
+
+ /**
+ * This method allow you to prompt a message to the user.
+ * No control is done on the answer provided by the user.
+ *
+ * @param session CommandSession
+ * @param msg String message to prompt
+ * @return the user answer
+ * @throws IOException
+ */
+ public static String promptMessageToUser(CommandSession session, String msg) throws IOException {
+ ConsoleReader reader = (ConsoleReader) session.get(".jline.reader");
+ return reader.readLine(msg, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/HttpUtils.java
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/HttpUtils.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/HttpUtils.java
new file mode 100644
index 0000000..6fd1e58
--- /dev/null
+++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/HttpUtils.java
@@ -0,0 +1,155 @@
+/*
+ * 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.shell.utils;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+
+/**
+ * @author dgaillard
+ */
+public class HttpUtils {
+ private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
+
+ public static CloseableHttpClient initHttpClient(boolean trustAllCertificates) {
+ long requestStartTime = System.currentTimeMillis();
+
+ HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties();
+
+ if (trustAllCertificates) {
+ try {
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, new TrustManager[]{new X509TrustManager() {
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ public void checkClientTrusted(X509Certificate[] certs,
+ String authType) {
+ }
+
+ public void checkServerTrusted(X509Certificate[] certs,
+ String authType) {
+ }
+ }}, new SecureRandom());
+
+ Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
+ .register("https", new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER))
+ .build();
+
+ httpClientBuilder.setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
+ .setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryRegistry));
+
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ logger.error("Error creating SSL Context", e);
+ }
+ } else {
+ httpClientBuilder.setConnectionManager(new PoolingHttpClientConnectionManager());
+ }
+
+ RequestConfig requestConfig = RequestConfig.custom().build();
+ httpClientBuilder.setDefaultRequestConfig(requestConfig);
+
+ if (logger.isDebugEnabled()) {
+ long totalRequestTime = System.currentTimeMillis() - requestStartTime;
+ logger.debug("Init HttpClient executed in " + totalRequestTime + "ms");
+ }
+
+ return httpClientBuilder.build();
+ }
+
+ public static HttpEntity executeGetRequest(CloseableHttpClient httpClient, String url, Map<String, String> headers) throws IOException {
+ HttpGet httpGet = new HttpGet(url);
+ httpGet.addHeader("accept", "application/json");
+
+ return getHttpEntity(httpClient, url, headers, httpGet);
+ }
+
+ public static HttpEntity executeDeleteRequest(CloseableHttpClient httpClient, String url, Map<String, String> headers) throws IOException {
+ HttpDelete httpDelete = new HttpDelete(url);
+ httpDelete.addHeader("accept", "application/json");
+
+ return getHttpEntity(httpClient, url, headers, httpDelete);
+ }
+
+ public static HttpEntity executePostRequest(CloseableHttpClient httpClient, String url, String jsonData, Map<String, String> headers) throws IOException {
+ HttpPost httpPost = new HttpPost(url);
+ httpPost.addHeader("accept", "application/json");
+
+ if (jsonData != null) {
+ StringEntity input = new StringEntity(jsonData);
+ input.setContentType("application/json");
+ httpPost.setEntity(input);
+ }
+
+ return getHttpEntity(httpClient, url, headers, httpPost);
+ }
+
+ private static HttpEntity getHttpEntity(CloseableHttpClient httpClient, String url, Map<String, String> headers, HttpRequestBase httpRequestBase) throws IOException {
+ long requestStartTime = System.currentTimeMillis();
+ if (headers != null) {
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ httpRequestBase.setHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ CloseableHttpResponse response = httpClient.execute(httpRequestBase);
+ final int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode >= 400) {
+ throw new IOException("Couldn't execute " + httpRequestBase + " response: " + EntityUtils.toString(response.getEntity()));
+ }
+
+ HttpEntity entity = response.getEntity();
+ if (logger.isDebugEnabled()) {
+ if (entity !=null) {
+ entity = new BufferedHttpEntity(response.getEntity());
+ }
+ logger.debug("POST request " + httpRequestBase + " executed with code: " + statusCode + " and message: " + (entity!=null?EntityUtils.toString(entity):null));
+
+ long totalRequestTime = System.currentTimeMillis() - requestStartTime;
+ logger.debug("Request to Apache Unomi url: " + url + " executed in " + totalRequestTime + "ms");
+ }
+
+ return entity;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/f0100317/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..8f1080b
--- /dev/null
+++ b/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<blueprint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/shell/v1.1.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.apache.unomi.shell.actions.Migrate"/>
+ </command>
+ <command>
+ <action class="org.apache.unomi.shell.actions.Version"/>
+ </command>
+ </command-bundle>
+
+</blueprint>