package org.keycloak.client.registration.cli.commands; import org.jboss.aesh.cl.Arguments; import org.jboss.aesh.cl.CommandDefinition; import org.jboss.aesh.cl.Option; import org.jboss.aesh.console.command.CommandException; import org.jboss.aesh.console.command.CommandResult; import org.jboss.aesh.console.command.invocation.CommandInvocation; import org.keycloak.client.registration.cli.common.AttributeKey; import org.keycloak.client.registration.cli.common.EndpointType; import org.keycloak.client.registration.cli.util.ReflectionUtil; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.oidc.OIDCClientRepresentation; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.keycloak.client.registration.cli.util.OsUtil.CMD; import static org.keycloak.client.registration.cli.util.OsUtil.PROMPT; import static org.keycloak.client.registration.cli.util.ReflectionUtil.getAttributeListWithJSonTypes; import static org.keycloak.client.registration.cli.util.ReflectionUtil.isBasicType; import static org.keycloak.client.registration.cli.util.ReflectionUtil.isListType; import static org.keycloak.client.registration.cli.util.ReflectionUtil.isMapType; /** * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> */ @CommandDefinition(name = "attrs", description = "[ATTRIBUTE] [--endpoint TYPE]") public class AttrsCmd extends AbstractGlobalOptionsCmd { @Option(shortName = 'e', name = "endpoint", description = "Endpoint type to use", hasValue = true) protected String endpoint; @Arguments protected List<String> args; protected String attr; @Override public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException { try { processGlobalOptions(); if (printHelp()) { return CommandResult.SUCCESS; } EndpointType regType = EndpointType.DEFAULT; PrintStream out = commandInvocation.getShell().out(); if (endpoint != null) { regType = EndpointType.of(endpoint); } if (args != null) { if (args.size() > 1) { throw new IllegalArgumentException("Invalid option: " + args.get(1)); } attr = args.get(0); } Class type = regType == EndpointType.DEFAULT ? ClientRepresentation.class : (regType == EndpointType.OIDC ? OIDCClientRepresentation.class : null); if (type == null) { throw new IllegalArgumentException("Endpoint not supported: " + regType); } AttributeKey key = attr == null ? new AttributeKey() : new AttributeKey(attr); Field f = ReflectionUtil.resolveField(type, key); String ts = f != null ? ReflectionUtil.getTypeString(null, f) : null; if (f == null) { out.printf("Attributes for %s format:\n", regType.getEndpoint()); LinkedHashMap<String, String> items = getAttributeListWithJSonTypes(type, key); for (Map.Entry<String, String> item : items.entrySet()) { out.printf(" %-40s %s\n", item.getKey(), item.getValue()); } } else { out.printf("%-40s %s", attr, ts); boolean eol = false; Type t = f.getGenericType(); if (isListType(f.getType()) && t instanceof ParameterizedType) { t = ((ParameterizedType) t).getActualTypeArguments()[0]; if (!isBasicType(t) && t instanceof Class) { eol = true; System.out.printf(", where value is:\n", ts); LinkedHashMap<String, String> items = ReflectionUtil.getAttributeListWithJSonTypes((Class) t, null); for (Map.Entry<String, String> item : items.entrySet()) { out.printf(" %-36s %s\n", item.getKey(), item.getValue()); } } } else if (isMapType(f.getType()) && t instanceof ParameterizedType) { t = ((ParameterizedType) t).getActualTypeArguments()[1]; if (!isBasicType(t) && t instanceof Class) { eol = true; out.printf(", where value is:\n", ts); LinkedHashMap<String, String> items = ReflectionUtil.getAttributeListWithJSonTypes((Class) t, null); for (Map.Entry<String, String> item : items.entrySet()) { out.printf(" %-36s %s\n", item.getKey(), item.getValue()); } } } if (!eol) { // add end of line out.println(); } } return CommandResult.SUCCESS; } finally { commandInvocation.stop(); } } protected String help() { return usage(); } public static String usage() { StringWriter sb = new StringWriter(); PrintWriter out = new PrintWriter(sb); out.println("Usage: " + CMD + " attrs [ATTRIBUTE] [ARGUMENTS]"); out.println(); out.println("List available configuration attributes."); out.println(); out.println("Arguments:"); out.println(); out.println(" Global options:"); out.println(" -x Print full stack trace when exiting with error"); out.println(); out.println(" Command specific options:"); out.println(" ATTRIBUTE Attribute key (if omitted all attributes for the endpoint type are listed)"); out.println(" Dot notation can be used to target sub-attributes."); out.println(" -e, --endpoint TYPE Endpoint type to use - one of: 'default', 'oidc' (if omitted 'default' is used)"); out.println(); out.println("Examples:"); out.println(); out.println("List all attributes for default endpoint:"); out.println(" " + PROMPT + " " + CMD + " attrs"); out.println(); out.println("List (sub)attributes of 'protocolMappers' attribute for default endpoint:"); out.println(" " + PROMPT + " " + CMD + " attrs protocolMappers"); out.println(); out.println(); out.println("Use '" + CMD + " help' for general information and a list of commands"); return sb.toString(); } }