All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.shell.legacy.LegacyMethodTargetRegistrar Maven / Gradle / Ivy

/*
 * Copyright 2015-2017 the original author or authors.
 *
 * 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.springframework.shell.legacy;

import static org.springframework.util.StringUtils.collectionToDelimitedString;

import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Supplier;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.shell.Availability;
import org.springframework.shell.ConfigurableCommandRegistry;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.MethodTarget;
import org.springframework.shell.MethodTargetRegistrar;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

/**
 * A {@link MethodTargetRegistrar} that discovers methods annotated with {@link CliCommand} on beans
 * implementing the {@link CommandMarker} marker interface.
 * 
 * @author Eric Bottard
 * @author Florent Biville
 * @author Camilo Gonzalez
 */
@Component
public class LegacyMethodTargetRegistrar implements MethodTargetRegistrar {

	@Autowired
	private ApplicationContext applicationContext;

	private Map commands = new TreeMap<>();
	
	@Override
	public void register(ConfigurableCommandRegistry registry) {
		Map beans = applicationContext.getBeansOfType(CommandMarker.class);
		for (Object bean : beans.values()) {
			Class clazz = bean.getClass();
			ReflectionUtils.doWithMethods(clazz, method -> {
				CliCommand cliCommand = method.getAnnotation(CliCommand.class);
				for (String key : cliCommand.value()) {
					Supplier availabilityIndicator = bridgeAvailabilityIndicator(key, bean);
					MethodTarget target = new MethodTarget(method, bean, cliCommand.help(), availabilityIndicator);
					registry.register(key, target);
					commands.put(key, target);
				}
			}, method -> method.getAnnotation(CliCommand.class) != null);
		}
	}

	private Supplier bridgeAvailabilityIndicator(String commandKey, Object bean) {
		Class clazz = bean.getClass();
		Set candidates = new HashSet<>();

		ReflectionUtils.doWithMethods(clazz, candidates::add,
			method -> method.getAnnotation(CliAvailabilityIndicator.class) != null
					&& Arrays.asList(method.getAnnotation(CliAvailabilityIndicator.class).value()).contains(commandKey));

		switch (candidates.size()) {
			case 0:
				return null;
			case 1:
				return () -> {
					boolean available = (Boolean) ReflectionUtils.invokeMethod(candidates.iterator().next(), bean);
					return available ? Availability.available() : Availability.unavailable("[Unknown reason]");
				};
			default:
				throw new IllegalStateException("Looks like there are several @" + CliAvailabilityIndicator.class.getSimpleName()
				+ " for '" + commandKey + "'. Found " + candidates);
		}
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + " contributing "
			+ collectionToDelimitedString(commands.keySet(), ", ", "[", "]");
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy