001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.svl; 014 015import java.io.*; 016import java.util.*; 017 018import org.apache.juneau.svl.vars.*; 019 020/** 021 * Utility class for resolving variables of the form <js>"$X{key}"</js> in strings. 022 * 023 * <p> 024 * Variables are of the form <code>$X{key}</code>, where <code>X</code> can consist of zero or more ASCII characters. 025 * <br>The variable key can contain anything, even nested variables that get recursively resolved. 026 * 027 * <p> 028 * Variables are defined through the {@link VarResolverBuilder#vars(Class[])} method. 029 * 030 * <p> 031 * The {@link Var} interface defines how variables are converted to values. 032 * 033 * <h5 class='section'>Example:</h5> 034 * <p class='bcode'> 035 * <jk>public class</jk> SystemPropertiesVar <jk>extends</jk> SimpleVar { 036 * 037 * <jc>// Must have a no-arg constructor!</jc> 038 * <jk>public</jk> SystemPropertiesVar() { 039 * <jk>super</jk>(<js>"S"</js>); 040 * } 041 * 042 * <ja>@Override</ja> 043 * <jk>public</jk> String resolve(VarResolverSession session, String varVal) { 044 * <jk>return</jk> System.<jsm>getProperty</jsm>(varVal); 045 * } 046 * } 047 * 048 * <jc>// Create a variable resolver that resolves system properties (e.g. "$S{java.home}")</jc> 049 * VarResolver r = VarResolver.<jsm>create</jsm>().vars(SystemPropertiesVar.<jk>class</jk>).build(); 050 * 051 * <jc>// Use it!</jc> 052 * System.<jsf>out</jsf>.println(r.resolve(<js>"java.home is set to $S{java.home}"</js>)); 053 * </p> 054 * 055 * <h5 class='section'>See Also:</h5> 056 * <ul> 057 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-svl.VarResolvers">Overview > juneau-svl > VarResolvers and VarResolverSessions</a> 058 * </ul> 059 */ 060public class VarResolver { 061 062 /** 063 * Default string variable resolver with support for system properties and environment variables: 064 * 065 * <ul> 066 * <li><code>$S{key[,default]}</code> - {@link SystemPropertiesVar} 067 * <li><code>$E{key[,default]}</code> - {@link EnvVariablesVar} 068 * <li><code>$A{key[,default]}</code> - {@link ArgsVar} 069 * <li><code>$MF{key[,default]}</code> - {@link ManifestFileVar} 070 * <li><code>$IF{arg,then[,else]}</code> - {@link IfVar} 071 * <li><code>$SW{arg,pattern1:then1[,pattern2:then2...]}</code> - {@link SwitchVar} 072 * <li><code>$CO{arg[,arg2...]}</code> - {@link CoalesceVar} 073 * <li><code>$PM{arg,pattern}</code> - {@link PatternMatchVar} 074 * <li><code>$UC{arg}</code> - {@link UpperCaseVar} 075 * <li><code>$LC{arg}</code> - {@link LowerCaseVar} 076 * <li><code>$NE{arg}</code> - {@link NotEmptyVar} 077 * </ul> 078 * 079 * @see SystemPropertiesVar 080 * @see EnvVariablesVar 081 */ 082 public static final VarResolver DEFAULT = new VarResolverBuilder().defaultVars().build(); 083 084 final VarResolverContext ctx; 085 086 /** 087 * Instantiates a new clean-slate {@link VarResolverBuilder} object. 088 * 089 * <p> 090 * This is equivalent to simply calling <code><jk>new</jk> VarResolverBuilder()</code>. 091 * 092 * @return A new {@link VarResolverBuilder} object. 093 */ 094 public static VarResolverBuilder create() { 095 return new VarResolverBuilder(); 096 } 097 098 /** 099 * Constructor. 100 * 101 * @param vars The var classes 102 * @param contextObjects 103 */ 104 VarResolver(Class<? extends Var>[] vars, Map<String,Object> contextObjects) { 105 this.ctx = new VarResolverContext(vars, contextObjects); 106 } 107 108 /** 109 * Returns a new builder object using the settings in this resolver as a base. 110 * 111 * @return A new var resolver builder. 112 */ 113 public VarResolverBuilder builder() { 114 return new VarResolverBuilder() 115 .vars(ctx.getVars()) 116 .contextObjects(ctx.getContextObjects()); 117 } 118 119 /** 120 * Returns the read-only properties on this variable resolver. 121 * 122 * @return The read-only properties on this variable resolver. 123 */ 124 public VarResolverContext getContext() { 125 return ctx; 126 } 127 128 /** 129 * Creates a new resolver session with no session objects. 130 * 131 * <p> 132 * Session objects can be associated with the specified session using the {@link VarResolverSession#sessionObject(String, Object)} 133 * method. 134 * 135 * @return A new resolver session. 136 */ 137 public VarResolverSession createSession() { 138 return new VarResolverSession(ctx, null); 139 } 140 141 /** 142 * Same as {@link #createSession()} except allows you to specify session objects as a map. 143 * 144 * @param sessionObjects The session objects to associate with the session. 145 * @return A new resolver session. 146 */ 147 public VarResolverSession createSession(Map<String,Object> sessionObjects) { 148 return new VarResolverSession(ctx, sessionObjects); 149 } 150 151 /** 152 * Resolve variables in the specified string. 153 * 154 * <p> 155 * This is a shortcut for calling <code>createSession(<jk>null</jk>).resolve(s);</code>. 156 * <br>This method can only be used if the string doesn't contain variables that rely on the existence of session 157 * variables. 158 * 159 * @param s The input string. 160 * @return The string with variables resolved, or the same string if it doesn't contain any variables to resolve. 161 */ 162 public String resolve(String s) { 163 return createSession(null).resolve(s); 164 } 165 166 /** 167 * Resolve variables in the specified string and sends the results to the specified writer. 168 * 169 * <p> 170 * This is a shortcut for calling <code>createSession(<jk>null</jk>).resolveTo(s, w);</code>. 171 * <br>This method can only be used if the string doesn't contain variables that rely on the existence of session 172 * variables. 173 * 174 * @param s The input string. 175 * @param w The writer to send the result to. 176 * @throws IOException 177 */ 178 public void resolveTo(String s, Writer w) throws IOException { 179 createSession(null).resolveTo(s, w); 180 } 181}