You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2019/09/26 05:18:04 UTC

[unomi] branch UNOMI-249-new-shell-commands created (now 2f877b5)

This is an automated email from the ASF dual-hosted git repository.

shuber pushed a change to branch UNOMI-249-new-shell-commands
in repository https://gitbox.apache.org/repos/asf/unomi.git.


      at 2f877b5  UNOMI-249 New shell commands to make plugin development easier The following shell dev commands have been added: - List events - Search for events by profile Id and type - Remove a profile - Remove a rule - Remove a segment - View a segment - Undeploy definitions provided by a plugin - Added the possibility to deploy all the definitions contained in a plugin with the deploy-definition command.

This branch includes the following new commits:

     new 2f877b5  UNOMI-249 New shell commands to make plugin development easier The following shell dev commands have been added: - List events - Search for events by profile Id and type - Remove a profile - Remove a rule - Remove a segment - View a segment - Undeploy definitions provided by a plugin - Added the possibility to deploy all the definitions contained in a plugin with the deploy-definition command.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[unomi] 01/01: UNOMI-249 New shell commands to make plugin development easier The following shell dev commands have been added: - List events - Search for events by profile Id and type - Remove a profile - Remove a rule - Remove a segment - View a segment - Undeploy definitions provided by a plugin - Added the possibility to deploy all the definitions contained in a plugin with the deploy-definition command.

Posted by sh...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

shuber pushed a commit to branch UNOMI-249-new-shell-commands
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 2f877b51b5bd3398bbbbf473c2a698054de05f11
Author: Serge Huber <sh...@apache.org>
AuthorDate: Thu Sep 26 07:17:54 2019 +0200

    UNOMI-249 New shell commands to make plugin development easier
    The following shell dev commands have been added:
    - List events
    - Search for events by profile Id and type
    - Remove a profile
    - Remove a rule
    - Remove a segment
    - View a segment
    - Undeploy definitions provided by a plugin
    - Added the possibility to deploy all the definitions contained in a plugin with the deploy-definition command.
    
    Signed-off-by: Serge Huber <sh...@apache.org>
---
 .../unomi/shell/commands/DeployDefinition.java     | 245 +++------------------
 .../shell/commands/DeploymentCommandSupport.java   | 232 +++++++++++++++++++
 .../org/apache/unomi/shell/commands/EventList.java |  78 +++++++
 .../apache/unomi/shell/commands/EventSearch.java   |  99 +++++++++
 .../{SegmentView.java => ProfileRemove.java}       |  22 +-
 .../commands/{SegmentView.java => RuleRemove.java} |  22 +-
 .../{SegmentView.java => SegmentRemove.java}       |  28 ++-
 .../apache/unomi/shell/commands/SegmentView.java   |   2 +-
 .../unomi/shell/commands/UndeployDefinition.java   | 111 ++++++++++
 9 files changed, 586 insertions(+), 253 deletions(-)

diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinition.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinition.java
index d0baae9..9365de8 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinition.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeployDefinition.java
@@ -16,13 +16,8 @@
  */
 package org.apache.unomi.shell.commands;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.Session;
 import org.apache.unomi.api.Patch;
 import org.apache.unomi.api.PersonaWithSessions;
 import org.apache.unomi.api.PropertyType;
@@ -33,260 +28,86 @@ import org.apache.unomi.api.goals.Goal;
 import org.apache.unomi.api.rules.Rule;
 import org.apache.unomi.api.segments.Scoring;
 import org.apache.unomi.api.segments.Segment;
-import org.apache.unomi.api.services.*;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
-import org.jline.reader.LineReader;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 
 import java.io.IOException;
 import java.net.URL;
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
 
-@Command(scope = "unomi", name = "deploy-definition", description = "This will deploy a specific definition")
+@Command(scope = "unomi", name = "deploy-definition", description = "This will deploy Unomi definitions contained in bundles")
 @Service
