/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed 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.keycloak.testsuite.util.cli; import org.jboss.logging.Logger; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.testsuite.KeycloakServer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * See Testsuite.md (section how to create many users and offline sessions) * * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> */ public class TestsuiteCLI { private static final Logger log = Logger.getLogger(TestsuiteCLI.class); private static final Class<?>[] BUILTIN_COMMANDS = { ExitCommand.class, HelpCommand.class, AbstractOfflineCacheCommand.PutCommand.class, AbstractOfflineCacheCommand.GetCommand.class, AbstractOfflineCacheCommand.GetMultipleCommand.class, AbstractOfflineCacheCommand.GetLocalCommand.class, AbstractOfflineCacheCommand.SizeLocalCommand.class, AbstractOfflineCacheCommand.RemoveCommand.class, AbstractOfflineCacheCommand.SizeCommand.class, AbstractOfflineCacheCommand.ListCommand.class, AbstractOfflineCacheCommand.ClearCommand.class, PersistSessionsCommand.class, LoadPersistentSessionsCommand.class, UserCommands.Create.class, UserCommands.Remove.class, UserCommands.Count.class, UserCommands.GetUser.class, SyncDummyFederationProviderCommand.class, RoleCommands.CreateRoles.class, CacheCommands.ListCachesCommand.class, CacheCommands.GetCacheCommand.class, CacheCommands.CacheRealmObjectsCommand.class }; private final KeycloakSessionFactory sessionFactory; private final Map<String, Class<? extends AbstractCommand>> commands = new LinkedHashMap<>(); public TestsuiteCLI(KeycloakServer server) { this.sessionFactory = server.getSessionFactory(); // register builtin commands for (Class<?> clazz : BUILTIN_COMMANDS) { Class<? extends AbstractCommand> commandClazz = (Class<? extends AbstractCommand>) clazz; try { AbstractCommand command = commandClazz.newInstance(); commands.put(command.getName(), commandClazz); } catch (Exception ex) { log.error("Error registering command of class: " + commandClazz.getName(), ex); } } } public void registerCommand(String name, Class<? extends AbstractCommand> command) { commands.put(name, command); } // WARNING: Stdin blocking operation public void start() throws IOException { log.info("Starting testsuite CLI. Exit with 'exit' . Available commands with 'help' "); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String line; System.out.print("$ "); try { while ((line = reader.readLine()) != null) { String[] splits = line.split(" "); String commandName = splits[0]; Class<? extends AbstractCommand> commandClass = commands.get(commandName); if (commandClass == null) { log.errorf("Unknown command: %s", commandName); } else { try { AbstractCommand command = commandClass.newInstance(); List<String> args = new ArrayList<>(Arrays.asList(splits)); args.remove(0); command.injectProperties(args, this, sessionFactory); command.runCommand(); // Just special handling of ExitCommand if (command instanceof ExitCommand) { return; } } catch (InstantiationException ex) { log.error(ex); } catch (IllegalAccessException ex) { log.error(ex); } } System.out.print("$ "); } } finally { log.info("Exit testsuite CLI"); reader.close(); } } public static class ExitCommand extends AbstractCommand { @Override public String getName() { return "exit"; } @Override public void runCommand() { // no need to implement. Exit handled in parent } @Override protected void doRunCommand(KeycloakSession session) { // no need to implement } @Override public String printUsage() { return getName(); } } public static class HelpCommand extends AbstractCommand { private List<String> commandNames = new ArrayList<>(); @Override public void injectProperties(List<String> args, TestsuiteCLI cli, KeycloakSessionFactory sessionFactory) { for (String commandName : cli.commands.keySet()) { commandNames.add(commandName); } } @Override public String getName() { return "help"; } @Override public void runCommand() { log.info("Available commands: " + commandNames.toString()); } @Override protected void doRunCommand(KeycloakSession session) { // no need to implement } } }