| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.flex.compiler.config; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| |
| import org.apache.flex.compiler.internal.config.annotations.DefaultArgumentValue; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Objects; |
| |
| /** |
| * Meta information for each configuration options. It is created by |
| * {@link ConfigurationBuffer#loadCache} from either annotations or |
| * {@code public static ConfigurationInfo getFooInfo();} methods in |
| * {@link Configuration} class. |
| */ |
| public class ConfigurationInfo |
| { |
| public static final int NOT_SET = -2; |
| public static final int INFINITE_ARGS = -1; |
| |
| /** |
| * This ctor is used when everything can be introspected off the setter |
| * method, or else when the names/types are provided by method overrides |
| * rather than ctor arguments |
| */ |
| public ConfigurationInfo() |
| { |
| this.argcount = NOT_SET; |
| this.argnames = null; |
| } |
| |
| /** |
| * Simple ctor for restricting the number of arguments. |
| * |
| * @param argcount number of args, -1 for an infinite list |
| */ |
| public ConfigurationInfo(int argcount) |
| { |
| this.argcount = argcount; |
| this.argnames = null; |
| } |
| |
| /** |
| * Simple ctor for naming the arguments. |
| * |
| * @param argnames list of argnames, argcount will default to # of elements |
| */ |
| public ConfigurationInfo(String argnames[]) |
| { |
| this.argcount = argnames.length; |
| this.argnames = argnames; |
| } |
| |
| /** |
| * Use this ctor when you want to set a single list of some number of |
| * identically named args |
| * |
| * @param argcount number of arguments (-1 for infinite) |
| * @param argname name of each argument |
| */ |
| public ConfigurationInfo(int argcount, String argname) |
| { |
| this.argcount = argcount; |
| this.argnames = new String[] {argname}; |
| } |
| |
| /** |
| * More unusual ctor, this would let you have the first few args named one |
| * thing, the rest named something else. It is far more likely that you want |
| * a constrained list of names or else an arbitrary list of identical names. |
| * |
| * @param argcount number of arguments |
| * @param argnames array of argument names |
| */ |
| public ConfigurationInfo(int argcount, String argnames[]) |
| { |
| this.argcount = argcount; |
| this.argnames = argnames; |
| } |
| |
| public final int getArgCount() |
| { |
| return argcount; |
| } |
| |
| protected int argcount = NOT_SET; |
| |
| protected String[] defaultArgValues = null; |
| |
| /** |
| * Get any default values for an argument |
| * |
| * @return an array of default argument values. May be null |
| */ |
| public final String[] getDefaultArgValues() |
| { |
| return defaultArgValues; |
| } |
| |
| private static String classToArgName(Class<?> c) |
| { |
| // we only support builtin classnames! |
| |
| String className = c.getName(); |
| if (className.startsWith("java.lang.")) |
| className = className.substring("java.lang.".length()); |
| |
| return className.toLowerCase(); |
| } |
| |
| /** |
| * Return the name of each parameter. The default implementation is usually |
| * sufficient for simple cases, but one could do wacky things here like |
| * support an infinite list of alternating arg names. |
| * |
| * @param argnum The argument number. |
| * @return name of argument |
| */ |
| public String getArgName(int argnum) |
| { |
| if (argNameGeneratorClass != null) |
| { |
| Method getArgNameMethod; |
| try |
| { |
| getArgNameMethod = argNameGeneratorClass.getMethod("getArgumentName", int.class); |
| return (String)getArgNameMethod.invoke(null, argnum); |
| } |
| catch (Exception e) |
| { |
| // TODO: connect these exception to our problem logging subsystem. |
| e.printStackTrace(); |
| } |
| |
| return ""; |
| } |
| |
| if ((argnames == null) || (argnames.length == 0)) |
| { |
| return classToArgName(getArgType(argnum)); |
| } |
| else if (argnum >= argnames.length) |
| { |
| return argnames[argnames.length - 1]; |
| } |
| else |
| { |
| return argnames[argnum]; |
| } |
| } |
| |
| /** |
| * Return the type of each parameter. This is computed based on your setter, |
| * and cannot be overridden |
| * |
| * @param argnum The argument number. |
| */ |
| public final Class<?> getArgType(int argnum) |
| { |
| if (argnum >= argtypes.length) |
| { |
| return argtypes[argtypes.length - 1]; |
| } |
| else |
| { |
| return argtypes[argnum]; |
| } |
| } |
| |
| protected Class<?> argNameGeneratorClass; |
| protected String[] argnames; |
| protected Class<?>[] argtypes; |
| |
| protected String[] prerequisites = null; |
| |
| /** |
| * Return variable names that should be set before this one. The buffer is |
| * always set such that it tries to set all variables at a given level |
| * before setting child values, but you could override by using this. Its |
| * probably a bad idea to depend on children, though. It is unnecessary to |
| * set parent vars as prerequisites, since they are implicitly set first |
| */ |
| public String[] getPrerequisites() |
| { |
| return prerequisites; |
| } |
| |
| protected String[] softPrerequisites = null; |
| |
| /** |
| * Prerequisites which should be set before this one if they exist |
| */ |
| public String[] getSoftPrerequisites() |
| { |
| return softPrerequisites; |
| } |
| |
| protected boolean allowMultiple = false; |
| |
| /** |
| * Variables are generally only allowed to be set once in a given |
| * file/cmdline. It is sometimes useful to allow the same set multiple times |
| * in order to aggregate values. |
| * |
| * @return true if the setter can be called multiple times |
| */ |
| public boolean allowMultiple() |
| { |
| return allowMultiple; |
| } |
| |
| protected String[] aliases = null; |
| |
| /** |
| * Return an array of other names for this variable. |
| */ |
| public String[] getAliases() |
| { |
| return aliases; |
| } |
| |
| protected boolean isAdvanced = false; |
| |
| /** |
| * Override to make a variable hidden by default (i.e. you need -advanced on |
| * the cmdline) |
| */ |
| public boolean isAdvanced() |
| { |
| return isAdvanced; |
| } |
| |
| protected boolean isHidden = false; |
| |
| /** |
| * Override to make a variable completely hidden |
| */ |
| public boolean isHidden() |
| { |
| return isHidden; |
| } |
| |
| protected boolean isDisplayed = true; |
| |
| /** |
| * Override to prevent printing when dumping configuration |
| */ |
| public boolean isDisplayed() |
| { |
| return isDisplayed; |
| } |
| |
| /** |
| * If a variable -must- be set, override this |
| */ |
| public boolean isRequired() |
| { |
| return isRequired; |
| } |
| |
| protected boolean isRequired = false; |
| |
| /** |
| * Magic used by the command line configurator only at the moment to decide |
| * whether this variable should eat all subsequent arguments. Useful for |
| * -help... |
| */ |
| public boolean isGreedy() |
| { |
| return isGreedy; |
| } |
| |
| protected boolean isGreedy = false; |
| |
| public boolean isPath() |
| { |
| return isPath; |
| } |
| |
| protected boolean isPath = false; |
| |
| public boolean doChecksum() |
| { |
| return true; |
| } |
| |
| public String getDeprecatedMessage() |
| { |
| return deprecatedMessage; |
| } |
| |
| protected String deprecatedMessage = null; |
| |
| public boolean isDeprecated() |
| { |
| return isDeprecated; |
| } |
| |
| protected boolean isDeprecated = false; |
| |
| public String getDeprecatedReplacement() |
| { |
| return deprecatedReplacement; |
| } |
| |
| protected String deprecatedReplacement; |
| |
| public String getDeprecatedSince() |
| { |
| return deprecatedSince; |
| } |
| |
| protected String deprecatedSince; |
| |
| /** |
| * @return True indicates that the option is no longer |
| * supported and will not have any affect. |
| */ |
| public boolean isRemoved() |
| { |
| return isRemoved; |
| } |
| |
| protected boolean isRemoved = false; |
| |
| /** |
| * @return True the option requires Flex in order to be useful. |
| */ |
| public boolean isFlexOnly() |
| { |
| return isFlexOnly; |
| } |
| |
| protected boolean isFlexOnly = false; |
| |
| protected final void setSetterMethod(Method setter) |
| { |
| Class<?>[] pt = setter.getParameterTypes(); |
| |
| assert (pt.length >= 2) : ("coding error: config setter must take at least 2 args!"); |
| |
| this.setter = setter; |
| |
| if (pt.length == 2) |
| { |
| Class<?> c = pt[1]; |
| |
| if (ConfigurationBuffer.isSupportedListType(c)) |
| { |
| if (argcount == NOT_SET) |
| argcount = -1; // infinite list |
| |
| argtypes = new Class[] {String.class}; |
| return; |
| } |
| else if (ConfigurationBuffer.isSupportedValueType(c)) |
| { |
| assert (argcount == NOT_SET) : ("coding error: value object setter cannot override argcount"); |
| assert (argnames == null) : ("coding error: value object setter cannot override argnames"); |
| |
| Field[] fields = c.getFields(); |
| |
| argcount = fields.length; |
| |
| assert (argcount > 0) : ("coding error: " + setter + " value object " + c.getName() + " must contain at least one public field"); |
| |
| argnames = new String[fields.length]; |
| argtypes = new Class[fields.length]; |
| |
| for (int f = 0; f < fields.length; ++f) |
| { |
| argnames[f] = ConfigurationBuffer.c2h(fields[f].getName()); |
| argtypes[f] = fields[f].getType(); |
| } |
| return; |
| } |
| } |
| |
| assert ((argcount == NOT_SET) || (argcount == pt.length - 1)) : ("coding error: the argument count must match the number of setter arguments"); |
| // We've taken care of lists and value objects, from here on out, it must match the parameter list. |
| |
| argcount = pt.length - 1; |
| |
| DefaultArgumentValue defaultArgValuesAnno = setter.getAnnotation(DefaultArgumentValue.class); |
| if (defaultArgValuesAnno != null) |
| defaultArgValues = defaultArgValuesAnno.value(); |
| |
| argtypes = new Class[pt.length - 1]; |
| for (int i = 1; i < pt.length; ++i) |
| { |
| assert (ConfigurationBuffer.isSupportedSimpleType(pt[i])) : ("coding error: " + setter.getClass().getName() + "." + setter.getName() + " parameter " + i + " is not a supported type!"); |
| argtypes[i - 1] = pt[i]; |
| } |
| } |
| |
| protected final Method getSetterMethod() |
| { |
| return setter; |
| } |
| |
| private Method setter; |
| private Method getter; |
| |
| protected final void setGetterMethod(Method getter) |
| { |
| this.getter = getter; |
| } |
| |
| protected final Method getGetterMethod() |
| { |
| return getter; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return Objects.toStringHelper("") |
| .add("alias", arrayAsString(getAliases())) |
| .add("argcount", getArgCount()) |
| .add("argnames", arrayAsString(argnames)) |
| .add("argtypes", arrayAsString(argtypes)) |
| .add("deprecated", isDeprecated()) |
| .add("deprecatedMessage", getDeprecatedMessage()) |
| .add("deprecatedReplacement", getDeprecatedReplacement()) |
| .add("deprecatedSince", getDeprecatedSince()) |
| .add("getter", getGetterMethod() == null ? "null" : getGetterMethod().getName()) |
| .add("setter", getSetterMethod() == null ? "null" : getSetterMethod().getName()) |
| .add("required", isRequired()) |
| .add("Prerequisites", arrayAsString(getPrerequisites())) |
| .add("softPrerequisites", arrayAsString(getSoftPrerequisites())) |
| .add("advanced", isAdvanced()) |
| .add("allow multiple", allowMultiple()) |
| //.add("doChecksum", doChecksum()) |
| .add("displayed", isDisplayed()) |
| .add("greedy", isGreedy()) |
| .add("hidden", isHidden()) |
| .add("removed", isRemoved()) |
| .add("path", isPath()) |
| .toString(); |
| } |
| |
| private String arrayAsString(Object[] array) |
| { |
| if (array == null) |
| return ""; |
| else |
| return "[" + Joiner.on(",").join(array) + "]"; |
| } |
| |
| /** |
| * True if only {@code compc} client can use this option. |
| */ |
| public boolean isCompcOnly = false; |
| } |