This is an automated email from the ASF dual-hosted git repository.
shuber pushed a commit to branch unomi-3-dev
in repository https://gitbox.apache.org/repos/asf/unomi.git
The following commit(s) were added to refs/heads/unomi-3-dev by this push:
new ccc07678e [UNOMI-879] feat(shell): enhance CSV output and table
formatting for CRUD commands
ccc07678e is described below
commit ccc07678ed56c1ddd6f84ccd115f0808229da2ec
Author: Serge Huber <[email protected]>
AuthorDate: Wed Jan 21 20:19:51 2026 +0100
[UNOMI-879] feat(shell): enhance CSV output and table formatting for CRUD
commands
- Add proper CSV output support using Apache Commons CSV library
- Fix --csv option parsing when placed before list operation arguments
- Convert cache statistics from plain text to ShellTable format
- Add CSV output option to cache commands with proper formatting
- Remove redundant specific completers (CampaignCompleter,
EventTypeCompleter, etc.)
- Use unified IdCompleter for all CRUD command ID completion
- Update UnomiCrudCommand to use CustomObjectMapper for consistency
- Add buildCsvOutput method to CrudCommand interface and BaseCrudCommand
- Update integration tests to validate table headers and CSV format
- Add commons-csv dependency to shell-dev-commands pom.xml
---
.../apache/unomi/itests/shell/CacheCommandsIT.java | 111 +++++++----
.../apache/unomi/itests/shell/CrudCommandsIT.java | 19 ++
tools/shell-dev-commands/pom.xml | 4 +
.../unomi/shell/dev/actions/UnomiCrudCommand.java | 65 +++----
.../unomi/shell/dev/commands/CacheCommands.java | 109 +++++++++--
.../commands/actions/ActionTypeCrudCommand.java | 15 +-
.../dev/commands/apikeys/ApiKeyCrudCommand.java | 4 +-
.../commands/campaigns/CampaignCrudCommand.java | 4 +-
.../campaigns/CampaignEventCrudCommand.java | 14 +-
.../conditions/ConditionTypeCrudCommand.java | 4 +-
.../dev/commands/consents/ConsentCrudCommand.java | 4 +-
.../dev/commands/events/EventCrudCommand.java | 4 +-
.../shell/dev/commands/goals/GoalCrudCommand.java | 4 +-
.../dev/commands/personas/PersonaCrudCommand.java | 4 +-
.../commands/profiles/ProfileAliasCrudCommand.java | 15 +-
.../dev/commands/profiles/ProfileCrudCommand.java | 4 +-
.../properties/PropertyTypeCrudCommand.java | 18 +-
.../shell/dev/commands/rules/RuleCrudCommand.java | 4 +-
.../commands/rules/RuleStatisticsCrudCommand.java | 4 +-
.../dev/commands/scopes/ScopeCrudCommand.java | 4 +-
.../dev/commands/scoring/ScoringCrudCommand.java | 4 +-
.../dev/commands/segments/SegmentCrudCommand.java | 4 +-
.../dev/commands/sessions/SessionCrudCommand.java | 14 +-
.../dev/commands/tenants/TenantCrudCommand.java | 74 ++++----
.../dev/commands/topics/TopicCrudCommand.java | 4 +-
.../shell/dev/completers/CampaignCompleter.java | 37 ----
.../shell/dev/completers/EventTypeCompleter.java | 63 -------
.../unomi/shell/dev/completers/GoalCompleter.java | 37 ----
.../shell/dev/completers/IPAddressCompleter.java | 54 ------
.../unomi/shell/dev/completers/IdCompleter.java | 77 +++++---
.../shell/dev/completers/ProfileCompleter.java | 70 -------
.../unomi/shell/dev/completers/RuleCompleter.java | 69 -------
.../unomi/shell/dev/completers/ScopeCompleter.java | 37 ----
.../shell/dev/completers/ScoringCompleter.java | 37 ----
.../shell/dev/completers/SegmentCompleter.java | 57 ------
.../shell/dev/completers/SessionCompleter.java | 72 -------
.../dev/completers/TenantStatusCompleter.java | 42 -----
.../unomi/shell/dev/services/BaseCrudCommand.java | 206 +++++++++++++++------
.../unomi/shell/dev/services/CrudCommand.java | 12 ++
39 files changed, 496 insertions(+), 888 deletions(-)
diff --git
a/itests/src/test/java/org/apache/unomi/itests/shell/CacheCommandsIT.java
b/itests/src/test/java/org/apache/unomi/itests/shell/CacheCommandsIT.java
index 13e920c34..a305c2068 100644
--- a/itests/src/test/java/org/apache/unomi/itests/shell/CacheCommandsIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/shell/CacheCommandsIT.java
@@ -27,33 +27,37 @@ public class CacheCommandsIT extends ShellCommandsBaseIT {
@Test
public void testCacheStats() throws Exception {
String output = executeCommandAndGetOutput("unomi:cache --stats");
- assertContainsAny(output, new String[]{"Statistics for type:",
"Hits:", "Misses:"},
- "Should show statistics for type");
+ // With ShellTable output, check for table headers instead of plain
text
+ assertContainsAny(output, new String[]{"Type", "Hits", "Misses", "No
cache statistics available"},
+ "Should show statistics table or indicate no stats");
- // If statistics are shown, validate they contain numeric values
- if (output.contains("Hits:")) {
- validateNumericValuesInOutput(output, new String[]{"Hits:",
"Misses:", "Updates:"}, false);
+ // If statistics are shown in table format, validate table structure
+ if (output.contains("Type") && output.contains("Hits")) {
+ validateTableHeaders(output, new String[]{"Type", "Hits",
"Misses"});
+ // Table should have at least header row
+ String[] lines = output.split("\n");
+ Assert.assertTrue("Should have table output with headers",
lines.length > 0);
}
}
@Test
public void testCacheStatsWithReset() throws Exception {
String output = executeCommandAndGetOutput("unomi:cache --stats
--reset");
- // Should show statistics and reset confirmation
- assertContainsAny(output, new String[]{"Statistics have been reset",
"Statistics for type:"},
- "Should show statistics have been reset");
+ // Should show statistics table and reset confirmation
+ assertContainsAny(output, new String[]{"Statistics have been reset",
"Type", "Hits"},
+ "Should show statistics table and reset confirmation");
- // If no explicit reset message, at least verify stats were shown
+ // If no explicit reset message, at least verify stats table was shown
if (!output.contains("Statistics have been reset")) {
- assertContainsAny(output, new String[]{"Statistics for type:",
"Hits:"},
- "Should show cache statistics");
+ assertContainsAny(output, new String[]{"Type", "Hits", "Misses"},
+ "Should show cache statistics table");
}
}
@Test
public void testCacheStatsWithTenant() throws Exception {
String output = executeCommandAndGetOutput("unomi:cache --stats
--tenant " + TEST_TENANT_ID);
- // Should show statistics (may be empty if no cache activity)
+ // Should show statistics table (may be empty if no cache activity)
// Note: --tenant option sets the tenantId but displayStatistics()
doesn't filter by tenant,
// so it shows all statistics. The output may be empty if there are no
statistics at all.
// Empty output is valid (means no statistics available)
@@ -63,16 +67,15 @@ public class CacheCommandsIT extends ShellCommandsBaseIT {
}
assertContainsAny(output, new String[]{
- "Statistics for type:",
- "Hits:",
- "No statistics available",
+ "Type",
+ "Hits",
+ "No cache statistics available",
"Cache service not available"
- }, "Should show cache statistics, indicate no stats, or service
unavailable");
+ }, "Should show cache statistics table, indicate no stats, or service
unavailable");
- // If stats are shown, they should be valid
- if (output.contains("Statistics for type:")) {
- assertContainsAny(output, new String[]{"Hits:", "Misses:"},
- "Should contain Hits or Misses when stats are shown");
+ // If stats table is shown, validate table structure
+ if (output.contains("Type") && output.contains("Hits")) {
+ validateTableHeaders(output, new String[]{"Type", "Hits",
"Misses"});
}
}
@@ -104,34 +107,68 @@ public class CacheCommandsIT extends ShellCommandsBaseIT {
@Test
public void testCacheStatsWithType() throws Exception {
String output = executeCommandAndGetOutput("unomi:cache --stats --type
profile");
- // Should show stats for the specific type or indicate no stats
+ // Should show stats table for the specific type or indicate no stats
assertContainsAny(output, new String[]{
- "Statistics for type: profile",
+ "profile",
"No statistics available for type: profile",
- "Hits:"
- }, "Should show statistics for profile type or indicate no stats");
+ "Type",
+ "Hits"
+ }, "Should show statistics table for profile type or indicate no
stats");
- // If stats are shown, verify they're for the correct type
- if (output.contains("Statistics for type: profile")) {
- assertContainsAny(output, new String[]{"Hits:", "Misses:"},
- "Should show Hits or Misses for profile type");
+ // If stats table is shown, verify it contains the type and table
structure
+ if (output.contains("Type") && output.contains("Hits")) {
+ validateTableHeaders(output, new String[]{"Type", "Hits",
"Misses"});
+ // If profile type is in the table, it should be in a data row
+ if (tableContainsValue(output, "profile")) {
+ Assert.assertTrue("Should show profile type in table", true);
+ }
}
}
@Test
public void testCacheDetailedStats() throws Exception {
String output = executeCommandAndGetOutput("unomi:cache --stats
--detailed");
- // Detailed stats should show additional metrics like efficiency score
+ // Detailed stats should show additional columns like efficiency score
and error rate
assertContainsAny(output, new String[]{
- "Statistics for type:",
- "Efficiency Score:",
- "Error Rate:",
- "Hits:"
- }, "Should show detailed statistics");
+ "Type",
+ "Efficiency Score",
+ "Error Rate",
+ "Hits"
+ }, "Should show detailed statistics table with additional columns");
- // If detailed stats are shown, verify they contain numeric values
(allow decimals)
- if (output.contains("Efficiency Score:") || output.contains("Error
Rate:")) {
- validateNumericValuesInOutput(output, new String[]{"Efficiency
Score:", "Error Rate:"}, true);
+ // If detailed stats table is shown, verify it has the additional
columns
+ if (output.contains("Type") && output.contains("Hits")) {
+ validateTableHeaders(output, new String[]{"Type", "Hits",
"Efficiency Score", "Error Rate"});
+ }
+ }
+
+ @Test
+ public void testCacheStatsCsv() throws Exception {
+ String csvOutput = executeCommandAndGetOutput("unomi:cache --stats
--csv");
+ // CSV should contain commas and have at least header row
+ Assert.assertTrue("Should output CSV format", csvOutput.contains(",")
|| csvOutput.trim().length() > 0);
+ // CSV should have at least one line (header)
+ String[] lines = csvOutput.split("\n");
+ Assert.assertTrue("CSV output should have at least header line",
lines.length > 0);
+ // CSV header should contain expected columns
+ if (lines.length > 0) {
+ String header = lines[0];
+ assertContainsAny(header, new String[]{"Type", "Hits", "Misses"},
+ "CSV header should contain expected columns");
+ }
+ }
+
+ @Test
+ public void testCacheStatsDetailedCsv() throws Exception {
+ String csvOutput = executeCommandAndGetOutput("unomi:cache --stats
--detailed --csv");
+ // CSV should contain commas and have detailed columns
+ Assert.assertTrue("Should output CSV format", csvOutput.contains(",")
|| csvOutput.trim().length() > 0);
+ // CSV header should contain detailed columns
+ String[] lines = csvOutput.split("\n");
+ if (lines.length > 0) {
+ String header = lines[0];
+ assertContainsAny(header, new String[]{"Type", "Hits", "Efficiency
Score", "Error Rate"},
+ "CSV header should contain detailed columns");
}
}
}
diff --git
a/itests/src/test/java/org/apache/unomi/itests/shell/CrudCommandsIT.java
b/itests/src/test/java/org/apache/unomi/itests/shell/CrudCommandsIT.java
index 48a8632be..31b179304 100644
--- a/itests/src/test/java/org/apache/unomi/itests/shell/CrudCommandsIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/shell/CrudCommandsIT.java
@@ -344,6 +344,25 @@ public class CrudCommandsIT extends ShellCommandsBaseIT {
Assert.assertTrue("CSV output should have at least one line",
lines.length > 0);
}
+ @Test
+ public void testGoalListCsvBeforeList() throws Exception {
+ // Test --csv option before list operation (fix for option parsing
issue)
+ String csvOutput = executeCommandAndGetOutput("unomi:crud --csv list
goal");
+ // CSV should contain commas and have at least one line
+ Assert.assertTrue("Should output CSV format when --csv is before
list",
+ csvOutput.contains(",") || csvOutput.trim().length() > 0);
+ // CSV should have at least header line
+ String[] lines = csvOutput.split("\n");
+ Assert.assertTrue("CSV output should have at least header line",
lines.length > 0);
+ // Verify it's actually CSV (not table format with spaces)
+ if (lines.length > 0) {
+ String firstLine = lines[0];
+ // CSV should have commas, not just spaces
+ Assert.assertTrue("First line should contain commas (CSV format)",
+ firstLine.contains(",") || firstLine.trim().isEmpty());
+ }
+ }
+
/**
* Helper method to test basic CRUD operations for an object type.
* Reduces code duplication across similar object types.
diff --git a/tools/shell-dev-commands/pom.xml b/tools/shell-dev-commands/pom.xml
index 3519e74e3..e62a63758 100644
--- a/tools/shell-dev-commands/pom.xml
+++ b/tools/shell-dev-commands/pom.xml
@@ -100,6 +100,10 @@
<artifactId>commons-lang3</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-csv</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/actions/UnomiCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/actions/UnomiCrudCommand.java
index e42d097d5..2ca8433f1 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/actions/UnomiCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/actions/UnomiCrudCommand.java
@@ -18,6 +18,7 @@ package org.apache.unomi.shell.dev.actions;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
+import org.apache.unomi.persistence.spi.CustomObjectMapper;
import org.apache.karaf.shell.api.action.*;
import org.apache.karaf.shell.api.action.lifecycle.Init;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
@@ -48,7 +49,7 @@ public class UnomiCrudCommand implements Action {
private static final Logger LOGGER =
LoggerFactory.getLogger(UnomiCrudCommand.class.getName());
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private static final ObjectMapper OBJECT_MAPPER =
CustomObjectMapper.getObjectMapper();
@Reference
private BundleContext bundleContext;
@@ -127,15 +128,18 @@ public class UnomiCrudCommand implements Action {
* Parse list-specific options from the remaining argument list.
* This implements Option 1: Simple Manual Parsing from the redesign
proposal.
*
+ * Note: If --csv was already set by Karaf's option parser (when placed
before arguments),
+ * we preserve that value. Otherwise, we parse it from the remaining list.
+ *
* @param remaining List of remaining tokens after type (e.g., ["--csv",
"-n", "50"])
*/
private void parseListOptions(List<String> remaining) {
- boolean csv = false;
- Integer maxEntries = null;
+ // Preserve csv value if already set by Karaf's option parser (when
--csv comes before arguments)
+ boolean csv = this.csv;
+ Integer maxEntries = this.maxEntries;
if (remaining == null || remaining.isEmpty()) {
- this.csv = csv;
- this.maxEntries = maxEntries;
+ // Keep existing values if already set by Karaf
return;
}
@@ -396,13 +400,13 @@ public class UnomiCrudCommand implements Action {
* Find and execute the CrudCommand for the given type.
*
* @param console console for output
- * @return the result of the operation, or null if no handler found
+ * @return true if a handler was found and executed, false otherwise
* @throws Exception if the operation fails
*/
- private Object findAndExecuteCommand(PrintStream console) throws Exception
{
+ private boolean findAndExecuteCommand(PrintStream console) throws
Exception {
ServiceReference<?>[] refs =
bundleContext.getAllServiceReferences(CrudCommand.class.getName(), null);
if (refs == null) {
- return null;
+ return false;
}
String operationLower = operation.toLowerCase();
@@ -410,13 +414,14 @@ public class UnomiCrudCommand implements Action {
CrudCommand cmd = (CrudCommand) bundleContext.getService(ref);
if (cmd.getObjectType().equals(type)) {
try {
- return executeOperation(cmd, operationLower, console);
+ executeOperation(cmd, operationLower, console);
+ return true; // Handler found and executed
} finally {
bundleContext.ungetService(ref);
}
}
}
- return null;
+ return false; // No handler found
}
@Override
@@ -427,11 +432,11 @@ public class UnomiCrudCommand implements Action {
return null;
}
- Object result = findAndExecuteCommand(console);
- if (result == null) {
+ boolean handlerFound = findAndExecuteCommand(console);
+ if (!handlerFound) {
console.println("No handler found for object type: " + type);
}
- return result;
+ return null;
}
/**
@@ -541,16 +546,7 @@ public class UnomiCrudCommand implements Action {
String id = remaining.get(0);
String jsonOrUrl = remaining.get(1);
- if (StringUtils.isBlank(id)) {
- console.println("Error: ID is required for update operation");
- return null;
- }
-
- if (StringUtils.isBlank(jsonOrUrl)) {
- console.println("Error: JSON string or URL is required for update
operation");
- return null;
- }
-
+ // hasMinimumRemainingArgs already ensures both id and jsonOrUrl are
non-blank
Map<String, Object> updateProps =
parsePropertiesWithErrorHandling(jsonOrUrl, console);
if (updateProps == null) {
return null;
@@ -586,22 +582,27 @@ public class UnomiCrudCommand implements Action {
// Parse list-specific options from remaining argument
parseListOptions(remaining);
- ShellTable table = new ShellTable();
- if (csv) {
- table.noHeaders().separator(",");
- }
String[] headers = cmd.getHeaders();
if (headers == null || headers.length == 0) {
console.println("Error: No headers available for " + type);
return null;
}
- for (String header : headers) {
- table.column(header);
- }
+
// Ensure limit is positive (default to 100 if null or invalid)
int limit = (maxEntries != null && maxEntries > 0) ? maxEntries : 100;
- cmd.buildRows(table, limit);
- table.print(console, !csv);
+
+ if (csv) {
+ // Generate proper CSV output using Apache Commons CSV
+ cmd.buildCsvOutput(console, headers, limit);
+ } else {
+ // Generate table output
+ ShellTable table = new ShellTable();
+ for (String header : headers) {
+ table.column(header);
+ }
+ cmd.buildRows(table, limit);
+ table.print(console, true);
+ }
return null;
}
}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/CacheCommands.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/CacheCommands.java
index b82869891..110990e51 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/CacheCommands.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/CacheCommands.java
@@ -16,12 +16,13 @@
*/
package org.apache.unomi.shell.dev.commands;
-import org.apache.karaf.shell.api.action.Action;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Option;
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.karaf.shell.support.table.ShellTable;
import org.apache.unomi.api.services.ExecutionContextManager;
import org.apache.unomi.api.services.cache.MultiTypeCacheService;
@@ -32,7 +33,9 @@ import
org.apache.unomi.shell.dev.commands.TenantContextHelper;
import java.io.PrintStream;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -73,6 +76,9 @@ public class CacheCommands extends BaseSimpleCommand {
@Option(name = "--watch", description = "Watch cache statistics (refresh
interval in seconds)", required = false)
private int watchInterval = 0;
+ @Option(name = "--csv", description = "Output statistics in CSV format",
required = false)
+ private boolean csv = false;
+
@Option(name = "--id", description = "Specific entry ID to view or
remove", required = false)
private String entryId;
@@ -234,18 +240,20 @@ public class CacheCommands extends BaseSimpleCommand {
CacheStatistics stats = cacheService.getStatistics();
Map<String, TypeStatistics> allStats = stats.getAllStats();
+ if (allStats.isEmpty()) {
+ println("No cache statistics available");
+ return;
+ }
+
if (type != null) {
TypeStatistics typeStats = allStats.get(type);
if (typeStats == null) {
println("No statistics available for type: " + type);
return;
}
- printTypeStats(type, typeStats);
+ displayStatisticsTable(Map.of(type, typeStats));
} else {
- for (Map.Entry<String, TypeStatistics> entry :
allStats.entrySet()) {
- printTypeStats(entry.getKey(), entry.getValue());
- println("---");
- }
+ displayStatisticsTable(allStats);
}
if (reset) {
@@ -254,27 +262,90 @@ public class CacheCommands extends BaseSimpleCommand {
}
}
- private void printTypeStats(String type, TypeStatistics stats) {
- println("Statistics for type: " + type);
- println(" Hits: " + stats.getHits());
- println(" Misses: " + stats.getMisses());
- println(" Updates: " + stats.getUpdates());
- println(" Validation Failures: " + stats.getValidationFailures());
- println(" Indexing Errors: " + stats.getIndexingErrors());
+ private void displayStatisticsTable(Map<String, TypeStatistics> allStats) {
+ PrintStream console = getConsole();
+
+ // Build headers
+ List<String> headers = new ArrayList<>();
+ headers.add("Type");
+ headers.add("Hits");
+ headers.add("Misses");
+ headers.add("Updates");
+ headers.add("Validation Failures");
+ headers.add("Indexing Errors");
+ headers.add("Hit Ratio (%)");
+ headers.add("Miss Ratio (%)");
+ if (detailed) {
+ headers.add("Efficiency Score");
+ headers.add("Error Rate (%)");
+ }
+
+ if (csv) {
+ // Generate CSV output
+ try {
+ CSVFormat csvFormat = CSVFormat.DEFAULT;
+ CSVPrinter printer = csvFormat.print(console);
+
+ // Print header
+ printer.printRecord(headers.toArray());
+
+ // Print data rows
+ for (Map.Entry<String, TypeStatistics> entry :
allStats.entrySet()) {
+ List<String> row = buildStatisticsRow(entry.getKey(),
entry.getValue());
+ printer.printRecord(row.toArray());
+ }
+
+ printer.close();
+ } catch (Exception e) {
+ console.println("Error generating CSV output: " +
e.getMessage());
+ }
+ } else {
+ // Generate table output
+ ShellTable table = new ShellTable();
+ for (String header : headers) {
+ table.column(header);
+ }
+
+ for (Map.Entry<String, TypeStatistics> entry :
allStats.entrySet()) {
+ List<String> row = buildStatisticsRow(entry.getKey(),
entry.getValue());
+ table.addRow().addContent(row.toArray());
+ }
+
+ table.print(console);
+ }
+ }
+
+ private List<String> buildStatisticsRow(String type, TypeStatistics stats)
{
+ List<String> row = new ArrayList<>();
+ row.add(type);
+ row.add(String.valueOf(stats.getHits()));
+ row.add(String.valueOf(stats.getMisses()));
+ row.add(String.valueOf(stats.getUpdates()));
+ row.add(String.valueOf(stats.getValidationFailures()));
+ row.add(String.valueOf(stats.getIndexingErrors()));
long total = stats.getHits() + stats.getMisses();
if (total > 0) {
double hitRatio = (double) stats.getHits() / total * 100;
double missRatio = (double) stats.getMisses() / total * 100;
- printf(" Hit Ratio: %.2f%%\n", hitRatio);
- printf(" Miss Ratio: %.2f%%\n", missRatio);
+ row.add(String.format("%.2f", hitRatio));
+ row.add(String.format("%.2f", missRatio));
if (detailed) {
- printf(" Efficiency Score: %.2f\n",
calculateEfficiencyScore(stats));
- printf(" Error Rate: %.2f%%\n",
- (double)(stats.getValidationFailures() +
stats.getIndexingErrors()) / total * 100);
+ row.add(String.format("%.2f",
calculateEfficiencyScore(stats)));
+ double errorRate = (double)(stats.getValidationFailures() +
stats.getIndexingErrors()) / total * 100;
+ row.add(String.format("%.2f", errorRate));
+ }
+ } else {
+ row.add("0.00");
+ row.add("0.00");
+ if (detailed) {
+ row.add("0.00");
+ row.add("0.00");
}
}
+
+ return row;
}
private double calculateEfficiencyScore(TypeStatistics stats) {
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/actions/ActionTypeCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/actions/ActionTypeCrudCommand.java
index 3c52088f2..319464aef 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/actions/ActionTypeCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/actions/ActionTypeCrudCommand.java
@@ -68,16 +68,7 @@ public class ActionTypeCrudCommand extends BaseCrudCommand {
@Override
protected PartialList<?> getItems(Query query) {
List<ActionType> actionTypes = new
ArrayList<>(definitionsService.getAllActionTypes());
-
- // Apply query limit
- Integer offset = query.getOffset();
- Integer limit = query.getLimit();
- int start = offset == null ? 0 : offset;
- int size = limit == null ? actionTypes.size() : limit;
- int end = Math.min(start + size, actionTypes.size());
-
- List<ActionType> pagedActionTypes = actionTypes.subList(start, end);
- return new PartialList<>(pagedActionTypes, start,
pagedActionTypes.size(), actionTypes.size(), PartialList.Relation.EQUAL);
+ return paginateList(actionTypes, query);
}
@Override
@@ -146,9 +137,7 @@ public class ActionTypeCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/apikeys/ApiKeyCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/apikeys/ApiKeyCrudCommand.java
index f9b2ec8c6..d91446ec8 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/apikeys/ApiKeyCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/apikeys/ApiKeyCrudCommand.java
@@ -186,9 +186,7 @@ public class ApiKeyCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignCrudCommand.java
index 42e589f55..caa609f47 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignCrudCommand.java
@@ -125,9 +125,7 @@ public class CampaignCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignEventCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignEventCrudCommand.java
index 16bd1352f..8096e9dcb 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignEventCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/campaigns/CampaignEventCrudCommand.java
@@ -108,11 +108,6 @@ public class CampaignEventCrudCommand extends
BaseCrudCommand {
@Override
public void update(String id, Map<String, Object> properties) {
- // First check if the event exists
- if (read(id) == null) {
- return;
- }
-
CampaignEvent updatedEvent = OBJECT_MAPPER.convertValue(properties,
CampaignEvent.class);
updatedEvent.setItemId(id);
goalsService.setCampaignEvent(updatedEvent);
@@ -120,17 +115,12 @@ public class CampaignEventCrudCommand extends
BaseCrudCommand {
@Override
public void delete(String id) {
- // First check if the event exists
- if (read(id) != null) {
- goalsService.removeCampaignEvent(id);
- }
+ goalsService.removeCampaignEvent(id);
}
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/conditions/ConditionTypeCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/conditions/ConditionTypeCrudCommand.java
index ef2f10367..b98560290 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/conditions/ConditionTypeCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/conditions/ConditionTypeCrudCommand.java
@@ -124,9 +124,7 @@ public class ConditionTypeCrudCommand extends
BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/consents/ConsentCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/consents/ConsentCrudCommand.java
index cf9c089bb..ed59c4288 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/consents/ConsentCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/consents/ConsentCrudCommand.java
@@ -224,9 +224,7 @@ public class ConsentCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/events/EventCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/events/EventCrudCommand.java
index 33551ca28..697867bd3 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/events/EventCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/events/EventCrudCommand.java
@@ -151,9 +151,7 @@ public class EventCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/goals/GoalCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/goals/GoalCrudCommand.java
index 43ca2f92a..38a7e77ef 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/goals/GoalCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/goals/GoalCrudCommand.java
@@ -119,9 +119,7 @@ public class GoalCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/personas/PersonaCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/personas/PersonaCrudCommand.java
index 85d3871e4..45e0b8845 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/personas/PersonaCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/personas/PersonaCrudCommand.java
@@ -140,9 +140,7 @@ public class PersonaCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileAliasCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileAliasCrudCommand.java
index d3d896bb9..64b27af14 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileAliasCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileAliasCrudCommand.java
@@ -77,8 +77,8 @@ public class ProfileAliasCrudCommand extends BaseCrudCommand {
@Override
public Map<String, Object> read(String id) {
// Since there's no direct method to get a single alias, we'll need to
search for it
- // We'll use findProfileAliases with a small limit since we know the ID
- PartialList<ProfileAlias> aliases =
profileService.findProfileAliases(null, 0, 1, null);
+ // Search with a reasonable limit to find the alias by ID
+ PartialList<ProfileAlias> aliases =
profileService.findProfileAliases(null, 0, 100, null);
ProfileAlias alias = aliases.getList().stream()
.filter(a -> a.getItemId().equals(id))
.findFirst()
@@ -108,13 +108,14 @@ public class ProfileAliasCrudCommand extends
BaseCrudCommand {
@Override
public void update(String id, Map<String, Object> properties) {
- // First check if the alias exists
- if (read(id) == null) {
+ // Get the existing alias (check if it exists and get its data in one
call)
+ Map<String, Object> aliasData = read(id);
+ if (aliasData == null) {
return;
}
// Remove the old alias and add the new one
- ProfileAlias oldAlias = OBJECT_MAPPER.convertValue(read(id),
ProfileAlias.class);
+ ProfileAlias oldAlias = OBJECT_MAPPER.convertValue(aliasData,
ProfileAlias.class);
profileService.removeAliasFromProfile(oldAlias.getProfileID(),
oldAlias.getItemId(), oldAlias.getClientID());
ProfileAlias updatedAlias = OBJECT_MAPPER.convertValue(properties,
ProfileAlias.class);
@@ -135,9 +136,7 @@ public class ProfileAliasCrudCommand extends
BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileCrudCommand.java
index dc6f96d8b..3dc1c6f0c 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/profiles/ProfileCrudCommand.java
@@ -144,9 +144,7 @@ public class ProfileCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/properties/PropertyTypeCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/properties/PropertyTypeCrudCommand.java
index f8eaa5a23..55b31301f 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/properties/PropertyTypeCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/properties/PropertyTypeCrudCommand.java
@@ -70,7 +70,7 @@ public class PropertyTypeCrudCommand extends BaseCrudCommand {
}
@Override
- public PartialList<?> getItems(Query query) {
+ protected PartialList<?> getItems(Query query) {
Map<String, Collection<PropertyType>> propertyTypesByTarget =
profileService.getTargetPropertyTypes();
List<PropertyType> propertyTypes = new ArrayList<>();
@@ -79,17 +79,7 @@ public class PropertyTypeCrudCommand extends BaseCrudCommand
{
propertyTypes.addAll(typeCollection);
}
- Integer start = query.getOffset();
- Integer size = query.getLimit();
- if (start == null) {
- start = 0;
- }
- if (size == null) {
- size = 50;
- }
- int end = Math.min(start + size, propertyTypes.size());
- List<PropertyType> pagedPropertyTypes = propertyTypes.subList(start,
end);
- return new PartialList<>(pagedPropertyTypes, start,
pagedPropertyTypes.size(), propertyTypes.size(), PartialList.Relation.EQUAL);
+ return paginateList(propertyTypes, query);
}
@Override
@@ -164,9 +154,7 @@ public class PropertyTypeCrudCommand extends
BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleCrudCommand.java
index 52def49f6..64d523926 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleCrudCommand.java
@@ -163,9 +163,7 @@ public class RuleCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleStatisticsCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleStatisticsCrudCommand.java
index 9e0c072ee..8a0507bdd 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleStatisticsCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/rules/RuleStatisticsCrudCommand.java
@@ -111,9 +111,7 @@ public class RuleStatisticsCrudCommand extends
BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scopes/ScopeCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scopes/ScopeCrudCommand.java
index bcb9f7fee..10bef1fca 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scopes/ScopeCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scopes/ScopeCrudCommand.java
@@ -133,9 +133,7 @@ public class ScopeCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scoring/ScoringCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scoring/ScoringCrudCommand.java
index 4a3a30970..78fd511dd 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scoring/ScoringCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/scoring/ScoringCrudCommand.java
@@ -118,9 +118,7 @@ public class ScoringCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/segments/SegmentCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/segments/SegmentCrudCommand.java
index 5b93b0636..85e16aecc 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/segments/SegmentCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/segments/SegmentCrudCommand.java
@@ -148,9 +148,7 @@ public class SegmentCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/sessions/SessionCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/sessions/SessionCrudCommand.java
index 2a79be13e..a185163d1 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/sessions/SessionCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/sessions/SessionCrudCommand.java
@@ -92,11 +92,6 @@ public class SessionCrudCommand extends BaseCrudCommand {
@Override
public void update(String id, Map<String, Object> properties) {
- // First check if the session exists
- if (read(id) == null) {
- return;
- }
-
Session updatedSession = OBJECT_MAPPER.convertValue(properties,
Session.class);
updatedSession.setItemId(id);
profileService.saveSession(updatedSession);
@@ -104,17 +99,12 @@ public class SessionCrudCommand extends BaseCrudCommand {
@Override
public void delete(String id) {
- // First check if the session exists
- if (read(id) != null) {
- profileService.deleteSession(id);
- }
+ profileService.deleteSession(id);
}
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/tenants/TenantCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/tenants/TenantCrudCommand.java
index c099e42a5..cd809bacf 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/tenants/TenantCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/tenants/TenantCrudCommand.java
@@ -21,8 +21,6 @@ import org.apache.karaf.shell.support.table.ShellTable;
import java.io.PrintStream;
import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.conditions.ConditionType;
import org.apache.unomi.api.query.Query;
import org.apache.unomi.api.tenants.*;
import org.apache.unomi.common.DataTable;
@@ -31,6 +29,8 @@ import org.apache.unomi.shell.dev.services.BaseCrudCommand;
import org.apache.unomi.shell.dev.services.CrudCommand;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
@@ -41,6 +41,7 @@ import java.util.stream.Collectors;
@Component(service = CrudCommand.class, immediate = true)
public class TenantCrudCommand extends BaseCrudCommand {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(TenantCrudCommand.class.getName());
private static final ObjectMapper OBJECT_MAPPER = new CustomObjectMapper();
private static final List<String> PROPERTY_NAMES = List.of(
"itemId", "name", "description", "status", "creationDate",
"lastModificationDate", "resourceQuota", "properties",
"restrictedEventPermissions", "authorizedIPs"
@@ -73,25 +74,25 @@ public class TenantCrudCommand extends BaseCrudCommand {
*/
@Override
protected DataTable buildDataTable() {
- Query query = new Query();
- query.setLimit(maxEntries);
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
- query.setSortby(getSortBy());
+ PrintStream console = getConsole();
+ try {
+ Query query = buildQuery(maxEntries);
+ PartialList<?> items = getItems(query);
+
+ printPaginationWarning(items, console);
- PartialList<?> items = getItems(query);
- if (items.getList().size() != items.getTotalSize()) {
- PrintStream console = getConsole();
- console.println("WARNING : Only the first " + items.getPageSize()
+ " items have been retrieved, there are " + items.getTotalSize() + " items
registered in total. Use the maxEntries parameter to retrieve more items");
- }
+ DataTable dataTable = new DataTable();
+ for (Object item : items.getList()) {
+ Comparable[] rowData = buildRow(item);
+ dataTable.addRow(rowData);
+ }
- DataTable dataTable = new DataTable();
- for (Object item : items.getList()) {
- Comparable[] rowData = buildRow(item);
- dataTable.addRow(rowData);
+ return dataTable;
+ } catch (Exception e) {
+ LOGGER.error("Error building data table", e);
+ console.println("Error: " + e.getMessage());
+ return new DataTable();
}
-
- return dataTable;
}
/**
@@ -99,29 +100,20 @@ public class TenantCrudCommand extends BaseCrudCommand {
*/
@Override
public void buildRows(ShellTable table, int maxEntries) {
- Query query = new Query();
- query.setLimit(maxEntries);
PrintStream console = getConsole();
- if (definitionsService == null) {
- console.println("Error: No definitions service available, unable
to build rows");
- return;
- }
- ConditionType matchAllConditionType =
definitionsService.getConditionType("matchAllCondition");
- if (matchAllConditionType == null) {
- console.println("Error: No matchAllCondition available, unable to
build rows");
- }
- Condition matchAllCondition = new Condition(matchAllConditionType);
- query.setCondition(matchAllCondition);
- query.setSortby(getSortBy());
-
- PartialList<?> items = getItems(query);
- if (items.getList().size() != items.getTotalSize()) {
- console.println("WARNING : Only the first " + items.getPageSize()
+ " items have been retrieved, there are " + items.getTotalSize() + " items
registered in total. Use the maxEntries parameter to retrieve more items");
- }
+ try {
+ Query query = buildQuery(maxEntries);
+ PartialList<?> items = getItems(query);
+
+ printPaginationWarning(items, console);
- for (Object item : items.getList()) {
- Comparable[] rowData = buildRow(item);
- table.addRow().addContent(rowData);
+ for (Object item : items.getList()) {
+ Comparable[] rowData = buildRow(item);
+ table.addRow().addContent(rowData);
+ }
+ } catch (Exception e) {
+ console.println("Error: " + e.getMessage());
+ LOGGER.error("Error building rows", e);
}
}
@@ -247,9 +239,7 @@ public class TenantCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
@Override
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/topics/TopicCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/topics/TopicCrudCommand.java
index fda6e6b5b..f97bed28d 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/topics/TopicCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/commands/topics/TopicCrudCommand.java
@@ -115,8 +115,6 @@ public class TopicCrudCommand extends BaseCrudCommand {
@Override
public List<String> completePropertyNames(String prefix) {
- return PROPERTY_NAMES.stream()
- .filter(name -> name.startsWith(prefix))
- .collect(Collectors.toList());
+ return filterPropertyNames(PROPERTY_NAMES, prefix);
}
}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/CampaignCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/CampaignCompleter.java
deleted file mode 100644
index 3b65ea1bb..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/CampaignCompleter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.campaigns.Campaign;
-
-/**
- * Completer for Campaign IDs
- */
-@Service
-public class CampaignCompleter extends BaseCompleter<Campaign> {
-
- @Override
- protected Class<Campaign> getItemType() {
- return Campaign.class;
- }
-
- @Override
- protected String getSortBy() {
- return "metadata.name";
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/EventTypeCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/EventTypeCompleter.java
deleted file mode 100644
index 086238ef0..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/EventTypeCompleter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-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.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.services.EventService;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-@Service
-public class EventTypeCompleter implements Completer {
-
- @Reference
- private EventService eventService;
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- // Add common event types
- Set<String> eventTypes = new HashSet<>();
- eventTypes.add("view");
- eventTypes.add("login");
- eventTypes.add("sessionCreated");
- eventTypes.add("profileUpdated");
- eventTypes.add("sessionReassigned");
- eventTypes.add("updateProperties");
- eventTypes.add("formSubmitted");
- eventTypes.add("click");
- eventTypes.add("download");
- eventTypes.add("search");
- eventTypes.add("videoStarted");
- eventTypes.add("videoCompleted");
-
- // Add event types to completer
- for (String eventType : eventTypes) {
- delegate.getStrings().add(eventType);
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/GoalCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/GoalCompleter.java
deleted file mode 100644
index 145946081..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/GoalCompleter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.goals.Goal;
-
-/**
- * Completer for Goal IDs
- */
-@Service
-public class GoalCompleter extends BaseCompleter<Goal> {
-
- @Override
- protected Class<Goal> getItemType() {
- return Goal.class;
- }
-
- @Override
- protected String getSortBy() {
- return "metadata.name";
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IPAddressCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IPAddressCompleter.java
deleted file mode 100644
index bd16c5d45..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IPAddressCompleter.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-@Service
-public class IPAddressCompleter implements Completer {
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- // Add common IP addresses and ranges
- Set<String> ipAddresses = new HashSet<>();
- ipAddresses.add("127.0.0.1");
- ipAddresses.add("localhost");
- ipAddresses.add("0.0.0.0");
- ipAddresses.add("::1");
- ipAddresses.add("192.168.0.0/16");
- ipAddresses.add("10.0.0.0/8");
- ipAddresses.add("172.16.0.0/12");
- ipAddresses.add("fc00::/7");
-
- // Add IP addresses to completer
- for (String ip : ipAddresses) {
- delegate.getStrings().add(ip);
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IdCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IdCompleter.java
index 1790f9267..71f6df412 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IdCompleter.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/IdCompleter.java
@@ -46,15 +46,16 @@ public class IdCompleter implements Completer {
@Override
public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- // Get the operation and type from the command line (index 0 =
operation, index 1 = type)
+ // Get the operation and type from the command line
+ // args[0] = "crud" (command name), args[1] = operation, args[2] =
type, args[3+] = remaining
String operation = null;
String type = null;
String[] args = commandLine.getArguments();
- if (args.length > 0) {
- operation = args[0];
- }
if (args.length > 1) {
- type = args[1];
+ operation = args[1];
+ }
+ if (args.length > 2) {
+ type = args[2];
}
if (type == null) {
return -1;
@@ -70,13 +71,26 @@ public class IdCompleter implements Completer {
}
}
- // For update operation, check if we're completing the first argument
(ID) or second (JSON)
- // remaining[0] = ID, remaining[1] = JSON
- // If args.length > 2, we're completing remaining[1] (JSON), so don't
complete IDs
- if (operation != null && "update".equals(operation.toLowerCase()) &&
args.length > 2) {
+ // Determine which argument we're completing based on args.length
+ // args[0] = "crud" (command name)
+ // args[1] = operation
+ // args[2] = type
+ // args[3+] = remaining (multi-valued)
+ // For read/delete: remaining[0] = ID (complete when args.length == 3,
i.e., we're at remaining[0])
+ // For update: remaining[0] = ID, remaining[1] = JSON
+ // - Complete IDs when args.length == 3 (completing remaining[0],
which is the ID)
+ // - Don't complete IDs when args.length >= 4 (completing
remaining[1], which is JSON)
+
+ // For update operation, if args.length >= 4, we're past the ID
argument
+ // and are completing the JSON part, so don't complete IDs
+ if (operation != null && "update".equals(operation.toLowerCase()) &&
args.length >= 4) {
// We're past the ID argument, so we're completing JSON - don't
complete IDs
return -1;
}
+
+ // For read/delete/update with args.length == 3, we're completing the
ID (remaining[0])
+ // The completer is attached to the "remaining" argument, so it will
be called
+ // when we're at that position
// Find the CrudCommand for this type
try {
@@ -88,21 +102,7 @@ public class IdCompleter implements Completer {
if (cmd.getObjectType().equals(type)) {
// Get the prefix from what the user has typed so
far
// StringsCompleter will handle the final
matching, but we need prefix for server-side filtering
- String prefix = "";
- String buffer = commandLine.getBuffer();
-
- if (buffer != null && !buffer.trim().isEmpty()) {
- // Get the last word from the buffer (the
current value being typed)
- String trimmed = buffer.trim();
- int lastSpace = trimmed.lastIndexOf(' ');
- if (lastSpace >= 0 && lastSpace <
trimmed.length() - 1) {
- prefix = trimmed.substring(lastSpace + 1);
- // Skip if it looks like an option
- if (prefix.startsWith("-")) {
- prefix = "";
- }
- }
- }
+ String prefix =
extractPrefixFromBuffer(commandLine);
List<String> completions = cmd.completeId(prefix);
@@ -124,4 +124,33 @@ public class IdCompleter implements Completer {
return -1;
}
+
+ /**
+ * Extract the prefix from the command line buffer for completion.
+ * This extracts the last word being typed, skipping options that start
with '-'.
+ *
+ * @param commandLine the command line
+ * @return the prefix to use for filtering completions, or empty string if
none
+ */
+ private String extractPrefixFromBuffer(CommandLine commandLine) {
+ String buffer = commandLine.getBuffer();
+ if (buffer == null || buffer.trim().isEmpty()) {
+ return "";
+ }
+
+ // Get the last word from the buffer (the current value being typed)
+ String trimmed = buffer.trim();
+ int lastSpace = trimmed.lastIndexOf(' ');
+ if (lastSpace < 0 || lastSpace >= trimmed.length() - 1) {
+ return "";
+ }
+
+ String prefix = trimmed.substring(lastSpace + 1);
+ // Skip if it looks like an option
+ if (prefix.startsWith("-")) {
+ return "";
+ }
+
+ return prefix;
+ }
}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ProfileCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ProfileCompleter.java
deleted file mode 100644
index 60cd251d1..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ProfileCompleter.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-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.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.Profile;
-import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.query.Query;
-import org.apache.unomi.api.services.DefinitionsService;
-import org.apache.unomi.api.services.ProfileService;
-
-import java.util.List;
-
-@Service
-public class ProfileCompleter implements Completer {
-
- private static final int DEFAULT_LIMIT = 50;
-
- @Reference
- private ProfileService profileService;
-
- @Reference
- private DefinitionsService definitionsService;
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- try {
- // Create query matching the profile-list command
- Query query = new Query();
-
query.setSortby("systemProperties.lastUpdated:desc,properties.lastVisit:desc");
- query.setLimit(DEFAULT_LIMIT);
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
-
- // Get the latest profiles
- PartialList<Profile> profiles = profileService.search(query,
Profile.class);
-
- // Add profile IDs to completer
- for (Profile profile : profiles.getList()) {
- delegate.getStrings().add(profile.getItemId());
- }
- } catch (Exception e) {
- // Log error or handle exception
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/RuleCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/RuleCompleter.java
deleted file mode 100644
index b30da0d0c..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/RuleCompleter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-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.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.query.Query;
-import org.apache.unomi.api.services.DefinitionsService;
-import org.apache.unomi.api.services.RulesService;
-
-import java.util.List;
-
-@Service
-public class RuleCompleter implements Completer {
-
- private static final int DEFAULT_LIMIT = 50;
-
- @Reference
- private RulesService rulesService;
-
- @Reference
- private DefinitionsService definitionsService;
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- try {
- // Create query matching the rule-list command
- Query query = new Query();
- query.setLimit(DEFAULT_LIMIT);
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
-
- // Get all rules
- PartialList<Metadata> rules = rulesService.getRuleMetadatas(query);
-
- // Add rule IDs to completer
- for (Metadata rule : rules.getList()) {
- delegate.getStrings().add(rule.getId());
- }
- } catch (Exception e) {
- // Log error or handle exception
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScopeCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScopeCompleter.java
deleted file mode 100644
index 391763399..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScopeCompleter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.Scope;
-
-/**
- * Completer for Scope IDs
- */
-@Service
-public class ScopeCompleter extends BaseCompleter<Scope> {
-
- @Override
- protected Class<Scope> getItemType() {
- return Scope.class;
- }
-
- @Override
- protected String getSortBy() {
- return "metadata.name";
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScoringCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScoringCompleter.java
deleted file mode 100644
index 7d9d310f2..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/ScoringCompleter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.unomi.api.segments.Scoring;
-
-/**
- * Completer for Scoring IDs
- */
-@Service
-public class ScoringCompleter extends BaseCompleter<Scoring> {
-
- @Override
- protected Class<Scoring> getItemType() {
- return Scoring.class;
- }
-
- @Override
- protected String getSortBy() {
- return "metadata.name";
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SegmentCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SegmentCompleter.java
deleted file mode 100644
index e5a47988c..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SegmentCompleter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.services.SegmentService;
-import org.osgi.service.component.annotations.Reference;
-
-@Service
-public class SegmentCompleter implements Completer {
-
- private static final int DEFAULT_LIMIT = 50;
-
- private SegmentService segmentService;
-
- @Reference
- public void setSegmentService(SegmentService segmentService) {
- this.segmentService = segmentService;
- }
-
- @Override
- public int complete(Session session, CommandLine commandLine,
java.util.List<String> candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- try {
- // Get segments sorted by name
- PartialList<Metadata> segments =
segmentService.getSegmentMetadatas(0, DEFAULT_LIMIT, "name:asc");
- for (Metadata segment : segments.getList()) {
- delegate.getStrings().add(segment.getId());
- }
- } catch (Exception e) {
- // Log error or handle exception
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SessionCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SessionCompleter.java
deleted file mode 100644
index ffa218b3d..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/SessionCompleter.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-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.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.PartialList;
-import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.query.Query;
-import org.apache.unomi.api.services.DefinitionsService;
-import org.apache.unomi.api.services.ProfileService;
-
-import java.io.PrintStream;
-import java.util.List;
-
-@Service
-public class SessionCompleter implements Completer {
-
- private static final int DEFAULT_LIMIT = 50;
-
- @Reference
- private ProfileService profileService;
-
- @Reference
- private DefinitionsService definitionsService;
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- try {
- // Create query matching the session-list command
- Query query = new Query();
- query.setSortby("lastEventDate:desc");
- query.setLimit(DEFAULT_LIMIT);
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
-
- // Get the latest sessions
- PartialList<org.apache.unomi.api.Session> sessions =
profileService.searchSessions(query);
-
- // Add session IDs to completer
- for (org.apache.unomi.api.Session s : sessions.getList()) {
- delegate.getStrings().add(s.getItemId());
- }
- } catch (Exception e) {
- // Note: Printing during completion can interfere with completion,
but using console for consistency
- PrintStream console = session.getConsole();
- console.println("Error: Error getting sessions: " +
e.getMessage());
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/TenantStatusCompleter.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/TenantStatusCompleter.java
deleted file mode 100644
index a63f73bb5..000000000
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/completers/TenantStatusCompleter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.unomi.shell.dev.completers;
-
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.api.console.CommandLine;
-import org.apache.karaf.shell.api.console.Completer;
-import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.support.completers.StringsCompleter;
-import org.apache.unomi.api.tenants.TenantStatus;
-
-import java.util.List;
-
-@Service
-public class TenantStatusCompleter implements Completer {
-
- @Override
- public int complete(Session session, CommandLine commandLine, List<String>
candidates) {
- StringsCompleter delegate = new StringsCompleter();
-
- // Add all tenant status values
- for (TenantStatus status : TenantStatus.values()) {
- delegate.getStrings().add(status.name());
- }
-
- return delegate.complete(session, commandLine, candidates);
- }
-}
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/BaseCrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/BaseCrudCommand.java
index 997e17ef6..4260a6086 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/BaseCrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/BaseCrudCommand.java
@@ -16,6 +16,8 @@
*/
package org.apache.unomi.shell.dev.services;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.support.table.ShellTable;
@@ -39,6 +41,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Base class for CRUD command implementations that provides common
functionality
@@ -59,34 +62,25 @@ public abstract class BaseCrudCommand extends
ListCommandSupport implements Crud
@Override
protected DataTable buildDataTable() {
- Query query = new Query();
- query.setLimit(maxEntries);
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
- query.setSortby(getSortBy());
-
- PartialList<?> items = getItems(query);
- if (items.getList().size() != items.getTotalSize()) {
- PrintStream console = getConsole();
- console.println("WARNING : Only the first " + items.getPageSize()
+ " items have been retrieved, there are " + items.getTotalSize() + " items
registered in total. Use the maxEntries parameter to retrieve more items");
- }
-
- DataTable dataTable = new DataTable();
- for (Object item : items.getList()) {
- Comparable[] rowData = buildRow(item);
-
- // Get tenant ID from the item if possible
- String tenantId = getTenantIdFromItem(item);
+ PrintStream console = getConsole();
+ try {
+ Query query = buildQuery(maxEntries);
+ PartialList<?> items = getItems(query);
+
+ printPaginationWarning(items, console);
- // Create a new array with tenantId as the first element
- Comparable[] rowWithTenant = new Comparable[rowData.length + 1];
- rowWithTenant[0] = tenantId;
- System.arraycopy(rowData, 0, rowWithTenant, 1, rowData.length);
+ DataTable dataTable = new DataTable();
+ for (Object item : items.getList()) {
+ Comparable[] rowWithTenant = buildRowWithTenant(item);
+ dataTable.addRow(rowWithTenant);
+ }
- dataTable.addRow(rowWithTenant);
+ return dataTable;
+ } catch (Exception e) {
+ LOGGER.error("Error building data table", e);
+ console.println("Error: " + e.getMessage());
+ return new DataTable();
}
-
- return dataTable;
}
/**
@@ -147,43 +141,118 @@ public abstract class BaseCrudCommand extends
ListCommandSupport implements Crud
*/
protected abstract String[] getHeadersWithoutTenant();
- @Override
- public void buildRows(ShellTable table, int maxEntries) {
+ /**
+ * Build a query with matchAllCondition and sort criteria.
+ * This is a common helper method used by buildDataTable(), buildRows(),
buildCsvOutput(), and completeId().
+ *
+ * @param limit maximum number of entries
+ * @return the configured query
+ * @throws Exception if definitions service is not available or
matchAllCondition cannot be found
+ */
+ protected Query buildQuery(int limit) throws Exception {
Query query = new Query();
- query.setLimit(maxEntries);
- PrintStream console = getConsole();
+ query.setLimit(limit);
+
if (definitionsService == null) {
- console.println("Error: No definitions service available, unable
to build rows");
- LOGGER.error("Definition service is not available, unable to build
rows");
- return;
+ throw new Exception("Definitions service is not available");
}
+
ConditionType matchAllConditionType =
definitionsService.getConditionType("matchAllCondition");
if (matchAllConditionType == null) {
- console.println("Error: No matchAllCondition available, unable to
build rows");
- LOGGER.error("No matchAllCondition available, unable to build
rows");
+ throw new Exception("No matchAllCondition available");
}
+
Condition matchAllCondition = new Condition(matchAllConditionType);
query.setCondition(matchAllCondition);
query.setSortby(getSortBy());
+
+ return query;
+ }
- PartialList<?> items = getItems(query);
+ /**
+ * Build a row array with tenant ID prepended as the first element.
+ * This is a common helper method used by buildDataTable(), buildRows(),
and buildCsvOutput().
+ *
+ * @param item the item to build a row from
+ * @return array with tenant ID as first element, followed by row data
+ */
+ protected Comparable[] buildRowWithTenant(Object item) {
+ Comparable[] rowData = buildRow(item);
+ String tenantId = getTenantIdFromItem(item);
+
+ // Create a new array with tenantId as the first element
+ Comparable[] rowWithTenant = new Comparable[rowData.length + 1];
+ rowWithTenant[0] = tenantId;
+ System.arraycopy(rowData, 0, rowWithTenant, 1, rowData.length);
+
+ return rowWithTenant;
+ }
+
+ /**
+ * Print pagination warning if not all items were retrieved.
+ * This is a common helper method used by buildDataTable() and buildRows().
+ *
+ * @param items the partial list of items
+ * @param console console for output
+ */
+ protected void printPaginationWarning(PartialList<?> items, PrintStream
console) {
if (items.getList().size() != items.getTotalSize()) {
console.println("WARNING : Only the first " + items.getPageSize()
+ " items have been retrieved, there are " + items.getTotalSize() + " items
registered in total. Use the maxEntries parameter to retrieve more items");
}
+ }
- for (Object item : items.getList()) {
- Comparable[] rowData = buildRow(item);
-
- // Get tenant ID from the item if possible
- String tenantId = getTenantIdFromItem(item);
+ @Override
+ public void buildRows(ShellTable table, int maxEntries) {
+ PrintStream console = getConsole();
+ try {
+ Query query = buildQuery(maxEntries);
+ PartialList<?> items = getItems(query);
+
+ printPaginationWarning(items, console);
- // Create a new array with tenantId as the first element
- Comparable[] rowWithTenant = new Comparable[rowData.length + 1];
- rowWithTenant[0] = tenantId;
- System.arraycopy(rowData, 0, rowWithTenant, 1, rowData.length);
+ for (Object item : items.getList()) {
+ Comparable[] rowWithTenant = buildRowWithTenant(item);
+ table.addRow().addContent(rowWithTenant);
+ }
+ } catch (Exception e) {
+ console.println("Error: " + e.getMessage());
+ LOGGER.error("Error building rows", e);
+ }
+ }
- table.addRow().addContent(rowWithTenant);
+ /**
+ * Generate CSV output directly using commons-csv API.
+ * This method uses the same logic as buildRows() but outputs as CSV.
+ *
+ * @param console console for output
+ * @param headers column headers
+ * @param limit maximum number of entries
+ * @throws Exception if generation fails
+ */
+ public void buildCsvOutput(PrintStream console, String[] headers, int
limit) throws Exception {
+ Query query = buildQuery(limit);
+ PartialList<?> items = getItems(query);
+
+ // Generate CSV directly using commons-csv
+ CSVFormat csvFormat = CSVFormat.DEFAULT;
+ CSVPrinter printer = csvFormat.print(console);
+
+ // Print header
+ printer.printRecord((Object[]) headers);
+
+ // Print data rows
+ for (Object item : items.getList()) {
+ Comparable[] rowWithTenant = buildRowWithTenant(item);
+
+ // Convert to List<String> for CSV printer
+ List<String> row = new ArrayList<>();
+ for (Comparable<?> cell : rowWithTenant) {
+ row.add(cell != null ? cell.toString() : "");
+ }
+ printer.printRecord(row.toArray());
}
+
+ printer.close();
}
/**
@@ -217,19 +286,9 @@ public abstract class BaseCrudCommand extends
ListCommandSupport implements Crud
*/
@Override
public List<String> completeId(String prefix) {
- // Create a query with increased limit to provide more completions
- Query query = new Query();
- query.setLimit(50); // Higher limit for completions
-
- if (definitionsService == null) {
- LOGGER.error("Definition service is not available, unable to
complete IDs");
- return List.of();
- }
-
try {
- Condition matchAllCondition = new
Condition(definitionsService.getConditionType("matchAllCondition"));
- query.setCondition(matchAllCondition);
- query.setSortby(getSortBy());
+ // Create a query with increased limit to provide more completions
+ Query query = buildQuery(50); // Higher limit for completions
// Get items using the appropriate service method
PartialList<?> items = getItems(query);
@@ -264,6 +323,39 @@ public abstract class BaseCrudCommand extends
ListCommandSupport implements Crud
return System.out;
}
+ /**
+ * Apply pagination to a list of items based on query parameters.
+ * This is a helper method for implementations that need to paginate
in-memory lists.
+ *
+ * @param items the full list of items
+ * @param query the query with offset and limit parameters
+ * @param <T> the type of items in the list
+ * @return a PartialList with paginated results
+ */
+ protected <T> PartialList<T> paginateList(List<T> items, Query query) {
+ Integer offset = query.getOffset();
+ Integer limit = query.getLimit();
+ int start = offset == null ? 0 : offset;
+ int size = limit == null ? items.size() : limit;
+ int end = Math.min(start + size, items.size());
+
+ List<T> pagedItems = items.subList(start, end);
+ return new PartialList<>(pagedItems, start, pagedItems.size(),
items.size(), PartialList.Relation.EQUAL);
+ }
+
+ /**
+ * Filter property names by prefix. This is a helper method for
completePropertyNames implementations.
+ *
+ * @param propertyNames the list of property names to filter
+ * @param prefix the prefix to filter by
+ * @return filtered list of property names
+ */
+ protected List<String> filterPropertyNames(List<String> propertyNames,
String prefix) {
+ return propertyNames.stream()
+ .filter(name -> name.startsWith(prefix))
+ .collect(Collectors.toList());
+ }
+
/**
* Extract the ID from an item. This method attempts to extract the ID
using common patterns.
* Subclasses can override this method to provide specialized ID
extraction for specific item types.
diff --git
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/CrudCommand.java
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/CrudCommand.java
index a9ed548b6..4c088e906 100644
---
a/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/CrudCommand.java
+++
b/tools/shell-dev-commands/src/main/java/org/apache/unomi/shell/dev/services/CrudCommand.java
@@ -18,6 +18,7 @@ package org.apache.unomi.shell.dev.services;
import org.apache.karaf.shell.support.table.ShellTable;
+import java.io.PrintStream;
import java.util.List;
import java.util.Map;
@@ -191,4 +192,15 @@ public interface CrudCommand {
* @param maxEntries maximum number of entries to include
*/
void buildRows(ShellTable table, int maxEntries);
+
+ /**
+ * Generate CSV output directly using commons-csv API.
+ * This method uses the same logic as buildRows() but outputs as CSV.
+ *
+ * @param console console for output
+ * @param headers column headers
+ * @param limit maximum number of entries
+ * @throws Exception if generation fails
+ */
+ void buildCsvOutput(PrintStream console, String[] headers, int limit)
throws Exception;
}