-public class DeployDefinition implements Action {
+public class DeployDefinition extends DeploymentCommandSupport {
 
-    @Reference
-    DefinitionsService definitionsService;
-
-    @Reference
-    GoalsService goalsService;
-
-    @Reference
-    ProfileService profileService;
-
-    @Reference
-    RulesService rulesService;
-
-    @Reference
-    SegmentService segmentService;
-
-    @Reference
-    PatchService patchService;
-
-    @Reference
-    BundleContext bundleContext;
-
-    @Reference
-    Session session;
-
-    private final static List<String> definitionTypes = Arrays.asList("condition", "action", "goal", "campaign", "persona", "property", "rule", "segment", "scoring", "patch");
-
-    @Argument(index = 0, name = "bundleId", description = "The bundle identifier where to find the definition", multiValued = false)
-    Long bundleIdentifier;
-
-    @Argument(index = 1, name = "type", description = "The kind of definitions you want to load (e.g.: condition, action, ..)", required = false, multiValued = false)
-    String definitionType;
-
-    @Argument(index = 2, name = "fileName", description = "The name of the file which contains the definition, without its extension (e.g: firstName)", required = false, multiValued = false)
-    String fileName;
-
-    public Object execute() throws Exception {
-        List<Bundle> bundlesToUpdate;
-        if (bundleIdentifier == null) {
-            List<Bundle> bundles = new ArrayList<>();
-            for (Bundle bundle : bundleContext.getBundles()) {
-                if (bundle.findEntries("META-INF/cxs/", "*.json", true) != null) {
-                    bundles.add(bundle);
+    public void processDefinition(String definitionType, URL definitionURL) {
+        try {
+            if (ALL_OPTION_LABEL.equals(definitionType)) {
+                String definitionURLString = definitionURL.toString();
+                for (String possibleDefinitionType : definitionTypes) {
+                    if (definitionURLString.contains(getDefinitionTypePath(possibleDefinitionType))) {
+                        definitionType = possibleDefinitionType;
+                        break;
+                    }
+                }
+                if (ALL_OPTION_LABEL.equals(definitionType)) {
+                    System.out.println("Couldn't resolve definition type for definition URL " + definitionURL);
+                    return;
                 }
             }
-
-            bundles = bundles.stream()
-                    .filter(b -> definitionTypes.stream().anyMatch((t) -> b.findEntries(getDefinitionTypePath(t), "*.json", true) != null))
-                    .collect(Collectors.toList());
-
-            List<String> stringList = bundles.stream().map(Bundle::getSymbolicName).collect(Collectors.toList());
-            stringList.add(0, "* (All)");
-
-            String bundleAnswer = askUserWithAuthorizedAnswer(session, "Which bundle ?" + getValuesWithNumber(stringList) + "\n",
-                    IntStream.range(1,bundles.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
-            if (bundleAnswer.equals("1")) {
-                bundlesToUpdate = bundles;
-            } else {
-                bundlesToUpdate = Collections.singletonList(bundles.get(new Integer(bundleAnswer) - 2));
-            }
-        } else {
-            Bundle bundle = bundleContext.getBundle(bundleIdentifier);
-
-            if (bundle == null) {
-                System.out.println("Couldn't find a bundle with id: " + bundleIdentifier);
-                return null;
-            }
-
-            bundlesToUpdate = Collections.singletonList(bundle);
-        }
-
-        if (definitionType == null) {
-            List<String> values = definitionTypes.stream().filter((t) -> bundlesToUpdate.stream().anyMatch(b->b.findEntries(getDefinitionTypePath(t), "*.json", true) != null)).collect(Collectors.toList());
-
-            if (values.isEmpty()) {
-                System.out.println("Couldn't find definitions in bundle : " + bundlesToUpdate);
-                return null;
-            }
-
-            String definitionTypeAnswer = askUserWithAuthorizedAnswer(session, "Which kind of definition do you want to load?" + getValuesWithNumber(values) + "\n",
-                    IntStream.range(1,values.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
-            definitionType = values.get(new Integer(definitionTypeAnswer)-1);
-        }
-
-        if (!definitionTypes.contains(definitionType)) {
-            System.out.println("Invalid type '" + definitionType + "' , allowed values : " +definitionTypes);
-            return null;
-        }
-
-        String path = getDefinitionTypePath(definitionType);
-        List<URL> values = bundlesToUpdate.stream().flatMap(b->b.findEntries(path, "*.json", true) != null ? Collections.list(b.findEntries(path, "*.json", true)).stream() : Stream.empty()).collect(Collectors.toList());
-        if (values.isEmpty()) {
-            System.out.println("Couldn't find definitions in bundle with id: " + bundleIdentifier + " and definition path: " + path);
-            return null;
-        }
-
-        if (fileName == null) {
-            List<String> stringList = values.stream().map(u -> StringUtils.substringAfterLast(u.getFile(), "/")).sorted().collect(Collectors.toList());
-            stringList.add(0, "* (All)");
-            String fileNameAnswer = askUserWithAuthorizedAnswer(session, "Which file do you want to load ?" + getValuesWithNumber(stringList) + "\n",
-                    IntStream.range(1,stringList.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
-            fileName = stringList.get(new Integer(fileNameAnswer)-1);
-        }
-        if (fileName.startsWith("*")) {
-            for (URL url : values) {
-                updateDefinition(definitionType, url);
-            }
-        } else {
-            if (!fileName.contains("/")) {
-                fileName = "/" + fileName;
-            }
-            if (!fileName.endsWith(".json")) {
-                fileName += ".json";
-            }
-
-            Optional<URL> optionalURL = values.stream().filter(u -> u.getFile().endsWith(fileName)).findFirst();
-            if (optionalURL.isPresent()) {
-                URL url = optionalURL.get();
-                updateDefinition(definitionType, url);
-            } else {
-                System.out.println("Couldn't find file " + fileName);
-                return null;
-            }
-        }
-
-        return null;
-    }
-
-    private String askUserWithAuthorizedAnswer(Session session, String msg, List<String> authorizedAnswer) throws IOException {
-        String answer;
-        do {
-            answer = promptMessageToUser(session,msg);
-        } while (!authorizedAnswer.contains(answer.toLowerCase()));
-        return answer;
-    }
-
-    private String promptMessageToUser(Session session, String msg) throws IOException {
-        LineReader reader = (LineReader) session.get(".jline.reader");
-        return reader.readLine(msg, null);
-    }
-
-    private String getValuesWithNumber(List<String> values) {
-        StringBuilder definitionTypesWithNumber = new StringBuilder();
-        for (int i = 0; i < values.size(); i++) {
-            definitionTypesWithNumber.append("\n").append(i+1).append(". ").append(values.get(i));
-        }
-        return definitionTypesWithNumber.toString();
-    }
-
-    private void updateDefinition(String definitionType, URL definitionURL) {
-        try {
-                    
+            boolean successful = true;
             switch (definitionType) {
-                case "condition":
+                case CONDITION_DEFINITION_TYPE:
                     ConditionType conditionType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, ConditionType.class);
                     definitionsService.setConditionType(conditionType);
                     break;
-                case "action":
+                case ACTION_DEFINITION_TYPE:
                     ActionType actionType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, ActionType.class);
                     definitionsService.setActionType(actionType);
                     break;
-                case "goal":
+                case GOAL_DEFINITION_TYPE:
                     Goal goal = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Goal.class);
                     goalsService.setGoal(goal);
                     break;
-                case "campaign":
+                case CAMPAIGN_DEFINITION_TYPE:
                     Campaign campaign = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Campaign.class);
                     goalsService.setCampaign(campaign);
                     break;
-                case "persona":
+                case PERSONA_DEFINITION_TYPE:
                     PersonaWithSessions persona = CustomObjectMapper.getObjectMapper().readValue(definitionURL, PersonaWithSessions.class);
                     profileService.savePersonaWithSessions(persona);
                     break;
-                case "property":
+                case PROPERTY_DEFINITION_TYPE:
                     PropertyType propertyType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, PropertyType.class);
                     profileService.setPropertyTypeTarget(definitionURL, propertyType);
                     profileService.setPropertyType(propertyType);
                     break;
-                case "rule":
+                case RULE_DEFINITION_TYPE:
                     Rule rule = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Rule.class);
                     rulesService.setRule(rule);
                     break;
-                case "segment":
+                case SEGMENT_DEFINITION_TYPE:
                     Segment segment = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Segment.class);
                     segmentService.setSegmentDefinition(segment);
                     break;
-                case "scoring":
+                case SCORING_DEFINITION_TYPE:
                     Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Scoring.class);
                     segmentService.setScoringDefinition(scoring);
                     break;
-                case "patch":
+                case PATCH_DEFINITION_TYPE:
                     Patch patch = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Patch.class);
                     patchService.patch(patch);
                     break;
+                default:
+                    System.out.println("Unrecognized definition type:" + definitionType);
+                    successful = false;
+                    break;
+            }
+            if (successful) {
+                System.out.println("Predefined definition registered : " + definitionURL.getFile());
             }
-            System.out.println("Predefined definition registered : "+definitionURL.getFile());
         } catch (IOException e) {
             System.out.println("Error while saving definition " + definitionURL);
             System.out.println(e.getMessage());
         }
     }
 
-    private String getDefinitionTypePath(String definitionType) {
-        StringBuilder path = new StringBuilder("META-INF/cxs/");
-        switch (definitionType) {
-            case "condition":
-                path.append("conditions");
-                break;
-            case "action":
-                path.append("actions");
-                break;
-            case "goal":
-                path.append("goals");
-                break;
-            case "campaign":
-                path.append("campaigns");
-                break;
-            case "persona":
-                path.append("personas");
-                break;
-            case "property":
-                path.append("properties");
-                break;
-            case "rule":
-                path.append("rules");
-                break;
-            case "segment":
-                path.append("segments");
-                break;
-            case "scoring":
-                path.append("scoring");
-                break;
-            case "patch":
-                path.append("patches");
-                break;
-        }
-
-        return path.toString();
-    }
 
 }
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeploymentCommandSupport.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeploymentCommandSupport.java
new file mode 100644
index 0000000..e417d0d
--- /dev/null
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/DeploymentCommandSupport.java
@@ -0,0 +1,232 @@
+/*
+ * 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.commands;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.unomi.api.services.*;
+import org.jline.reader.LineReader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public abstract class DeploymentCommandSupport implements Action {
+
+    public static final String ALL_OPTION_LABEL = "* (All)";
+    @Reference
+    DefinitionsService definitionsService;
+
+    @Reference
+    GoalsService goalsService;
+
+    @Reference
+    ProfileService profileService;
+
+    @Reference
+    RulesService rulesService;
+
+    @Reference
+    SegmentService segmentService;
+
+    @Reference
+    PatchService patchService;
+
+    @Reference
+    BundleContext bundleContext;
+
+    @Reference
+    Session session;
+
+    public static final String CONDITION_DEFINITION_TYPE = "conditions";
+    public static final String ACTION_DEFINITION_TYPE = "actions";
+    public static final String GOAL_DEFINITION_TYPE = "goals";
+    public static final String CAMPAIGN_DEFINITION_TYPE = "campaigns";
+    public static final String PERSONA_DEFINITION_TYPE = "personas";
+    public static final String PROPERTY_DEFINITION_TYPE = "properties";
+    public static final String RULE_DEFINITION_TYPE = "rules";
+    public static final String SEGMENT_DEFINITION_TYPE = "segments";
+    public static final String SCORING_DEFINITION_TYPE = "scoring";
+    public static final String PATCH_DEFINITION_TYPE = "patches";
+    public static final String VALUE_DEFINITION_TYPE = "values";
+    public static final String MERGER_DEFINITION_TYPE = "mergers";
+    public static final String MAPPING_DEFINITION_TYPE = "mappings";
+
+    protected final static List<String> definitionTypes = Arrays.asList(
+            CONDITION_DEFINITION_TYPE,
+            ACTION_DEFINITION_TYPE,
+            GOAL_DEFINITION_TYPE,
+            CAMPAIGN_DEFINITION_TYPE,
+            PERSONA_DEFINITION_TYPE,
+            PROPERTY_DEFINITION_TYPE,
+            RULE_DEFINITION_TYPE,
+            SEGMENT_DEFINITION_TYPE,
+            SCORING_DEFINITION_TYPE,
+            PATCH_DEFINITION_TYPE,
+            VALUE_DEFINITION_TYPE,
+            MERGER_DEFINITION_TYPE,
+            MAPPING_DEFINITION_TYPE);
+
+    @Argument(index = 0, name = "bundleId", description = "The bundle identifier where to find the definition", multiValued = false)
+    Long bundleIdentifier;
+
+    @Argument(index = 1, name = "type", description = "The kind of definitions you want to load (e.g.: *, conditions, actions, ..)", required = false, multiValued = false)
+    String definitionType;
+
+    @Argument(index = 2, name = "fileName", description = "The name of the file which contains the definition, without its extension (e.g: firstName)", required = false, multiValued = false)
+    String fileName;
+
+    public abstract void processDefinition(String definitionType, URL definitionURL);
+
+    public Object execute() throws Exception {
+        List<Bundle> bundlesToUpdate;
+        if ("*".equals(definitionType)) {
+            definitionType = ALL_OPTION_LABEL;
+        }
+        if ("*".equals(fileName)) {
+            fileName = ALL_OPTION_LABEL;
+        }
+        if (bundleIdentifier == null) {
+            List<Bundle> bundles = new ArrayList<>();
+            for (Bundle bundle : bundleContext.getBundles()) {
+                if (bundle.findEntries("META-INF/cxs/", "*.json", true) != null) {
+                    bundles.add(bundle);
+                }
+            }
+
+            bundles = bundles.stream()
+                    .filter(b -> definitionTypes.stream().anyMatch((t) -> b.findEntries(getDefinitionTypePath(t), "*.json", true) != null))
+                    .collect(Collectors.toList());
+
+            List<String> bundleSymbolicNames = bundles.stream().map(Bundle::getSymbolicName).collect(Collectors.toList());
+            bundleSymbolicNames.add(ALL_OPTION_LABEL);
+
+            String bundleAnswer = askUserWithAuthorizedAnswer(session, "Which bundle ?" + getValuesWithNumber(bundleSymbolicNames) + "\n",
+                    IntStream.range(1,bundleSymbolicNames.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
+            String selectedBundle = bundleSymbolicNames.get(new Integer(bundleAnswer)-1);
+            if (selectedBundle.equals(ALL_OPTION_LABEL)) {
+                bundlesToUpdate = bundles;
+            } else {
+                bundlesToUpdate = Collections.singletonList(bundles.get(new Integer(bundleAnswer) - 1));
+            }
+        } else {
+            Bundle bundle = bundleContext.getBundle(bundleIdentifier);
+
+            if (bundle == null) {
+                System.out.println("Couldn't find a bundle with id: " + bundleIdentifier);
+                return null;
+            }
+
+            bundlesToUpdate = Collections.singletonList(bundle);
+        }
+
+        if (definitionType == null) {
+            List<String> possibleDefinitionNames = definitionTypes.stream().filter((t) -> bundlesToUpdate.stream().anyMatch(b->b.findEntries(getDefinitionTypePath(t), "*.json", true) != null)).collect(Collectors.toList());
+            possibleDefinitionNames.add(ALL_OPTION_LABEL);
+
+            if (possibleDefinitionNames.isEmpty()) {
+                System.out.println("Couldn't find definitions in bundle : " + bundlesToUpdate);
+                return null;
+            }
+
+            String definitionTypeAnswer = askUserWithAuthorizedAnswer(session, "Which kind of definition do you want to load?" + getValuesWithNumber(possibleDefinitionNames) + "\n",
+                    IntStream.range(1,possibleDefinitionNames.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
+            definitionType = possibleDefinitionNames.get(new Integer(definitionTypeAnswer)-1);
+        }
+
+        if (!definitionTypes.contains(definitionType) && !ALL_OPTION_LABEL.equals(definitionType)) {
+            System.out.println("Invalid type '" + definitionType + "' , allowed values : " +definitionTypes);
+            return null;
+        }
+
+        String definitionTypePath = getDefinitionTypePath(definitionType);
+        List<URL> definitionTypeURLs = bundlesToUpdate.stream().flatMap(b->b.findEntries(definitionTypePath, "*.json", true) != null ? Collections.list(b.findEntries(definitionTypePath, "*.json", true)).stream() : Stream.empty()).collect(Collectors.toList());
+        if (definitionTypeURLs.isEmpty()) {
+            System.out.println("Couldn't find definitions in bundle with id: " + bundleIdentifier + " and definition path: " + definitionTypePath);
+            return null;
+        }
+
+        if (fileName == null) {
+            List<String> definitionTypeFileNames = definitionTypeURLs.stream().map(u -> StringUtils.substringAfterLast(u.getFile(), "/")).sorted().collect(Collectors.toList());
+            definitionTypeFileNames.add(ALL_OPTION_LABEL);
+            String fileNameAnswer = askUserWithAuthorizedAnswer(session, "Which file do you want to load ?" + getValuesWithNumber(definitionTypeFileNames) + "\n",
+                    IntStream.range(1,definitionTypeFileNames.size()+1).mapToObj(Integer::toString).collect(Collectors.toList()));
+            fileName = definitionTypeFileNames.get(new Integer(fileNameAnswer)-1);
+        }
+        if (ALL_OPTION_LABEL.equals(fileName)) {
+            for (URL url : definitionTypeURLs) {
+                processDefinition(definitionType, url);
+            }
+        } else {
+            if (!fileName.contains("/")) {
+                fileName = "/" + fileName;
+            }
+            if (!fileName.endsWith(".json")) {
+                fileName += ".json";
+            }
+
+            Optional<URL> optionalURL = definitionTypeURLs.stream().filter(u -> u.getFile().endsWith(fileName)).findFirst();
+            if (optionalURL.isPresent()) {
+                URL url = optionalURL.get();
+                processDefinition(definitionType, url);
+            } else {
+                System.out.println("Couldn't find file " + fileName);
+                return null;
+            }
+        }
+
+        return null;
+    }
+
+    protected String askUserWithAuthorizedAnswer(Session session, String msg, List<String> authorizedAnswer) throws IOException {
+        String answer;
+        do {
+            answer = promptMessageToUser(session,msg);
+        } while (!authorizedAnswer.contains(answer.toLowerCase()));
+        return answer;
+    }
+
+    protected String promptMessageToUser(Session session, String msg) throws IOException {
+        LineReader reader = (LineReader) session.get(".jline.reader");
+        return reader.readLine(msg, null);
+    }
+
+    protected String getValuesWithNumber(List<String> values) {
+        StringBuilder definitionTypesWithNumber = new StringBuilder();
+        for (int i = 0; i < values.size(); i++) {
+            definitionTypesWithNumber.append("\n").append(i+1).append(". ").append(values.get(i));
+        }
+        return definitionTypesWithNumber.toString();
+    }
+
+    protected String getDefinitionTypePath(String definitionType) {
+        StringBuilder path = new StringBuilder("META-INF/cxs/");
+        if (!ALL_OPTION_LABEL.equals(definitionType)) {
+            path.append(definitionType);
+        }
+        return path.toString();
+    }
+
+}
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventList.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventList.java
new file mode 100644
index 0000000..9991b47
--- /dev/null
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventList.java
@@ -0,0 +1,78 @@
+/*
+ * 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.commands;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.services.DefinitionsService;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.common.DataTable;
+
+import java.util.ArrayList;
+
+@Command(scope = "unomi", name = "event-list", description = "This commands lists the latest events updated in the Apache Unomi Context Server")
+@Service
+public class EventList extends ListCommandSupport {
+
+    @Reference
+    private EventService eventService;
+
+    @Reference
+    DefinitionsService definitionsService;
+
+    @Argument(index = 0, name = "maxEntries", description = "The maximum number of entries to retrieve (defaults to 100)", required = false, multiValued = false)
+    int maxEntries = 100;
+
+    String[] columnHeaders = new String[] {
+            "ID",
+            "Type",
+            "Session",
+            "Profile",
+            "Timestamp",
+            "Scope",
+            "Persistent"
+    };
+
+    @Override
+    protected String[] getHeaders() {
+        return columnHeaders;
+    }
+
+    @Override
+    protected DataTable buildDataTable() {
+        Condition matchAllCondition = new Condition(definitionsService.getConditionType("matchAllCondition"));
+        PartialList<Event> lastEvents = eventService.searchEvents(matchAllCondition, 0, maxEntries);
+        DataTable dataTable = new DataTable();
+        for (Event event : lastEvents.getList()) {
+            ArrayList<Comparable> rowData = new ArrayList<>();
+            rowData.add(event.getItemId());
+            rowData.add(event.getEventType());
+            rowData.add(event.getSessionId());
+            rowData.add(event.getProfileId());
+            rowData.add(event.getTimeStamp().toString());
+            rowData.add(event.getScope());
+            rowData.add(Boolean.toString(event.isPersistent()));
+            dataTable.addRow(rowData.toArray(new Comparable[rowData.size()]));
+        }
+        return dataTable;
+    }
+}
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventSearch.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventSearch.java
new file mode 100644
index 0000000..082f1d3
--- /dev/null
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/EventSearch.java
@@ -0,0 +1,99 @@
+/*
+ * 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.commands;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.services.DefinitionsService;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.common.DataTable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Command(scope = "unomi", name = "event-search", description = "This commands search for profile events of a certain type by last timestamp in the Apache Unomi Context Server")
+@Service
+public class EventSearch extends ListCommandSupport  {
+    @Reference
+    private EventService eventService;
+
+    @Reference
+    DefinitionsService definitionsService;
+
+    @Argument(index = 0, name = "profile", description = "The identifier for the profile", required = true, multiValued = false)
+    String profileIdentifier;
+
+    @Argument(index = 1, name = "eventType", description = "The type of the event", required = false, multiValued = false)
+    String eventTypeId;
+
+    @Argument(index = 2, name = "maxEntries", description = "The maximum number of entries to retrieve (defaults to 100)", required = false, multiValued = false)
+    int maxEntries = 100;
+
+    String[] columnHeaders = new String[] {
+            "ID",
+            "Type",
+            "Session",
+            "Profile",
+            "Timestamp",
+            "Scope",
+            "Persistent"
+    };
+
+    @Override
+    protected String[] getHeaders() {
+        return columnHeaders;
+    }
+
+    @Override
+    protected DataTable buildDataTable() {
+        Condition booleanCondition = new Condition(definitionsService.getConditionType("booleanCondition"));
+        booleanCondition.setParameter("operator", "and");
+        List<Condition> subConditions = new ArrayList<>();
+        if (profileIdentifier != null) {
+            Condition eventProfileIdCondition = new Condition(definitionsService.getConditionType("eventPropertyCondition"));
+            eventProfileIdCondition.setParameter("propertyName", "profileId");
+            eventProfileIdCondition.setParameter("comparisonOperator", "equals");
+            eventProfileIdCondition.setParameter("propertyValue", profileIdentifier);
+            subConditions.add(eventProfileIdCondition);
+        }
+        if (eventTypeId != null) {
+            Condition eventTypeIdCondition = new Condition(definitionsService.getConditionType("eventTypeCondition"));
+            eventTypeIdCondition.setParameter("eventTypeId", eventTypeId);
+            subConditions.add(eventTypeIdCondition);
+        }
+        booleanCondition.setParameter("subConditions", subConditions);
+        PartialList<Event> lastEvents = eventService.searchEvents(booleanCondition, 0, maxEntries);
+        DataTable dataTable = new DataTable();
+        for (Event event : lastEvents.getList()) {
+            ArrayList<Comparable> rowData = new ArrayList<>();
+            rowData.add(event.getItemId());
+            rowData.add(event.getEventType());
+            rowData.add(event.getSessionId());
+            rowData.add(event.getProfileId());
+            rowData.add(event.getTimeStamp().toString());
+            rowData.add(event.getScope());
+            rowData.add(Boolean.toString(event.isPersistent()));
+            dataTable.addRow(rowData.toArray(new Comparable[rowData.size()]));
+        }
+        return dataTable;
+    }
+}
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/ProfileRemove.java
similarity index 56%
copy from tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
copy to tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/ProfileRemove.java
index d502148..6fba5d3 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/ProfileRemove.java
@@ -21,28 +21,20 @@ import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.segments.Segment;
-import org.apache.unomi.api.services.SegmentService;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
+import org.apache.unomi.api.services.ProfileService;
 
-@Command(scope = "unomi", name = "segment-view", description = "This will allows to view a segment in the Apache Unomi Context Server")
+@Command(scope = "unomi", name = "profile-remove", description = "This command will remove a profile")
 @Service
-public class SegmentView implements Action {
+public class ProfileRemove implements Action {
 
     @Reference
-    SegmentService segmentService;
+    ProfileService profileService;
 
-    @Argument(index = 0, name = "segmentId", description = "The identifier for the segment", required = true, multiValued = false)
-    String segmentIdentifier;
+    @Argument(index = 0, name = "profile", description = "The identifier for the profile", required = true, multiValued = false)
+    String profileIdentifier;
 
     public Object execute() throws Exception {
-        Segment segment = segmentService.getSegmentDefinition(segmentIdentifier);
-        if (segment == null) {
-            System.out.println("Couldn't find an action with id=" + segmentIdentifier);
-            return null;
-        }
-        String jsonRule = CustomObjectMapper.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(segment);
-        System.out.println(jsonRule);
+        profileService.delete(profileIdentifier, false);
         return null;
     }
 }
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/RuleRemove.java
similarity index 56%
copy from tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
copy to tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/RuleRemove.java
index d502148..b5afea0 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/RuleRemove.java
@@ -21,28 +21,20 @@ import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.segments.Segment;
-import org.apache.unomi.api.services.SegmentService;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
+import org.apache.unomi.api.services.RulesService;
 
-@Command(scope = "unomi", name = "segment-view", description = "This will allows to view a segment in the Apache Unomi Context Server")
+@Command(scope = "unomi", name = "rule-remove", description = "This will allows to remove a rule in the Apache Unomi Context Server")
 @Service
-public class SegmentView implements Action {
+public class RuleRemove implements Action {
 
     @Reference
-    SegmentService segmentService;
+    RulesService rulesService;
 
-    @Argument(index = 0, name = "segmentId", description = "The identifier for the segment", required = true, multiValued = false)
-    String segmentIdentifier;
+    @Argument(index = 0, name = "rule", description = "The identifier for the rule", required = true, multiValued = false)
+    String ruleIdentifier;
 
     public Object execute() throws Exception {
-        Segment segment = segmentService.getSegmentDefinition(segmentIdentifier);
-        if (segment == null) {
-            System.out.println("Couldn't find an action with id=" + segmentIdentifier);
-            return null;
-        }
-        String jsonRule = CustomObjectMapper.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(segment);
-        System.out.println(jsonRule);
+        rulesService.removeRule(ruleIdentifier);
         return null;
     }
 }
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentRemove.java
similarity index 55%
copy from tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
copy to tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentRemove.java
index d502148..14b4efd 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentRemove.java
@@ -21,13 +21,12 @@ import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.segments.Segment;
+import org.apache.unomi.api.segments.DependentMetadata;
 import org.apache.unomi.api.services.SegmentService;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
 
-@Command(scope = "unomi", name = "segment-view", description = "This will allows to view a segment in the Apache Unomi Context Server")
+@Command(scope = "unomi", name = "segment-remove", description = "Remove segments in the Apache Unomi Context Server")
 @Service
-public class SegmentView implements Action {
+public class SegmentRemove implements Action {
 
     @Reference
     SegmentService segmentService;
@@ -35,14 +34,23 @@ public class SegmentView implements Action {
     @Argument(index = 0, name = "segmentId", description = "The identifier for the segment", required = true, multiValued = false)
     String segmentIdentifier;
 
+    @Argument(index = 1, name = "validate", description = "Check if the segment is used in goals or other segments", required = false, multiValued = false)
+    Boolean validate = true;
+
+
     public Object execute() throws Exception {
-        Segment segment = segmentService.getSegmentDefinition(segmentIdentifier);
-        if (segment == null) {
-            System.out.println("Couldn't find an action with id=" + segmentIdentifier);
-            return null;
+        DependentMetadata dependantMetadata = segmentService.removeSegmentDefinition(segmentIdentifier, validate);
+        if (!validate || (dependantMetadata.getSegments().isEmpty() && dependantMetadata.getScorings().isEmpty())) {
+            System.out.println("Segment " + segmentIdentifier + " successfully deleted");
+        } else if (validate) {
+            System.out.print("Segment " + segmentIdentifier + " could not be deleted because of the following dependents:");
+            if (!dependantMetadata.getScorings().isEmpty()) {
+                System.out.print(" scoring:" + dependantMetadata.getScorings());
+            }
+            if (!dependantMetadata.getSegments().isEmpty()) {
+                System.out.println(" segments:" + dependantMetadata.getSegments());
+            }
         }
-        String jsonRule = CustomObjectMapper.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(segment);
-        System.out.println(jsonRule);
         return null;
     }
 }
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
index d502148..9016aa9 100644
--- a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/SegmentView.java
@@ -38,7 +38,7 @@ public class SegmentView implements Action {
     public Object execute() throws Exception {
         Segment segment = segmentService.getSegmentDefinition(segmentIdentifier);
         if (segment == null) {
-            System.out.println("Couldn't find an action with id=" + segmentIdentifier);
+            System.out.println("Couldn't find a segment with id=" + segmentIdentifier);
             return null;
         }
         String jsonRule = CustomObjectMapper.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(segment);
diff --git a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/UndeployDefinition.java b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/UndeployDefinition.java
new file mode 100644
index 0000000..e672bff
--- /dev/null
+++ b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/commands/UndeployDefinition.java
@@ -0,0 +1,111 @@
+/*
+ * 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.commands;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.unomi.api.Patch;
+import org.apache.unomi.api.PersonaWithSessions;
+import org.apache.unomi.api.PropertyType;
+import org.apache.unomi.api.actions.ActionType;
+import org.apache.unomi.api.campaigns.Campaign;
+import org.apache.unomi.api.conditions.ConditionType;
+import org.apache.unomi.api.goals.Goal;
+import org.apache.unomi.api.rules.Rule;
+import org.apache.unomi.api.segments.Scoring;
+import org.apache.unomi.api.segments.Segment;
+import org.apache.unomi.persistence.spi.CustomObjectMapper;
+
+import java.io.IOException;
+import java.net.URL;
+
+@Command(scope = "unomi", name = "undeploy-definition", description = "This will undeploy definitions contained in bundles")
+@Service
+public class UndeployDefinition extends DeploymentCommandSupport {
+
+    public void processDefinition(String definitionType, URL definitionURL) {
+        try {
+            if (ALL_OPTION_LABEL.equals(definitionType)) {
+                String definitionURLString = definitionURL.toString();
+                for (String possibleDefinitionType : definitionTypes) {
+                    if (definitionURLString.contains(getDefinitionTypePath(possibleDefinitionType))) {
+                        definitionType = possibleDefinitionType;
+                        break;
+                    }
+                }
+                if (ALL_OPTION_LABEL.equals(definitionType)) {
+                    System.out.println("Couldn't resolve definition type for definition URL " + definitionURL);
+                    return;
+                }
+            }
+            boolean successful = true;
+            switch (definitionType) {
+                case CONDITION_DEFINITION_TYPE:
+                    ConditionType conditionType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, ConditionType.class);
+                    definitionsService.removeActionType(conditionType.getItemId());
+                    break;
+                case ACTION_DEFINITION_TYPE:
+                    ActionType actionType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, ActionType.class);
+                    definitionsService.removeActionType(actionType.getItemId());
+                    break;
+                case GOAL_DEFINITION_TYPE:
+                    Goal goal = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Goal.class);
+                    goalsService.removeGoal(goal.getItemId());
+                    break;
+                case CAMPAIGN_DEFINITION_TYPE:
+                    Campaign campaign = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Campaign.class);
+                    goalsService.removeCampaign(campaign.getItemId());
+                    break;
+                case PERSONA_DEFINITION_TYPE:
+                    PersonaWithSessions persona = CustomObjectMapper.getObjectMapper().readValue(definitionURL, PersonaWithSessions.class);
+                    profileService.delete(persona.getPersona().getItemId(), true);
+                    break;
+                case PROPERTY_DEFINITION_TYPE:
+                    PropertyType propertyType = CustomObjectMapper.getObjectMapper().readValue(definitionURL, PropertyType.class);
+                    profileService.deletePropertyType(propertyType.getItemId());
+                    break;
+                case RULE_DEFINITION_TYPE:
+                    Rule rule = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Rule.class);
+                    rulesService.removeRule(rule.getItemId());
+                    break;
+                case SEGMENT_DEFINITION_TYPE:
+                    Segment segment = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Segment.class);
+                    segmentService.removeSegmentDefinition(segment.getItemId(), false);
+                    break;
+                case SCORING_DEFINITION_TYPE:
+                    Scoring scoring = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Scoring.class);
+                    segmentService.removeScoringDefinition(scoring.getItemId(), false);
+                    break;
+                case PATCH_DEFINITION_TYPE:
+                    Patch patch = CustomObjectMapper.getObjectMapper().readValue(definitionURL, Patch.class);
+                    // patchService.patch(patch);
+                    break;
+                default:
+                    System.out.println("Unrecognized definition type: " + definitionType);
+                    successful = false;
+                    break;
+            }
+            if (successful) {
+                System.out.println("Predefined definition unregistered : " + definitionURL.getFile());
+            }
+        } catch (IOException e) {
+            System.out.println("Error while removing definition " + definitionURL);
+            System.out.println(e.getMessage());
+        }
+    }
+
+}