All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.trigonic.utils.spring.cmdline.CommandLineMetaData Maven / Gradle / Ivy
/*
* Copyright 2011 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 com.trigonic.utils.spring.cmdline;
import java.beans.PropertyDescriptor;
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import joptsimple.OptionParser;
import joptsimple.internal.ColumnarData;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
public class CommandLineMetaData {
private Map options = new HashMap ();
private Map operands = new HashMap();
public CommandLineMetaData(Class> beanClass) {
populateOptionMethods(beanClass);
populateOptionFields(beanClass);
populateOperandMethods(beanClass);
populateOperandFields(beanClass);
validateOperands();
}
private void validateOperands() {
int expectedIndex = 0;
boolean remainderConsumed = false;
for (Entry entry : operands.entrySet()) {
if (remainderConsumed) {
throw new IllegalArgumentException(String.format("Operand index [%d] illegally follows multi-value operand"));
}
Operand operand = entry.getKey();
if (operand.index() < expectedIndex) {
throw new IllegalArgumentException(String.format("Duplicate operand index [%d]", operand.index()));
} else if (operand.index() > expectedIndex) {
throw new IllegalArgumentException(String.format("Missing operand index [%d]", expectedIndex));
}
expectedIndex = operand.index() + 1;
OperandHandler operandHandler = entry.getValue();
remainderConsumed = operandHandler.hasMultipleValues();
}
}
public Collection getOptionHandlers() {
return options.values();
}
public Collection getOperandHandlers() {
Set result = new TreeSet(new OperandHandlerOrderComparator());
result.addAll(operands.values());
return result;
}
public void register(OptionParser parser) {
for (OptionHandler optionHandler : getOptionHandlers()) {
optionHandler.register(parser);
}
}
public void printOperandsOn(PrintStream err) {
Collection operands = getOperandHandlers();
if (operands.size() > 0) {
ColumnarData columnarData = new ColumnarData("Operands", "Description");
for (OperandHandler operand : operands) {
columnarData.addRow(operand.getName(), operand.getDescription());
}
err.println();
err.println(columnarData.format());
}
}
private void checkWriteableProperty(T annotation, Class> beanClass, Field field) {
PropertyDescriptor property = BeanUtils.getPropertyDescriptor(beanClass, field.getName());
if (property == null || property.getWriteMethod() == null) {
throw new BeanDefinitionStoreException("@" + annotation.getClass().getSimpleName() + " annotation cannot be applied to fields without matching setters");
}
}
private PropertyDescriptor getPropertyForMethod(String annotationType, Annotation annotation, Method method) {
PropertyDescriptor property = BeanUtils.findPropertyForMethod(method);
if (property == null) {
throw new BeanDefinitionStoreException(annotationType + " annotation cannot be applied to non-property methods");
}
return property;
}
private void populateOperandFields(Class> beanClass) {
Class> superClass = beanClass.getSuperclass();
if (!superClass.equals(Object.class)) {
populateOperandFields(superClass);
}
for (Field field : beanClass.getDeclaredFields()) {
Operand operand = field.getAnnotation(Operand.class);
if (operand != null) {
checkWriteableProperty(operand, beanClass, field);
operands.put(operand, new OperandFieldHandler(operand, field));
}
}
}
private void populateOperandMethods(Class> beanClass) {
Class> superClass = beanClass.getSuperclass();
if (!superClass.equals(Object.class)) {
populateOperandMethods(superClass);
}
for (Method method : beanClass.getDeclaredMethods()) {
Operand operand = method.getAnnotation(Operand.class);
if (operand != null) {
operands.put(operand, new OperandPropertyHandler(operand, getPropertyForMethod("@Operand", operand, method), beanClass));
}
}
}
private void populateOptionFields(Class> beanClass) {
Class> superClass = beanClass.getSuperclass();
if (!superClass.equals(Object.class)) {
populateOptionFields(superClass);
}
for (Field field : beanClass.getDeclaredFields()) {
Option option = field.getAnnotation(Option.class);
if (option != null) {
checkWriteableProperty(option, beanClass, field);
options.put(option, new OptionFieldHandler(option, field));
}
}
}
private void populateOptionMethods(Class> beanClass) {
Class> superClass = beanClass.getSuperclass();
if (!superClass.equals(Object.class)) {
populateOptionMethods(superClass);
}
for (Method method : beanClass.getDeclaredMethods()) {
Option option = method.getAnnotation(Option.class);
if (option != null) {
options.put(option, new OptionPropertyHandler(option, getPropertyForMethod("@Option", option, method), beanClass));
}
}
}
}