1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.frontend.cli;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.PrintWriter;
28 import java.net.URL;
29 import java.net.URLClassLoader;
30 import java.nio.charset.Charset;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.Files;
33 import java.nio.file.Paths;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Vector;
38 import java.util.concurrent.atomic.AtomicInteger;
39 import java.util.stream.Stream;
40
41 import org.apache.commons.text.StringSubstitutor;
42 import org.apache.logging.log4j.LogManager;
43 import org.apache.logging.log4j.Logger;
44 import org.jdom2.Element;
45 import org.mycore.common.MCRClassTools;
46 import org.mycore.common.MCRSession;
47 import org.mycore.common.MCRSessionMgr;
48 import org.mycore.common.MCRSystemUserInformation;
49 import org.mycore.common.MCRTransactionHelper;
50 import org.mycore.common.config.MCRConfiguration2;
51 import org.mycore.common.content.MCRJDOMContent;
52 import org.mycore.common.events.MCRStartupHandler;
53 import org.mycore.common.xml.MCRURIResolver;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class MCRCommandLineInterface {
72
73 private static final Logger LOGGER = LogManager.getLogger();
74
75
76 private static String system = null;
77
78
79 protected static Vector<String> commandQueue = new Vector<>();
80
81 protected static Vector<String> failedCommands = new Vector<>();
82
83 private static boolean interactiveMode = true;
84
85 private static boolean SKIP_FAILED_COMMAND = false;
86
87 private static MCRCommandManager knownCommands;
88
89 private static ThreadLocal<String> sessionId = new ThreadLocal<>();
90
91
92
93
94
95 public static void main(String[] args) {
96 if (!(MCRCommandLineInterface.class.getClassLoader() instanceof URLClassLoader)) {
97 System.out.println("Current ClassLoader is not extendable at runtime. Using workaround.");
98 Thread.currentThread().setContextClassLoader(new CLIURLClassLoader(new URL[0]));
99 }
100 MCRStartupHandler.startUp(null);
101 system = MCRConfiguration2.getStringOrThrow("MCR.CommandLineInterface.SystemName") + ":";
102
103 initSession();
104
105 MCRSession session = MCRSessionMgr.getSession(sessionId.get());
106 MCRSessionMgr.setCurrentSession(session);
107
108 try {
109 output("");
110 output("Command Line Interface.");
111 output("");
112
113 output("Initializing...");
114 knownCommands = new MCRCommandManager();
115 output("Initialization done.");
116
117 output("Type 'help' to list all commands!");
118 output("");
119 } finally {
120 MCRSessionMgr.releaseCurrentSession();
121 }
122
123 readCommandFromArguments(args);
124
125 String command = null;
126
127 MCRCommandPrompt prompt = new MCRCommandPrompt(system);
128 while (true) {
129 if (commandQueue.isEmpty()) {
130 if (interactiveMode) {
131 command = prompt.readCommand();
132 } else if (MCRConfiguration2.getString("MCR.CommandLineInterface.unitTest").orElse("false")
133 .equals("true")) {
134 break;
135 } else {
136 exit();
137 }
138 } else {
139 command = commandQueue.firstElement();
140 commandQueue.removeElementAt(0);
141 System.out.println(system + "> " + command);
142 }
143
144 processCommand(command);
145 }
146 }
147
148 private static void readCommandFromArguments(String[] args) {
149 if (args.length > 0) {
150 interactiveMode = false;
151
152 String line = readLineFromArguments(args);
153 addCommands(line);
154 }
155 }
156
157 private static void addCommands(String line) {
158 Stream.of(line.split(";;"))
159 .map(String::trim)
160 .filter(s -> !s.isEmpty())
161 .forEachOrdered(commandQueue::add);
162 }
163
164 private static String readLineFromArguments(String[] args) {
165 StringBuilder sb = new StringBuilder();
166 for (String arg : args) {
167 sb.append(arg).append(" ");
168 }
169 return sb.toString();
170 }
171
172 private static void initSession() {
173 MCRSessionMgr.unlock();
174 MCRSession session = MCRSessionMgr.getCurrentSession();
175 session.setCurrentIP("127.0.0.1");
176 session.setUserInformation(MCRSystemUserInformation.getSuperUserInstance());
177 MCRSessionMgr.setCurrentSession(session);
178 sessionId.set(session.getID());
179 MCRSessionMgr.releaseCurrentSession();
180 }
181
182
183
184
185
186
187
188
189 protected static void processCommand(String command) {
190
191 MCRSession session = MCRSessionMgr.getSession(sessionId.get());
192 MCRSessionMgr.setCurrentSession(session);
193
194 try {
195 MCRTransactionHelper.beginTransaction();
196 List<String> commandsReturned = knownCommands.invokeCommand(expandCommand(command));
197 MCRTransactionHelper.commitTransaction();
198 addCommandsToQueue(commandsReturned);
199 } catch (Exception ex) {
200 MCRCLIExceptionHandler.handleException(ex);
201 rollbackTransaction(session);
202 if (SKIP_FAILED_COMMAND) {
203 saveFailedCommand(command);
204 } else {
205 saveQueue(command);
206 if (!interactiveMode) {
207 System.exit(1);
208 }
209 commandQueue.clear();
210 }
211 } finally {
212 MCRSessionMgr.releaseCurrentSession();
213 }
214 }
215
216
217
218
219
220
221
222
223
224 public static String expandCommand(final String command) {
225 StringSubstitutor strSubstitutor = new StringSubstitutor(MCRConfiguration2.getPropertiesMap());
226 String expandedCommand = strSubstitutor.replace(command);
227 if (!expandedCommand.equals(command)) {
228 LOGGER.info("{} --> {}", command, expandedCommand);
229 }
230 return expandedCommand;
231 }
232
233 private static void rollbackTransaction(MCRSession session) {
234 output("Command failed. Performing transaction rollback...");
235
236 if (MCRTransactionHelper.isTransactionActive()) {
237 try {
238 MCRTransactionHelper.rollbackTransaction();
239 } catch (Exception ex2) {
240 MCRCLIExceptionHandler.handleException(ex2);
241 }
242 }
243 }
244
245 private static void addCommandsToQueue(List<String> commandsReturned) {
246 if (commandsReturned.size() > 0) {
247 output("Queueing " + commandsReturned.size() + " commands to process");
248
249 for (int i = 0; i < commandsReturned.size(); i++) {
250 commandQueue.insertElementAt(commandsReturned.get(i), i);
251 }
252 }
253 }
254
255 protected static void saveQueue(String lastCommand) {
256 output("");
257 output("The following command failed:");
258 output(lastCommand);
259 if (!commandQueue.isEmpty()) {
260 System.out.printf(Locale.ROOT, "%s There are %s other commands still unprocessed.%n", system,
261 commandQueue.size());
262 } else if (interactiveMode) {
263 return;
264 }
265 commandQueue.add(0, lastCommand);
266 saveCommandQueueToFile(commandQueue, "unprocessed-commands.txt");
267 }
268
269 private static void saveCommandQueueToFile(final Vector<String> queue, String fname) {
270 output("Writing unprocessed commands to file " + fname);
271 try (PrintWriter pw = new PrintWriter(new File(fname), Charset.defaultCharset().name())) {
272 for (String command : queue) {
273 pw.println(command);
274 }
275 pw.close();
276 } catch (IOException ex) {
277 MCRCLIExceptionHandler.handleException(ex);
278 }
279 }
280
281 protected static void saveFailedCommand(String lastCommand) {
282 output("");
283 output("The following command failed:");
284 output(lastCommand);
285 if (!commandQueue.isEmpty()) {
286 System.out.printf(Locale.ROOT, "%s There are %s other commands still unprocessed.%n", system,
287 commandQueue.size());
288 }
289 failedCommands.add(lastCommand);
290 }
291
292 protected static void handleFailedCommands() {
293 if (failedCommands.size() > 0) {
294 System.err.println(system + " Several command failed.");
295 saveCommandQueueToFile(failedCommands, "failed-commands.txt");
296 }
297 }
298
299
300
301
302
303
304
305 public static void show(String fname) throws Exception {
306 AtomicInteger ln = new AtomicInteger();
307 System.out.println();
308 Files.readAllLines(Paths.get(fname), Charset.defaultCharset())
309 .forEach(l -> System.out.printf(Locale.ROOT, "%04d: %s", ln.incrementAndGet(), l));
310 System.out.println();
311 }
312
313
314
315
316 public static void getURI(String uri, String file) throws Exception {
317 Element resolved = MCRURIResolver.instance().resolve(uri);
318 Element cloned = resolved.clone();
319 new MCRJDOMContent(cloned).sendTo(new File(file));
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333
334 public static List<String> readCommandsFile(String file) throws IOException {
335 try (BufferedReader reader = Files.newBufferedReader(new File(file).toPath(), Charset.defaultCharset())) {
336 output("Reading commands from file " + file);
337 return readCommandsFromBufferedReader(reader);
338 }
339 }
340
341 public static List<String> readCommandsRessource(String resource) throws IOException {
342 final URL resourceURL = MCRClassTools.getClassLoader().getResource(resource);
343 if (resourceURL == null) {
344 throw new IOException("Resource URL is null!");
345 }
346 try (InputStream is = resourceURL.openStream();
347 InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
348 BufferedReader reader = new BufferedReader(isr)) {
349 output("Reading commands from resource " + resource);
350 return readCommandsFromBufferedReader(reader);
351 }
352 }
353
354 private static List<String> readCommandsFromBufferedReader(BufferedReader reader) throws IOException {
355 String line;
356 List<String> list = new ArrayList<>();
357 while ((line = reader.readLine()) != null) {
358 line = line.trim();
359
360 if (line.startsWith("#") || line.isEmpty()) {
361 continue;
362 }
363 list.add(line);
364 }
365 return list;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public static void executeShellCommand(String command) throws Exception {
382 MCRExternalProcess process = new MCRExternalProcess(command);
383 process.run();
384 output(process.getOutput().asString());
385 output(process.getErrors());
386 }
387
388
389
390
391 public static void whoami() {
392 MCRSession session = MCRSessionMgr.getCurrentSession();
393 String userName = session.getUserInformation().getUserID();
394 output("You are user " + userName);
395 }
396
397 public static void cancelOnError() {
398 SKIP_FAILED_COMMAND = false;
399 }
400
401 public static void skipOnError() {
402 SKIP_FAILED_COMMAND = true;
403 }
404
405
406
407
408
409 public static void exit() {
410 showSessionDuration();
411 handleFailedCommands();
412 System.exit(0);
413 }
414
415 private static void showSessionDuration() {
416 MCRSessionMgr.unlock();
417 MCRSession session = MCRSessionMgr.getCurrentSession();
418 long duration = System.currentTimeMillis() - session.getLoginTime();
419 output("Session duration: " + duration + " ms");
420 MCRSessionMgr.releaseCurrentSession();
421 session.close();
422 }
423
424 static void output(String message) {
425 System.out.println(system + " " + message);
426 }
427
428 private static class CLIURLClassLoader extends URLClassLoader {
429
430 CLIURLClassLoader(URL[] urls) {
431 super(urls);
432 }
433
434 @Override
435 protected void addURL(URL url) {
436
437 super.addURL(url);
438 }
439 }
440
441 }