001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.svl.vars;
018
019import java.util.function.*;
020
021import org.apache.juneau.commons.runtime.*;
022import org.apache.juneau.commons.settings.*;
023import org.apache.juneau.commons.svl.*;
024
025/**
026 * JVM args variable resolver.
027 *
028 * <p>
029 * The format for this var is <js>"$A{arg[,default]}"</js>.
030 *
031 * <p>
032 * The argument can be either a positional index (e.g. <js>"$A{0}"</js>) or a named option (e.g. <js>"$A{port}"</js>).
033 *
034 * <p>
035 * This variable resolver requires that the command-line arguments be made available through any of the following:
036 * <ul class='spaced-list'>
037 *    <li><js>"sun.java.command"</js> system property.
038 *    <li><js>"juneau.args"</js> system property.
039 *    <li>The instance was created via {@link #create(Supplier)}.
040 * </ul>
041 *
042 * <h5 class='section'>Example:</h5>
043 * <p class='bjava'>
044 *    <jc>// Create an args object from the main(String[]) method.</jc>
045 *    Args <jv>args</jv> = <jk>new</jk> Args(<jv>argv</jv>);
046 *
047 *    <jc>// Create a variable resolver that resolves JVM arguments (e.g. "$A{1}")</jc>
048 *    VarResolver <jv>varResolver</jv> = VarResolver.<jsm>create</jsm>().vars(ArgsVar.<jsm>create</jsm>(() -&gt; <jv>args</jv>)).build();
049 *
050 *    <jc>// Use it!</jc>
051 *    System.<jsf>out</jsf>.println(<jv>varResolver</jv>.resolve(<js>"Arg #1 is set to $A{1}"</js>));
052 * </p>
053 *
054 * <p>
055 * Since this is a {@link SimpleVar}, any variables contained in the result will be recursively resolved.
056 * Likewise, if the arguments contain any variables, those will be resolved before they are passed to this var.
057 *
058 * <h5 class='section'>See Also:</h5><ul>
059 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallSimpleVariableLanguage">Marshall Simple Variable Language</a>
060 * </ul>
061 */
062public class ArgsVar extends DefaultingVar {
063
064   /** The name of this variable. */
065   public static final String NAME = "A";
066
067   /**
068    * Creates an {@link ArgsVar} bound to a per-instance {@link Supplier} of {@link Args}.
069    *
070    * <p>
071    * The supplier is invoked on every resolve, so callers can update the underlying {@link Args} between resolves if
072    * needed.
073    *
074    * @param supplier The supplier of {@link Args} for this var instance.  Must not be <jk>null</jk>.
075    * @return A new {@link ArgsVar} instance backed by the supplier.
076    */
077   public static ArgsVar create(Supplier<Args> supplier) {
078      return new ArgsVar(supplier);
079   }
080
081   private final ArgsPropertySource source;
082   private final boolean stable;
083
084   /**
085    * Constructor.
086    */
087   public ArgsVar() {
088      super(NAME);
089      this.source = new ArgsPropertySource(ArgsPropertySource::getDefaultArgs);
090      this.stable = true;
091   }
092
093   private ArgsVar(Supplier<Args> supplier) {
094      super(NAME);
095      this.source = new ArgsPropertySource(supplier);
096      // Supplier form may return updated args between resolves; opt out of stable folding.
097      this.stable = false;
098   }
099
100   @Override /* Overridden from Var */
101   public String resolve(VarResolverSession session, String key) {
102      var result = source.get(key);
103      return result.isPresent() ? result.value().orElse(null) : null;
104   }
105
106   /**
107    * Process command-line args are immutable for the lifetime of the JVM, so the no-arg
108    * constructor opts in to compile-time stable-value folding.
109    *
110    * <p>
111    * The {@link #create(Supplier)} variant returns {@code false} since the supplier may
112    * return updated args between resolves.
113    *
114    * @return {@code true} for the default no-arg constructor; {@code false} for the
115    *  {@link #create(Supplier)} variant.
116    */
117   @Override /* Overridden from Var */
118   protected boolean isStable() {
119      return stable;
120   }
121}