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:05 UTC
[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.
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());
+ }
+ }
+
+}