UNOMI-117 improve shell commands, add a start and stop command, change behavior of Unomi by default it's not starting automatically on a fresh install unless you add the property unomi.autoStart=true to your setenv.sh
Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/eb8f07b8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/eb8f07b8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/eb8f07b8 Branch: refs/heads/feature-UNOMI-117 Commit: eb8f07b80fa861aba6bd0d862ee9db7bf17130dc Parents: f010031 Author: dgaillard <[email protected]> Authored: Fri Sep 15 17:55:46 2017 +0200 Committer: dgaillard <[email protected]> Committed: Thu Sep 28 10:49:15 2017 +0200 ---------------------------------------------------------------------- .../src/main/feature/feature.xml | 42 ++++ kar/src/main/feature/feature.xml | 33 ++-- .../org/apache/unomi/shell/actions/Migrate.java | 67 ------- .../org/apache/unomi/shell/actions/Start.java | 37 ++++ .../org/apache/unomi/shell/actions/Stop.java | 37 ++++ .../apache/unomi/shell/migration/Migration.java | 34 ++++ .../unomi/shell/migration/actions/Migrate.java | 81 ++++++++ .../shell/migration/impl/MigrationTo200.java | 194 +++++++++++++++++++ .../shell/migration/utils/ConsoleUtils.java | 82 ++++++++ .../unomi/shell/migration/utils/HttpUtils.java | 163 ++++++++++++++++ .../shell/migration/utils/MigrationUtils.java | 47 +++++ .../migrations/AbstractMigrationResource.java | 81 -------- .../unomi/shell/migrations/MigrationTo200.java | 130 ------------- .../shell/services/UnomiManagementService.java | 29 +++ .../internal/UnomiManagementServiceImpl.java | 88 +++++++++ .../apache/unomi/shell/utils/ConsoleUtils.java | 82 -------- .../org/apache/unomi/shell/utils/HttpUtils.java | 155 --------------- .../resources/OSGI-INF/blueprint/blueprint.xml | 69 ++++++- 18 files changed, 915 insertions(+), 536 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/extensions/router/router-karaf-feature/src/main/feature/feature.xml ---------------------------------------------------------------------- diff --git a/extensions/router/router-karaf-feature/src/main/feature/feature.xml b/extensions/router/router-karaf-feature/src/main/feature/feature.xml new file mode 100644 index 0000000..0d9e122 --- /dev/null +++ b/extensions/router/router-karaf-feature/src/main/feature/feature.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + ~ 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. + --> +<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.1" name="unomi-router-karaf-feature"> + <feature name="unomi-router-karaf-feature" version="${project.version}" description="Apache Unomi :: Extensions :: Router :: Apache Karaf Feature"> + <details>Apache Karaf feature for the Apache Unomi Context Server extension</details> + <feature>unomi-kar</feature> + <bundle start-level="90">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jsch/0.1.54_1</bundle> + <bundle start-level="90">mvn:commons-net/commons-net/3.5</bundle> + <bundle start-level="90">wrap:mvn:org.apache.kafka/kafka-clients/0.10.1.0</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-core/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-core-osgi/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-blueprint/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-jackson/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-http-common/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-servlet/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-ftp/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-stream/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.camel/camel-kafka/2.19.1</bundle> + <bundle start-level="90">mvn:org.apache.cxf/cxf-rt-rs-security-cors/3.0.2</bundle> + <bundle start-level="90" start="false">mvn:org.apache.unomi/unomi-router-api/${project.version}</bundle> + <bundle start-level="90" start="false">mvn:org.apache.unomi/unomi-router-core/${project.version}</bundle> + <bundle start-level="90" start="false">mvn:org.apache.unomi/unomi-router-service/${project.version}</bundle> + <bundle start-level="90" start="false">mvn:org.apache.unomi/unomi-router-rest/${project.version}</bundle> + <bundle start-level="90">mvn:org.apache.httpcomponents/httpclient-osgi/4.3.6</bundle> + <bundle start-level="90">mvn:org.apache.httpcomponents/httpcore-osgi/4.3.3</bundle> + </feature> +</features> http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/kar/src/main/feature/feature.xml ---------------------------------------------------------------------- diff --git a/kar/src/main/feature/feature.xml b/kar/src/main/feature/feature.xml index e541135..bb672b4 100644 --- a/kar/src/main/feature/feature.xml +++ b/kar/src/main/feature/feature.xml @@ -32,7 +32,6 @@ <configfile finalname="/etc/hazelcast.xml">mvn:org.apache.unomi/unomi-services/${project.version}/xml/hazelcastconfig</configfile> <configfile finalname="/etc/org.apache.unomi.privacy.cfg">mvn:org.apache.unomi/cxs-privacy-extension-services/${project.version}/cfg/privacycfg</configfile> <configfile finalname="/etc/org.apache.unomi.geonames.cfg">mvn:org.apache.unomi/cxs-geonames-services/${project.version}/cfg/geonamescfg</configfile> - <bundle start-level="70">mvn:org.apache.unomi/unomi-lifecycle-watcher/${project.version}</bundle> <bundle start-level="75">mvn:commons-io/commons-io/2.4</bundle> <bundle start-level="75">mvn:com.fasterxml.jackson.core/jackson-core/${version.jackson.core}</bundle> <bundle start-level="75">mvn:com.fasterxml.jackson.core/jackson-databind/${version.jackson.core}</bundle> @@ -42,16 +41,26 @@ <bundle start-level="75">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${version.jackson.core}</bundle> <bundle start-level="75">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jakarta-regexp/1.4_1</bundle> <bundle start-level="75">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.joda-time/2.3_1</bundle> - <bundle start-level="75">mvn:org.apache.unomi/unomi-api/${project.version}</bundle> - <bundle start-level="75">mvn:org.apache.unomi/unomi-persistence-spi/${project.version}</bundle> - <bundle start-level="76">mvn:org.apache.unomi/unomi-persistence-elasticsearch-core/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/unomi-services/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-lists-extension-services/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-lists-extension-rest/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-geonames-services/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-geonames-rest/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-privacy-extension-services/${project.version}</bundle> - <bundle start-level="77">mvn:org.apache.unomi/cxs-privacy-extension-rest/${project.version}</bundle> - <bundle start-level="78">mvn:org.apache.unomi/unomi-rest/${project.version}</bundle> + + <bundle start-level="70" start="false">mvn:org.apache.unomi/unomi-lifecycle-watcher/${project.version}</bundle> + <bundle start-level="75" start="false">mvn:org.apache.unomi/unomi-api/${project.version}</bundle> + <bundle start-level="75" start="false">mvn:org.apache.unomi/unomi-persistence-spi/${project.version}</bundle> + <bundle start-level="76" start="false">mvn:org.apache.unomi/unomi-persistence-elasticsearch-core/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/unomi-services/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-lists-extension-services/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-lists-extension-rest/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-geonames-services/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-geonames-rest/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-privacy-extension-services/${project.version}</bundle> + <bundle start-level="77" start="false">mvn:org.apache.unomi/cxs-privacy-extension-rest/${project.version}</bundle> + <bundle start-level="78" start="false">mvn:org.apache.unomi/unomi-rest/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/unomi-wab/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/unomi-plugins-base/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/unomi-plugins-request/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/unomi-plugins-mail/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/unomi-plugins-optimization-test/${project.version}</bundle> + <bundle start-level="85" start="false">mvn:org.apache.unomi/cxs-lists-extension-actions/${project.version}</bundle> + + <bundle start-level="99">mvn:org.apache.unomi/shell-commands/${project.version}</bundle> </feature> </features> http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/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 deleted file mode 100644 index f24a884..0000000 --- a/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Migrate.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Start.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Start.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Start.java new file mode 100644 index 0000000..8f7530e --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Start.java @@ -0,0 +1,37 @@ +/* + * 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; +import org.apache.unomi.shell.services.UnomiManagementService; + +@Command(scope = "unomi", name = "start", description = "This will start Apache Unomi") +public class Start extends OsgiCommandSupport { + + private UnomiManagementService unomiManagementService; + + protected Object doExecute() throws Exception { + unomiManagementService.startUnomi(); + + return null; + } + + public void setUnomiManagementService(UnomiManagementService unomiManagementService) { + this.unomiManagementService = unomiManagementService; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Stop.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Stop.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Stop.java new file mode 100644 index 0000000..d612cdc --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/actions/Stop.java @@ -0,0 +1,37 @@ +/* + * 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; +import org.apache.unomi.shell.services.UnomiManagementService; + +@Command(scope = "unomi", name = "stop", description = "This will stop Apache Unomi") +public class Stop extends OsgiCommandSupport { + + private UnomiManagementService unomiManagementService; + + protected Object doExecute() throws Exception { + unomiManagementService.stopUnomi(); + + return null; + } + + public void setUnomiManagementService(UnomiManagementService unomiManagementService) { + this.unomiManagementService = unomiManagementService; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/Migration.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/Migration.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/Migration.java new file mode 100644 index 0000000..08fb797 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/Migration.java @@ -0,0 +1,34 @@ +/* + * 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.migration; + +import org.apache.felix.service.command.CommandSession; +import org.apache.http.impl.client.CloseableHttpClient; +import org.osgi.framework.Version; + +import java.io.IOException; + +/** + * @author dgaillard + */ +public interface Migration { + Version getFromVersion(); + + Version getToVersion(); + + void execute(CommandSession session, CloseableHttpClient httpClient) throws IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/actions/Migrate.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/actions/Migrate.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/actions/Migrate.java new file mode 100644 index 0000000..45d6471 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/actions/Migrate.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.migration.actions; + +import org.apache.http.impl.client.CloseableHttpClient; +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.migration.Migration; +import org.apache.unomi.shell.migration.utils.ConsoleUtils; +import org.apache.unomi.shell.migration.utils.HttpUtils; +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 { + + private List<Migration> migrations; + + @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; + } + + CloseableHttpClient httpClient = HttpUtils.initHttpClient(session); + + for (Migration migration : migrations) { + if (fromVersion.compareTo(migration.getToVersion()) < 0) { + System.out.println("Starting migration to version " + migration.getToVersion()); + migration.execute(session, httpClient); + + System.out.println("Migration to version 2.0.0 done successfully"); + } + } + + if (httpClient != null) { + httpClient.close(); + } + + return null; + } + + private Version getCurrentVersionWithoutQualifier() { + Version currentVersion = bundleContext.getBundle().getVersion(); + return new Version(currentVersion.getMajor() + "." + currentVersion.getMinor() + "." + currentVersion.getMicro()); + } + + public void setMigrations(List<Migration> migrations) { + this.migrations = migrations; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/impl/MigrationTo200.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/impl/MigrationTo200.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/impl/MigrationTo200.java new file mode 100644 index 0000000..99e2fb2 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/impl/MigrationTo200.java @@ -0,0 +1,194 @@ +/* + * 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.migration.impl; + +import org.apache.commons.lang3.StringUtils; +import org.apache.felix.service.command.CommandSession; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.unomi.shell.migration.Migration; +import org.apache.unomi.shell.migration.utils.ConsoleUtils; +import org.apache.unomi.shell.migration.utils.MigrationUtils; +import org.json.JSONArray; +import org.json.JSONObject; +import org.osgi.framework.Version; + +import java.io.IOException; +import java.util.*; + +/** + * @author dgaillard + */ +public class MigrationTo200 implements Migration { + + private CloseableHttpClient httpClient; + private CommandSession session; + private LinkedHashMap<String, List<String>> tagsStructurePriorTo200; + + @Override + public Version getFromVersion() { + return null; + } + + @Override + public Version getToVersion() { + return new Version("2.0.0"); + } + + @Override + public void execute(CommandSession session, CloseableHttpClient httpClient) throws IOException { + try { + this.httpClient = httpClient; + this.session = session; + migrateTags(); + } catch (IOException e) { + if (httpClient != null) { + httpClient.close(); + } + throw e; + } + } + + private void migrateTags() throws IOException { + initTagsStructurePriorTo200(); + String hostAddress = ConsoleUtils.askUserWithDefaultAnswer(session, "Host address (default = http://localhost:9200): ", "http://localhost:9200"); + + List<String> typeToMigrate = Arrays.asList("actionType", "conditionType", "campaign", "goal", "rule", "scoring", "segment", "userList"); + for (String type : typeToMigrate) { + migrateTypeTags(hostAddress, type); + } + + migratePropertyTypesTags(hostAddress); + } + + private void migrateTypeTags(String hostAddress, String type) throws IOException { + JSONObject responseJSON = MigrationUtils.queryWithScroll(httpClient, hostAddress + "/context/" + type + "/_search"); + + migrateTagsInResult(responseJSON, hostAddress, type,10, true); + } + + private void migratePropertyTypesTags(String hostAddress) throws IOException { + JSONObject responseJSON = MigrationUtils.queryWithScroll(httpClient,hostAddress + "/context/propertyType/_search"); + + migrateTagsInResult(responseJSON, hostAddress, "propertyType", 10, false); + } + + private void migrateTagsInResult(JSONObject responseJSON, String hostAddress, String type, int currentOffset, boolean tagsInMetadata) throws IOException { + if (responseJSON.has("hits")) { + JSONObject hitsObject = responseJSON.getJSONObject("hits"); + if (hitsObject.has("hits")) { + JSONArray hits = hitsObject.getJSONArray("hits"); + + StringBuilder updatedHits = new StringBuilder(); + Iterator<Object> hitsIterator = hits.iterator(); + while (hitsIterator.hasNext()) { + JSONObject hit = (JSONObject) hitsIterator.next(); + if (hit.has("_source")) { + JSONObject hitSource = hit.getJSONObject("_source"); + if (tagsInMetadata && hitSource.has("metadata")) { + JSONObject hitMetadata = hitSource.getJSONObject("metadata"); + updateTagsForHit(updatedHits, hit.getString("_id"), hitMetadata, tagsInMetadata); + } else if (!tagsInMetadata) { + updateTagsForHit(updatedHits, hit.getString("_id"), hitSource, tagsInMetadata); + } + } + } + String jsonData = updatedHits.toString(); + if (StringUtils.isNotBlank(jsonData)) { + MigrationUtils.bulkUpdate(httpClient, hostAddress + "/context/" + type + "/_bulk", jsonData); + } + + if (hitsObject.getInt("total") > currentOffset) { + migrateTagsInResult(MigrationUtils.continueQueryWithScroll(httpClient, hostAddress, responseJSON.getString("_scroll_id")), hostAddress, type,currentOffset + 10, tagsInMetadata); + } + } + } + } + + private void updateTagsForHit(StringBuilder updatedHits, String hitId, JSONObject jsonObject, boolean tagsInMetadata) { + if (jsonObject.has("tags")) { + JSONArray hitTags = jsonObject.getJSONArray("tags"); + Iterator<Object> tagsIterator = hitTags.iterator(); + List<String> tagsBeforeMigration = new ArrayList<>(); + List<String> tagsAfterMigration = new ArrayList<>(); + if (tagsIterator.hasNext()) { + while (tagsIterator.hasNext()) { + tagsBeforeMigration.add((String) tagsIterator.next()); + } + + for (String tag : tagsBeforeMigration) { + if (tagsStructurePriorTo200.containsKey(tag) && !tagsAfterMigration.containsAll(tagsStructurePriorTo200.get(tag))) { + tagsAfterMigration.addAll(tagsStructurePriorTo200.get(tag)); + } + + if (!tagsAfterMigration.contains(tag)) { + tagsAfterMigration.add(tag); + } + } + + updatedHits.append("{\"update\":{\"_id\":\"").append(hitId).append("\"}}\n"); + updatedHits.append("{\"doc\":{\"metadata\":{\"tags\":").append(new JSONArray(tagsAfterMigration)).append("}}}\n"); + if (!tagsInMetadata) { + updatedHits.append("{\"update\":{\"_id\":\"").append(hitId).append("\"}}\n"); + updatedHits.append("{\"script\":\"ctx._source.remove(\\\"tags\\\")\"}\n"); + } + } + } + } + + private void initTagsStructurePriorTo200() { + tagsStructurePriorTo200 = new LinkedHashMap<>(); + tagsStructurePriorTo200.put("landing", Collections.singletonList("campaign")); + tagsStructurePriorTo200.put("parameter", Collections.singletonList("campaign")); + tagsStructurePriorTo200.put("referrer", Collections.singletonList("campaign")); + + tagsStructurePriorTo200.put("eventCondition", Collections.singletonList("condition")); + tagsStructurePriorTo200.put("profileCondition", Collections.singletonList("condition")); + tagsStructurePriorTo200.put("sessionCondition", Collections.singletonList("condition")); + tagsStructurePriorTo200.put("sourceEventCondition", Collections.singletonList("condition")); + tagsStructurePriorTo200.put("trackedCondition", Collections.singletonList("condition")); + tagsStructurePriorTo200.put("usableInPastEventCondition", Collections.singletonList("condition")); + + tagsStructurePriorTo200.put("formMappingRule", Collections.<String>emptyList()); + + tagsStructurePriorTo200.put("downloadGoal", Collections.singletonList("goal")); + tagsStructurePriorTo200.put("formGoal", Collections.singletonList("goal")); + tagsStructurePriorTo200.put("funnelGoal", Collections.singletonList("goal")); + tagsStructurePriorTo200.put("landingPageGoal", Collections.singletonList("goal")); + tagsStructurePriorTo200.put("pageVisitGoal", Collections.singletonList("goal")); + tagsStructurePriorTo200.put("videoGoal", Collections.singletonList("goal")); + + tagsStructurePriorTo200.put("aggregated", Collections.singletonList("profileTags")); + tagsStructurePriorTo200.put("autocompleted", Collections.singletonList("profileTags")); + tagsStructurePriorTo200.put("demographic", Collections.singletonList("profileTags")); + tagsStructurePriorTo200.put("event", Collections.singletonList("profileTags")); + tagsStructurePriorTo200.put("geographic", Collections.singletonList("profileTags")); + tagsStructurePriorTo200.put("logical", Collections.singletonList("profileTags")); + + tagsStructurePriorTo200.put("profileProperties", Collections.singletonList("properties")); + tagsStructurePriorTo200.put("systemProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("basicProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("leadProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("contactProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("socialProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("personalProfileProperties", Arrays.asList("properties", "profileProperties")); + tagsStructurePriorTo200.put("workProfileProperties", Arrays.asList("properties", "profileProperties")); + + tagsStructurePriorTo200.put("sessionProperties", Collections.singletonList("properties")); + tagsStructurePriorTo200.put("geographicSessionProperties", Arrays.asList("properties", "sessionProperties")); + tagsStructurePriorTo200.put("technicalSessionProperties", Arrays.asList("properties", "sessionProperties")); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/ConsoleUtils.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/ConsoleUtils.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/ConsoleUtils.java new file mode 100644 index 0000000..e8fdc83 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/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.migration.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/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/HttpUtils.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/HttpUtils.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/HttpUtils.java new file mode 100644 index 0000000..2f16c83 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/HttpUtils.java @@ -0,0 +1,163 @@ +/* + * 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.migration.utils; + +import org.apache.felix.service.command.CommandSession; +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.Arrays; +import java.util.Map; + +/** + * @author dgaillard + */ +public class HttpUtils { + private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class); + + public static CloseableHttpClient initHttpClient(CommandSession session) throws IOException { + String confirmation = ConsoleUtils.askUserWithAuthorizedAnswer(session,"We need to initialize a HttpClient, do we need to trust all certificates? (yes/no): ", Arrays.asList("yes", "no")); + boolean trustAllCertificates = confirmation.equalsIgnoreCase("yes"); + + 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 String executeGetRequest(CloseableHttpClient httpClient, String url, Map<String, String> headers) throws IOException { + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader("accept", "application/json"); + + return getResponse(httpClient, url, headers, httpGet); + } + + public static String executeDeleteRequest(CloseableHttpClient httpClient, String url, Map<String, String> headers) throws IOException { + HttpDelete httpDelete = new HttpDelete(url); + httpDelete.addHeader("accept", "application/json"); + + return getResponse(httpClient, url, headers, httpDelete); + } + + public static String 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 getResponse(httpClient, url, headers, httpPost); + } + + private static String getResponse(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"); + } + + String stringResponse = EntityUtils.toString(entity); + EntityUtils.consumeQuietly(entity); + + return stringResponse; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java new file mode 100644 index 0000000..ccc67f2 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java @@ -0,0 +1,47 @@ +/* + * 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.migration.utils; + +import org.apache.http.impl.client.CloseableHttpClient; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * @author dgaillard + */ +public class MigrationUtils { + private static final Logger logger = LoggerFactory.getLogger(MigrationUtils.class); + + public static JSONObject queryWithScroll(CloseableHttpClient httpClient, String url) throws IOException { + url += "?scroll=1m"; + + return new JSONObject(HttpUtils.executeGetRequest(httpClient, url, null)); + } + + public static JSONObject continueQueryWithScroll(CloseableHttpClient httpClient, String url, String scrollId) throws IOException { + url += "/_search/scroll?scroll=1m&scroll_id=" + scrollId; + + return new JSONObject(HttpUtils.executeGetRequest(httpClient, url, null)); + } + + public static void bulkUpdate(CloseableHttpClient httpClient, String url, String jsonData) throws IOException { + HttpUtils.executePostRequest(httpClient, url, jsonData, null); + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/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 deleted file mode 100644 index 37171a0..0000000 --- a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/AbstractMigrationResource.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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/eb8f07b8/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 deleted file mode 100644 index 134db02..0000000 --- a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migrations/MigrationTo200.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/UnomiManagementService.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/UnomiManagementService.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/UnomiManagementService.java new file mode 100644 index 0000000..e77f4b9 --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/UnomiManagementService.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.services; + +import org.osgi.framework.BundleException; + +/** + * @author dgaillard + */ +public interface UnomiManagementService { + + void startUnomi() throws BundleException; + + void stopUnomi() throws BundleException; +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/internal/UnomiManagementServiceImpl.java ---------------------------------------------------------------------- diff --git a/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/internal/UnomiManagementServiceImpl.java b/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/internal/UnomiManagementServiceImpl.java new file mode 100644 index 0000000..fedb8bb --- /dev/null +++ b/tools/shell-commands/src/main/java/org/apache/unomi/shell/services/internal/UnomiManagementServiceImpl.java @@ -0,0 +1,88 @@ +/* + * 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.services.internal; + +import org.apache.commons.lang3.StringUtils; +import org.apache.unomi.shell.services.UnomiManagementService; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author dgaillard + */ +public class UnomiManagementServiceImpl implements UnomiManagementService { + + private BundleContext bundleContext; + private List<String> bundleSymbolicNames; + private List<String> reversedBundleSymbolicNames; + + public void init() throws BundleException { + initReversedBundleSymbolicNames(); + if (StringUtils.isNotBlank(bundleContext.getProperty("unomi.autoStart")) && bundleContext.getProperty("unomi.autoStart").equals("true")) { + startUnomi(); + } + } + + @Override + public void startUnomi() throws BundleException { + for (String bundleSymbolicName : bundleSymbolicNames) { + for (Bundle bundle : bundleContext.getBundles()) { + if (bundle.getSymbolicName().equals(bundleSymbolicName)) { + if (bundle.getState() == Bundle.RESOLVED) { + bundle.start(); + } + break; + } + } + } + } + + @Override + public void stopUnomi() throws BundleException { + for (String bundleSymbolicName : reversedBundleSymbolicNames) { + for (Bundle bundle : bundleContext.getBundles()) { + if (bundle.getSymbolicName().equals(bundleSymbolicName)) { + if (bundle.getState() == Bundle.ACTIVE) { + bundle.stop(); + } + break; + } + } + } + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void setBundleSymbolicNames(List<String> bundleSymbolicNames) { + this.bundleSymbolicNames = bundleSymbolicNames; + } + + public void initReversedBundleSymbolicNames() { + if (reversedBundleSymbolicNames == null || reversedBundleSymbolicNames.isEmpty()) { + this.reversedBundleSymbolicNames = new ArrayList<>(); + reversedBundleSymbolicNames.addAll(bundleSymbolicNames); + Collections.reverse(reversedBundleSymbolicNames); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/eb8f07b8/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 deleted file mode 100644 index b2c6323..0000000 --- a/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/ConsoleUtils.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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/eb8f07b8/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 deleted file mode 100644 index 6fd1e58..0000000 --- a/tools/shell-commands/src/main/java/org/apache/unomi/shell/utils/HttpUtils.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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/eb8f07b8/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 index 8f1080b..562159f 100644 --- a/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/tools/shell-commands/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -18,15 +18,66 @@ <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"> + xmlns:shell="http://karaf.apache.org/xmlns/shell/v1.1.0" + xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> - <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> + <bean id="migrateTo200" class="org.apache.unomi.shell.migration.impl.MigrationTo200"/> + + <shell:command-bundle> + <shell:command> + <shell:action class="org.apache.unomi.shell.migration.actions.Migrate"> + <shell:property name="migrations"> + <list> + <!-- Migration beans must be executed in the right order so you must place new bean at the end of this list --> + <ref component-id="migrateTo200"/> + </list> + </shell:property> + </shell:action> + </shell:command> + <shell:command> + <shell:action class="org.apache.unomi.shell.actions.Version"/> + </shell:command> + <shell:command> + <shell:action class="org.apache.unomi.shell.actions.Start"> + <shell:property name="unomiManagementService" ref="unomiManagementServiceImpl"/> + </shell:action> + </shell:command> + <shell:command> + <shell:action class="org.apache.unomi.shell.actions.Stop"> + <shell:property name="unomiManagementService" ref="unomiManagementServiceImpl"/> + </shell:action> + </shell:command> + </shell:command-bundle> + + <bean id="unomiManagementServiceImpl" class="org.apache.unomi.shell.services.internal.UnomiManagementServiceImpl" init-method="init"> + <property name="bundleSymbolicNames"> + <list> + <value>org.apache.unomi.lifecycle-watcher</value> + <value>org.apache.unomi.api</value> + <value>org.apache.unomi.persistence-spi</value> + <value>org.apache.unomi.persistence-elasticsearch-core</value> + <value>org.apache.unomi.services</value> + <value>org.apache.unomi.cxs-lists-extension-services</value> + <value>org.apache.unomi.cxs-lists-extension-rest</value> + <value>org.apache.unomi.cxs-geonames-services</value> + <value>org.apache.unomi.cxs-geonames-rest</value> + <value>org.apache.unomi.cxs-privacy-extension-services</value> + <value>org.apache.unomi.cxs-privacy-extension-rest</value> + <value>org.apache.unomi.rest</value> + <value>org.apache.unomi.wab</value> + <value>org.apache.unomi.plugins-base</value> + <value>org.apache.unomi.plugins-request</value> + <value>org.apache.unomi.plugins-mail</value> + <value>org.apache.unomi.plugins-optimization-test</value> + <value>org.apache.unomi.cxs-lists-extension-actions</value> + <value>org.apache.unomi.router-api</value> + <value>org.apache.unomi.router-core</value> + <value>org.apache.unomi.router-service</value> + <value>org.apache.unomi.router-rest</value> + </list> + </property> + <property name="bundleContext" ref="blueprintBundleContext"/> + </bean> + <service id="unomiManagementService" ref="unomiManagementServiceImpl" auto-export="interfaces"/> </blueprint>
