package com.framsticks.params; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import com.framsticks.params.annotations.AutoAppendAnnotation; import com.framsticks.params.annotations.FramsClassAnnotation; import com.framsticks.params.annotations.ParamAnnotation; import com.framsticks.parsers.FileSource; import com.framsticks.parsers.Loaders; import com.framsticks.util.Builder; import com.framsticks.util.Misc; import com.framsticks.util.lang.Containers; import com.framsticks.util.lang.Strings; @FramsClassAnnotation(id = "class", name = "class") public class FramsClassBuilder implements Builder { private static final Logger log = LogManager.getLogger(FramsClassBuilder.class); public static String getName(FramsClassAnnotation fca, Class javaClass) { return fca.name().equals("") ? javaClass.getSimpleName() : fca.name(); } public static String getId(FramsClassAnnotation fca, Class javaClass) { return fca.id().equals("") ? javaClass.getSimpleName() : fca.id(); } public static final String GENERATE_HELP_PREFIX = "automatically generated from: "; public static FramsClass readFromStream(InputStream stream) { return readFromSource(new FileSource(stream)); } public static FramsClass readFromSource(Source source) { return Loaders.loadFramsClass(source); } // public static Class getParamType(@Nonnull Class c) { // if (c.equals(Integer.class)) { // return DecimalParam.class; // } // if (c.equals(Double.class)) { // return FloatParam.class; // } // if (c.equals(String.class)) { // return StringParam.class; // } // if (c.equals(Object.class)) { // return UniversalParam.class; // } // return null; // } public static String extractIdOf(Member member) { if (member instanceof Field) { return member.getName(); } if (member instanceof Method) { Method m = (Method) member; String n = m.getName(); int argsNum = m.getParameterTypes().length; if (argsNum == 0) { return n.startsWith("get") ? Strings.uncapitalize(n.substring(3)) : n; } if (argsNum == 1) { if (n.startsWith("set")) { return Strings.uncapitalize(n.substring(3)); } if (n.startsWith("add")) { return Strings.uncapitalize(n.substring(3)); } if (n.startsWith("remove")) { return Strings.uncapitalize(n.substring(6)); } return n; } log.error("invalid number of arguments"); return null; } log.error("invalid kind of member"); return null; } public static String getName(ParamAnnotation annotation, Member member) { return annotation.name().equals("") ? Strings.capitalize(extractIdOf(member)) : annotation.name(); } public static String getId(ParamAnnotation annotation, Member member) { return annotation.id().equals("") ? extractIdOf(member) : annotation.id(); } public static ParamBuilder fill(ParamBuilder builder, Member member, ParamAnnotation annotation) { return builder .id(getId(annotation, member)) .name(getName(annotation, member)); } public static final Map, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new IdentityHashMap, FramsClass>()); public FramsClass forClass(Class javaClass) throws ConstructionException { FramsClass result = synchronizedCacheForBasedOnForJavaClass.get(javaClass); if (result != null) { return result; } log.debug("building for class {}", javaClass); FramsClassAnnotation fca = javaClass.getAnnotation(FramsClassAnnotation.class); if (fca == null) { throw new ConstructionException().msg("java class is not annotated with FramsClassAnnotation").arg("java", javaClass); } id(getId(fca, javaClass)); name(getName(fca, javaClass)); for (ParamCandidate pc : ParamCandidate.getAllCandidates(javaClass).getOrder()) { ParamBuilder builder = Param.build().id(pc.getId()).name(pc.getName()).flags(pc.getFlags()); pc.induceParamType(builder); for (ParamAnnotation pa : pc.getAnnotations()) { if (!"".equals(pa.def())) { builder.def(pa.def()); } if (!"".equals(pa.help())) { builder.help(pa.help()); } if (!"".equals(pa.min())) { builder.min(pa.min()); } if (!"".equals(pa.max())) { builder.max(pa.max()); } builder.extra(pa.extra()); if (!"".equals(pa.stringType())) { builder.type(pa.stringType()); } if (!pa.paramType().equals(Param.class)) { builder.type(pa.paramType()); } } param(builder); } result = finish(); synchronizedCacheForBasedOnForJavaClass.put(javaClass, result); return result; } protected String id; protected String name; protected String description; protected final List params = new LinkedList<>(); protected List groupBuilders = new ArrayList(); @ParamAnnotation public FramsClassBuilder id(String id) { this.id = id; return this; } @ParamAnnotation public FramsClassBuilder name(String name) { this.name = name; return this; } public FramsClassBuilder idAndName(String v) { this.id = v; this.name = v; return this; } @ParamAnnotation(id = "desc") public FramsClassBuilder description(String description) { this.description = description; return this; } public FramsClassBuilder() { } public FramsClass finish() { return new FramsClass(this); } @AutoAppendAnnotation public FramsClassBuilder param(ParamBuilder builder) { Param param = builder.finish(); Integer group = param.getGroup(); if (group != null) { Containers.getFromList(groupBuilders, group, "group", this).addParam(param); } params.add(param); return this; } @AutoAppendAnnotation public FramsClassBuilder group(GroupBuilder builder) { groupBuilders.add(builder); return this; } /** * @return the id */ @ParamAnnotation public String getId() { return id; } /** * @return the name */ @ParamAnnotation public String getName() { return name; } /** * @return the description */ @ParamAnnotation(id = "desc") public String getDescription() { return description; } public FramsClassBuilder group(String group) { return group(new GroupBuilder().name(group)); } @Override public String toString() { return "FramsClassBuilder for " + Misc.returnNotNull(id, ""); } }