]> git.basschouten.com Git - openhab-addons.git/blob
0bcab36a2ac49fbdb4e3648524ca510196974552
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.persistence.jdbc.console;
14
15 import java.util.Arrays;
16 import java.util.Comparator;
17 import java.util.List;
18 import java.util.stream.Stream;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.core.io.console.Console;
23 import org.openhab.core.io.console.ConsoleCommandCompleter;
24 import org.openhab.core.io.console.StringsCompleter;
25 import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
26 import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
27 import org.openhab.core.persistence.PersistenceService;
28 import org.openhab.core.persistence.PersistenceServiceRegistry;
29 import org.openhab.persistence.jdbc.ItemTableCheckEntry;
30 import org.openhab.persistence.jdbc.ItemTableCheckEntryStatus;
31 import org.openhab.persistence.jdbc.internal.JdbcPersistenceService;
32 import org.openhab.persistence.jdbc.internal.JdbcPersistenceServiceConstants;
33 import org.osgi.service.component.annotations.Activate;
34 import org.osgi.service.component.annotations.Component;
35 import org.osgi.service.component.annotations.Reference;
36
37 /**
38  * The {@link JdbcCommandExtension} is responsible for handling console commands
39  *
40  * @author Jacob Laursen - Initial contribution
41  */
42 @NonNullByDefault
43 @Component(service = ConsoleCommandExtension.class)
44 public class JdbcCommandExtension extends AbstractConsoleCommandExtension implements ConsoleCommandCompleter {
45
46     private static final String CMD_TABLES = "tables";
47     private static final String SUBCMD_TABLES_LIST = "list";
48     private static final String SUBCMD_TABLES_CLEAN = "clean";
49     private static final String PARAMETER_ALL = "all";
50     private static final String PARAMETER_FORCE = "force";
51     private static final StringsCompleter CMD_COMPLETER = new StringsCompleter(List.of(CMD_TABLES), false);
52     private static final StringsCompleter SUBCMD_TABLES_COMPLETER = new StringsCompleter(
53             List.of(SUBCMD_TABLES_LIST, SUBCMD_TABLES_CLEAN), false);
54
55     private final PersistenceServiceRegistry persistenceServiceRegistry;
56
57     @Activate
58     public JdbcCommandExtension(final @Reference PersistenceServiceRegistry persistenceServiceRegistry) {
59         super(JdbcPersistenceServiceConstants.SERVICE_ID, "Interact with the JDBC persistence service.");
60         this.persistenceServiceRegistry = persistenceServiceRegistry;
61     }
62
63     @Override
64     public void execute(String[] args, Console console) {
65         if (args.length < 2 || args.length > 4 || !CMD_TABLES.equals(args[0])) {
66             printUsage(console);
67             return;
68         }
69         JdbcPersistenceService persistenceService = getPersistenceService();
70         if (persistenceService == null) {
71             return;
72         }
73         if (SUBCMD_TABLES_LIST.equalsIgnoreCase(args[1])) {
74             listTables(persistenceService, console, args.length == 3 && PARAMETER_ALL.equalsIgnoreCase(args[2]));
75             return;
76         } else if (SUBCMD_TABLES_CLEAN.equalsIgnoreCase(args[1])) {
77             if (args.length == 3) {
78                 cleanupItem(persistenceService, console, args[2], false);
79                 return;
80             } else if (args.length == 4 && PARAMETER_FORCE.equalsIgnoreCase(args[3])) {
81                 cleanupItem(persistenceService, console, args[2], true);
82                 return;
83             } else {
84                 cleanupTables(persistenceService, console);
85                 return;
86             }
87         }
88         printUsage(console);
89     }
90
91     private @Nullable JdbcPersistenceService getPersistenceService() {
92         for (PersistenceService persistenceService : persistenceServiceRegistry.getAll()) {
93             if (persistenceService instanceof JdbcPersistenceService) {
94                 return (JdbcPersistenceService) persistenceService;
95             }
96         }
97         return null;
98     }
99
100     private void listTables(JdbcPersistenceService persistenceService, Console console, Boolean all) {
101         List<ItemTableCheckEntry> entries = persistenceService.getCheckedEntries();
102         if (!all) {
103             entries.removeIf(t -> t.getStatus() == ItemTableCheckEntryStatus.VALID);
104         }
105         entries.sort(Comparator.comparing(ItemTableCheckEntry::getTableName));
106         int itemNameMaxLength = Math
107                 .max(entries.stream().map(t -> t.getItemName().length()).max(Integer::compare).get(), 4);
108         int tableNameMaxLength = Math
109                 .max(entries.stream().map(t -> t.getTableName().length()).max(Integer::compare).get(), 5);
110         int statusMaxLength = Stream.of(ItemTableCheckEntryStatus.values()).map(t -> t.toString().length())
111                 .max(Integer::compare).get();
112         console.println(String.format(
113                 "%1$-" + (tableNameMaxLength + 2) + "sRow Count  %2$-" + (itemNameMaxLength + 2) + "s%3$s", "Table",
114                 "Item", "Status"));
115         console.println("-".repeat(tableNameMaxLength) + "  " + "---------  " + "-".repeat(itemNameMaxLength) + "  "
116                 + "-".repeat(statusMaxLength));
117         for (ItemTableCheckEntry entry : entries) {
118             String tableName = entry.getTableName();
119             ItemTableCheckEntryStatus status = entry.getStatus();
120             long rowCount = status == ItemTableCheckEntryStatus.VALID
121                     || status == ItemTableCheckEntryStatus.ITEM_MISSING ? persistenceService.getRowCount(tableName) : 0;
122             console.println(String.format(
123                     "%1$-" + (tableNameMaxLength + 2) + "s%2$9d  %3$-" + (itemNameMaxLength + 2) + "s%4$s", tableName,
124                     rowCount, entry.getItemName(), status));
125         }
126     }
127
128     private void cleanupTables(JdbcPersistenceService persistenceService, Console console) {
129         console.println("Cleaning up all inconsistent items...");
130         List<ItemTableCheckEntry> entries = persistenceService.getCheckedEntries();
131         entries.removeIf(t -> t.getStatus() == ItemTableCheckEntryStatus.VALID || t.getItemName().isEmpty());
132         for (ItemTableCheckEntry entry : entries) {
133             console.print(entry.getItemName() + " -> ");
134             if (persistenceService.cleanupItem(entry)) {
135                 console.println("done.");
136             } else {
137                 console.println("skipped/failed.");
138             }
139         }
140     }
141
142     private void cleanupItem(JdbcPersistenceService persistenceService, Console console, String itemName,
143             boolean force) {
144         console.print("Cleaning up item " + itemName + "... ");
145         if (persistenceService.cleanupItem(itemName, force)) {
146             console.println("done.");
147         } else {
148             console.println("skipped/failed.");
149         }
150     }
151
152     @Override
153     public List<String> getUsages() {
154         return Arrays.asList(
155                 buildCommandUsage(CMD_TABLES + " " + SUBCMD_TABLES_LIST + " [" + PARAMETER_ALL + "]",
156                         "list tables (all = include valid)"),
157                 buildCommandUsage(
158                         CMD_TABLES + " " + SUBCMD_TABLES_CLEAN + " [<itemName>]" + " [" + PARAMETER_FORCE + "]",
159                         "clean inconsistent items (remove from index and drop tables)"));
160     }
161
162     @Override
163     public @Nullable ConsoleCommandCompleter getCompleter() {
164         return this;
165     }
166
167     @Override
168     public boolean complete(String[] args, int cursorArgumentIndex, int cursorPosition, List<String> candidates) {
169         if (cursorArgumentIndex <= 0) {
170             return CMD_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
171         } else if (cursorArgumentIndex == 1) {
172             if (CMD_TABLES.equalsIgnoreCase(args[0])) {
173                 return SUBCMD_TABLES_COMPLETER.complete(args, cursorArgumentIndex, cursorPosition, candidates);
174             }
175         } else if (cursorArgumentIndex == 2) {
176             if (CMD_TABLES.equalsIgnoreCase(args[0])) {
177                 if (SUBCMD_TABLES_CLEAN.equalsIgnoreCase(args[1])) {
178                     JdbcPersistenceService persistenceService = getPersistenceService();
179                     if (persistenceService != null) {
180                         return new StringsCompleter(persistenceService.getItemNames(), true).complete(args,
181                                 cursorArgumentIndex, cursorPosition, candidates);
182                     }
183                 } else if (SUBCMD_TABLES_LIST.equalsIgnoreCase(args[1])) {
184                     new StringsCompleter(List.of(PARAMETER_ALL), false).complete(args, cursorArgumentIndex,
185                             cursorPosition, candidates);
186                 }
187             }
188         }
189         return false;
190     }
191 }