package act.inject.param; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * 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. * #L% */ import act.cli.CliContext; import act.cli.Optional; import act.cli.Required; import act.util.ActContext; import org.osgl.inject.BeanSpec; import org.osgl.util.E; import org.osgl.util.Keyword; import org.osgl.util.S; import org.osgl.util.StringValueResolver; /** * Load command line options */ class OptionLoader extends CliParamValueLoader implements ParamValueLoader { final String bindName; String lead1; String lead2; final String defVal; final String requiredGroup; final boolean required; final BeanSpec beanSpec; final String errorTemplate; private final StringValueResolver resolver; OptionLoader(String bindName, Optional optional, StringValueResolver resolver, BeanSpec beanSpec) { this.bindName = bindName; this.required = false; this.parseLeads(optional.lead()); this.defVal = optional.defVal(); this.requiredGroup = null; this.beanSpec = beanSpec; this.errorTemplate = errorTemplate(optional); this.resolver = resolver; CliContext.ParsingContextBuilder.foundOptional(); } OptionLoader(String bindName, Required required, StringValueResolver resolver, BeanSpec beanSpec) { this.bindName = bindName; this.required = true; this.parseLeads(required.lead()); this.defVal = null; String group = required.group(); this.requiredGroup = S.blank(group) ? bindName : group; this.beanSpec = beanSpec; this.errorTemplate = errorTemplate(required); this.resolver = resolver; CliContext.ParsingContextBuilder.foundRequired(this.requiredGroup); } @Override public Object load(Object cachedBean, ActContext<?> context, boolean noDefaultValue) { CliContext ctx = (CliContext) context; String optVal = ctx.paramVal(bindName); if (S.blank(optVal) && required) { optVal = getFirstArgument(ctx); } Object val = null; if (S.notBlank(optVal)) { val = resolve(optVal); } if (null == val && null != cachedBean) { val = cachedBean; } if (null == val) { if (!required) { val = S.notBlank(defVal) ? resolve(defVal) : resolve(null); } } if (null != val && required) { ctx.parsingContext().foundRequired(requiredGroup); } return val; } @Override public String bindName() { return this.bindName; } private Object resolve(String val) { return resolve(val, resolver); } private <T> T resolve(String val, StringValueResolver<T> resolver) { if (null == errorTemplate) { return resolver.resolve(val); } try { return resolver.resolve(val); } catch (Exception e) { throw E.unexpected(errorTemplate, val); } } private String errorTemplate(Optional optional) { return verifyErrorTemplate(optional.errorTemplate()); } private String errorTemplate(Required required) { return verifyErrorTemplate(required.errorTemplate()); } private String verifyErrorTemplate(String s) { if (S.blank(s)) { return null; } if (!s.contains("%")) { throw E.invalidConfiguration("Error template must have format argument placeholder, e.g. %s inside it: " + s); } if (s.split("%").length > 2) { throw E.invalidConfiguration("Error template must not have more than one format argument placeholder, e.g. %s inside it: " + s); } return s; } private void parseLeads(String[] specs) { lead1 = specs[0]; if (specs.length > 1) { lead2 = specs[1]; } else { String[] sa = lead1.split("[,;\\s]+"); if (sa.length > 2) { throw E.unexpected("Option cannot have more than two leads"); } if (sa.length > 1) { lead1 = sa[0]; lead2 = sa[1]; } } if (S.blank(lead1)) { lead1 = "-" + bindName.charAt(0); lead2 = "--" + Keyword.of(bindName).dashed(); } } }