/*
* Copyright (C) 2017 by Fonoster Inc (http://fonoster.com)
* http://astivetoolkit.org
*
* This file is part of Astive Toolkit(ATK)
*
* 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.astivetoolkit.agi;
import org.astivetoolkit.agi.annotation.*;
import org.astivetoolkit.util.AppLocale;
import java.lang.reflect.Field;
import java.util.*;
/**
* This class is a helper. Can be use to extract meta information from Agi
* commands classes and then construct commands in string format.
*
* @since 1.0
*/
public final class CommandProcessor {
/**
* Build a command from a class marked with {@link AgiCommand}.
*
* @param o object to in command generation.
* @return command as string.
* @throws AgiException
*/
public static String buildCommand(Object o) throws AgiException {
AgiCommand command = o.getClass().getAnnotation(AgiCommand.class);
if (command == null) {
throw new AgiException(AppLocale.getI18n("notACommandObject"));
}
final List<Field> parameters = getParameters(o);
StringBuilder cmd = new StringBuilder(command.command());
if (parameters == null || parameters.isEmpty()) {
return command.command();
}
for (Field field : parameters) {
Parameter p = field.getAnnotation(Parameter.class);
Object param;
try {
param = field.get(o);
} catch (IllegalArgumentException ex) {
throw new AgiException(ex);
} catch (IllegalAccessException ex) {
throw new AgiException(ex);
}
if (param instanceof String || param instanceof Character) {
if (param instanceof Character) {
Character c = (Character) param;
if (!c.toString().trim().isEmpty()) {
cmd.append(" ");
cmd.append("\"");
cmd.append(c);
cmd.append("\"");
}
} else {
cmd.append(" ");
cmd.append("\"");
cmd.append(param.toString().trim());
cmd.append("\"");
}
} else if (param.getClass().isArray()) {
if (!field.isAnnotationPresent(ParamConverter.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation",
new Object[]{ParamConverter.class}));
} else if (!field.isAnnotationPresent(Separator.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation",
new Object[]{Separator.class}));
}
ParamConverter pc = field.getAnnotation(ParamConverter.class);
Separator separator = field.getAnnotation(Separator.class);
StringConverter sc;
try {
sc = (StringConverter) pc.converter().newInstance();
String[] paramArr = (String[]) param;
String paramStr = sc.fromArrayString(paramArr, separator.value());
cmd.append(" ");
cmd.append("\"");
cmd.append(paramStr);
cmd.append("\"");
} catch (InstantiationException ex) {
throw new AgiException(ex.getMessage());
} catch (IllegalAccessException ex) {
throw new AgiException(ex.getMessage());
}
} else if (param instanceof Boolean) {
if (!field.isAnnotationPresent(ParamConverter.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation"));
} else if (!field.isAnnotationPresent(BooleanChoose.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation",
new Object[]{Separator.class}));
}
BooleanChoose bc = field.getAnnotation(BooleanChoose.class);
String t = bc.valueOnFalse();
Boolean b = (Boolean) param;
if (b == true) {
t = bc.valueOnTrue();
}
if (!t.isEmpty()) {
cmd.append(" ");
cmd.append("\"");
cmd.append(t);
cmd.append("\"");
}
} else if (param instanceof Date) {
if (!field.isAnnotationPresent(ParamConverter.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation"));
}
Date date = (Date) param;
long seconds = date.getTime() / 1000;
cmd.append(" ");
cmd.append("\"");
cmd.append(seconds);
cmd.append("\"");
} else if (param instanceof TimeZone) {
if (!field.isAnnotationPresent(ParamConverter.class)) {
throw new AgiException(AppLocale.getI18n("cantFoundAnnotation"));
}
TimeZone tz = (TimeZone) param;
String id = tz.getID();
cmd.append(" ");
cmd.append("\"");
cmd.append(id);
cmd.append("\"");
} else {
if (!p.prefix().isEmpty()) {
cmd.append(" ");
cmd.append("\"");
cmd.append(p.prefix());
cmd.append(param);
cmd.append("\"");
} else {
cmd.append(" ");
cmd.append(param);
}
}
}
return cmd.toString().trim();
}
// Get all fields marked with annotations {@link Parameter}
// @param o object to analyze.
private static List getParameters(Object o) throws AgiException {
List parameters = new ArrayList();
Field[] fs = o.getClass().getDeclaredFields();
HashMap map = new HashMap();
for (Field f : fs) {
if (f.getAnnotation(Parameter.class) != null) {
map.put(f.getAnnotation(Parameter.class).position(), f);
}
}
Object[] keysArr = map.keySet().toArray();
Arrays.sort(keysArr);
for (Object i : keysArr) {
Field f = (Field) map.get(i);
f.setAccessible(true);
Object c;
try {
c = f.get(o);
} catch (IllegalArgumentException ex) {
throw new AgiException(ex);
} catch (IllegalAccessException ex) {
throw new AgiException(ex);
}
// This avoid automatic cast to string
if (c != null) {
parameters.add(map.get(i));
} else {
break;
}
}
return parameters;
}
private CommandProcessor() {
}
}