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.microservice; 014 015import java.io.*; 016import java.util.*; 017import java.util.jar.*; 018import java.util.logging.*; 019 020import org.apache.juneau.config.*; 021import org.apache.juneau.config.store.*; 022import org.apache.juneau.config.vars.*; 023import org.apache.juneau.microservice.console.*; 024import org.apache.juneau.svl.*; 025import org.apache.juneau.utils.*; 026 027/** 028 * Builder for {@link Microservice} class. 029 * 030 * <p> 031 * Instances of this class are created using {@link Microservice#create()}. 032 */ 033public class MicroserviceBuilder { 034 035 Args args; 036 ManifestFile manifest; 037 Logger logger; 038 LogConfig logConfig; 039 Config config; 040 String configName; 041 ConfigStore configStore; 042 ConfigBuilder configBuilder = Config.create(); 043 Boolean consoleEnabled; 044 List<ConsoleCommand> consoleCommands = new ArrayList<>(); 045 VarResolverBuilder varResolverBuilder = VarResolver.create().defaultVars().vars(ConfigVar.class); 046 Scanner consoleReader; 047 PrintWriter consoleWriter; 048 MicroserviceListener listener; 049 050 /** 051 * Constructor. 052 */ 053 protected MicroserviceBuilder() {} 054 055 /** 056 * Copy constructor. 057 * 058 * @param copyFrom The builder to copy settings from. 059 */ 060 protected MicroserviceBuilder(MicroserviceBuilder copyFrom) { 061 this.args = copyFrom.args; 062 this.manifest = copyFrom.manifest; 063 this.logger = copyFrom.logger; 064 this.configName = copyFrom.configName; 065 this.logConfig = copyFrom.logConfig == null ? null : copyFrom.logConfig.copy(); 066 this.consoleEnabled = copyFrom.consoleEnabled; 067 this.configBuilder = copyFrom.configBuilder; 068 this.varResolverBuilder = copyFrom.varResolverBuilder; 069 this.consoleReader = copyFrom.consoleReader; 070 this.consoleWriter = copyFrom.consoleWriter; 071 } 072 073 /** 074 * Creates a copy of this builder. 075 * 076 * @return A new copy of this builder. 077 */ 078 public MicroserviceBuilder copy() { 079 return new MicroserviceBuilder(this); 080 } 081 082 /** 083 * Instantiate a new microservice using the settings defined on this builder. 084 * 085 * @return A new microservice. 086 * @throws Exception 087 */ 088 public Microservice build() throws Exception { 089 return new Microservice(this); 090 } 091 092 /** 093 * Specifies the command-line arguments passed into the Java command. 094 * 095 * <p> 096 * This is required if you use {@link Microservice#getArgs()} or <code>$A</code> string variables. 097 * 098 * @param args 099 * The command-line arguments passed into the Java command as a pre-parsed {@link Args} object. 100 * @return This object (for method chaining). 101 */ 102 public MicroserviceBuilder args(Args args) { 103 this.args = args; 104 return this; 105 } 106 107 /** 108 * Specifies the command-line arguments passed into the Java command. 109 * 110 * <p> 111 * This is required if you use {@link Microservice#getArgs()} or <code>$A</code> string variables. 112 * 113 * @param args 114 * The command-line arguments passed into the Java command as the raw command-line arguments. 115 * @return This object (for method chaining). 116 */ 117 public MicroserviceBuilder args(String...args) { 118 this.args = new Args(args); 119 return this; 120 } 121 122 /** 123 * Specifies the manifest file of the jar file this microservice is contained within. 124 * 125 * <p> 126 * This is required if you use {@link Microservice#getManifest()}. 127 * It's also used to locate initialization values such as <code>Main-Config</code>. 128 * 129 * <p> 130 * If you do not specify the manifest file, we attempt to resolve it through the following methods: 131 * <ol class='spaced-list'> 132 * <li> 133 * Looking on the file system for a file at <js>"META-INF/MANIFEST.MF"</js>. 134 * This is primarily to allow for running microservices from within eclipse workspaces where the manifest file 135 * is located in the project root. 136 * <li> 137 * Using the class loader for this class to find the file at the URL <js>"META-INF/MANIFEST.MF"</js>. 138 * </ol> 139 * 140 * @param value 141 * The manifest file of this microservice. 142 * <br>Can be any of the following types: 143 * <ul> 144 * <li>{@link ManifestFile} 145 * <li>{@link Manifest} 146 * <li>{@link Reader} - Containing the raw contents of the manifest. Note that the input must end with a newline. 147 * <li>{@link InputStream} - Containing the raw contents of the manifest. Note that the input must end with a newline. 148 * <li>{@link File} - File containing the raw contents of the manifest. 149 * <li>{@link String} - Path to file containing the raw contents of the manifest. 150 * <li>{@link Class} - Finds and loads the manifest file of the jar file that the specified class is contained within. 151 * </ul> 152 * @return This object (for method chaining). 153 * @throws IOException 154 */ 155 public MicroserviceBuilder manifest(Object value) throws IOException { 156 if (value == null) 157 this.manifest = null; 158 else if (value instanceof ManifestFile) 159 this.manifest = (ManifestFile)value; 160 else if (value instanceof Manifest) 161 this.manifest = new ManifestFile((Manifest)value); 162 else if (value instanceof Reader) 163 this.manifest = new ManifestFile((Reader)value); 164 else if (value instanceof InputStream) 165 this.manifest = new ManifestFile((InputStream)value); 166 else if (value instanceof File) 167 this.manifest = new ManifestFile((File)value); 168 else if (value instanceof String) 169 this.manifest = new ManifestFile(new File((String)value)); 170 else if (value instanceof Class) 171 this.manifest = new ManifestFile((Class<?>)value); 172 else 173 throw new RuntimeException("Invalid type passed to MicroserviceBuilder.manifest(Object). Type=["+value.getClass().getName()+"]"); 174 175 return this; 176 } 177 178 /** 179 * Specifies the logger used by the microservice and returned by the {@link Microservice#getLogger()} method. 180 * 181 * <p> 182 * Calling this method overrides the default logging mechanism controlled by the {@link #logConfig(LogConfig)} method. 183 * 184 * @param logger The logger to use for logging microservice messages. 185 * @return This object (for method chaining). 186 */ 187 public MicroserviceBuilder logger(Logger logger) { 188 this.logger = logger; 189 return this; 190 } 191 192 /** 193 * Specifies logging instructions for the microservice. 194 * 195 * <p> 196 * If not specified, the values are taken from the <js>"Logging"</js> section of the configuration. 197 * 198 * <p> 199 * This method is ignored if {@link #logger(Logger)} is used to set the microservice logger. 200 * 201 * @param logConfig The log configuration. 202 * @return This object (for method chaining). 203 */ 204 public MicroserviceBuilder logConfig(LogConfig logConfig) { 205 this.logConfig = logConfig; 206 return this; 207 } 208 209 /** 210 * Specifies the config for initializing this microservice. 211 * 212 * <p> 213 * Calling this method overrides the default configuration controlled by the {@link #configName(String)} and {@link #configStore(ConfigStore)} methods. 214 * 215 * @param config The configuration. 216 * @return This object (for method chaining). 217 */ 218 public MicroserviceBuilder config(Config config) { 219 this.config = config; 220 return this; 221 } 222 223 /** 224 * Specifies the config name for initializing this microservice. 225 * 226 * <p> 227 * If you do not specify the config file location, we attempt to resolve it through the following methods: 228 * <ol class='spaced-list'> 229 * <li> 230 * Resolve file first in working directory, then in classpath, using the following names: 231 * <ul> 232 * <li> 233 * The <js>"configFile"</js> argument in the command line arguments passed in through the constructor. 234 * <li> 235 * The value of the <code>Main-Config</code> entry in the manifest file. 236 * <li> 237 * A config file in the same location and with the same name as the executable jar file. 238 * (e.g. <js>"java -jar myjar.jar"</js> will look for <js>"myjar.cfg"</js>). 239 * </ul> 240 * <li> 241 * Resolve any <js>"*.cfg"</js> file that can be found in the working directory. 242 * <li> 243 * Resolve any of the following files in the classpath: <js>"juneau.cfg"</js>, <js>"system.cfg"</js> 244 * </ol> 245 * 246 * <p> 247 * If no configuration file is found, and empty in-memory configuration is used. 248 * 249 * @param configName The configuration name. 250 * @return This object (for method chaining). 251 */ 252 public MicroserviceBuilder configName(String configName) { 253 this.configName = configName; 254 return this; 255 } 256 257 /** 258 * Specifies the config store to use for storing and retrieving configurations. 259 * 260 * <p> 261 * By default, we use a {@link ConfigFileStore} store for configuration files. 262 * 263 * @param configStore The configuration name. 264 * @return This object (for method chaining). 265 */ 266 public MicroserviceBuilder configStore(ConfigStore configStore) { 267 this.configStore = configStore; 268 return this; 269 } 270 271 /** 272 * Specifies that the Java console is enabled for this microservice. 273 * 274 * <p> 275 * If not specified, this value is taken from the <js>"Console/enabled"</js> configuration setting. 276 * If not specified in the configuration, defaults to <jk>false</jk>. 277 * 278 * @param consoleEnabled <jk>true</jk> if the Java console is enabled for this microservice. 279 * @return This object (for method chaining). 280 */ 281 public MicroserviceBuilder consoleEnabled(boolean consoleEnabled) { 282 this.consoleEnabled = consoleEnabled; 283 return this; 284 } 285 286 /** 287 * Specifies console commands to make available on the Java console. 288 * 289 * <p> 290 * Note that these are ignored if the console is not enabled via {@link #consoleEnabled(boolean)}. 291 * 292 * <p> 293 * This list augments the commands defined via the <js>"Console/commands"</js> configuration setting. 294 * 295 * <p> 296 * This method can only be used on console commands with no-arg constructors. 297 * 298 * @param consoleCommands The list of console commands to append to the list of available commands. 299 * @return This object (for method chaining). 300 * @throws IllegalAccessException 301 * @throws InstantiationException 302 */ 303 @SuppressWarnings("unchecked") 304 public MicroserviceBuilder consoleCommands(Class<? extends ConsoleCommand>...consoleCommands) throws InstantiationException, IllegalAccessException { 305 for (Class<? extends ConsoleCommand> cc : consoleCommands) 306 this.consoleCommands.add(cc.newInstance()); 307 return this; 308 } 309 310 /** 311 * Specifies console commands to make available on the Java console. 312 * 313 * <p> 314 * Note that these are ignored if the console is not enabled via {@link #consoleEnabled(boolean)}. 315 * 316 * <p> 317 * This list augments the commands defined via the <js>"Console/commands"</js> configuration setting. 318 * 319 * @param consoleCommands The list of console commands to append to the list of available commands. 320 * @return This object (for method chaining). 321 */ 322 public MicroserviceBuilder consoleCommands(ConsoleCommand...consoleCommands) { 323 this.consoleCommands.addAll(Arrays.asList(consoleCommands)); 324 return this; 325 } 326 327 /** 328 * Specifies the console input and output. 329 * 330 * <p> 331 * If not specified, uses the console returned by {@link System#console()}. 332 * If that is not available, uses {@link System#in} and {@link System#out}. 333 * 334 * <p> 335 * Note that these are ignored if the console is not enabled via {@link #consoleEnabled(boolean)}. 336 * 337 * @param consoleReader The console input. 338 * @param consoleWriter The console output. 339 * @return This object (for method chaining). 340 */ 341 public MicroserviceBuilder console(Scanner consoleReader, PrintWriter consoleWriter) { 342 this.consoleReader = consoleReader; 343 this.consoleWriter = consoleWriter; 344 return this; 345 } 346 347 /** 348 * Augments the set of variables defined in the configuration and var resolver. 349 * 350 * <p> 351 * This calls {@link VarResolverBuilder#vars(Class[])} on the var resolver used to construct the configuration 352 * object returned by {@link Microservice#getConfig()} and the var resolver returned by {@link Microservice#getVarResolver()}. 353 * 354 * @param vars The set of variables to append to the var resolver builder. 355 * @return This object (for method chaining). 356 */ 357 @SuppressWarnings("unchecked") 358 public MicroserviceBuilder vars(Class<? extends Var>...vars) { 359 varResolverBuilder.vars(vars); 360 return this; 361 } 362 363 /** 364 * Adds a var resolver context object for vars defined in the configuration and var resolver. 365 * 366 * <p> 367 * This calls {@link VarResolverBuilder#contextObject(String,Object)} on the var resolver used to construct the configuration 368 * object returned by {@link Microservice#getConfig()} and the var resolver returned by {@link Microservice#getVarResolver()}. 369 * 370 * @param name The context object name. 371 * @param object The context object. 372 * @return This object (for method chaining). 373 */ 374 public MicroserviceBuilder varContext(String name, Object object) { 375 varResolverBuilder.contextObject(name, object); 376 return this; 377 } 378 379 /** 380 * Registers an event listener for this microservice. 381 * 382 * @param listener An event listener for this microservice. 383 * @return This object (for method chaining). 384 */ 385 public MicroserviceBuilder listener(MicroserviceListener listener) { 386 this.listener = listener; 387 return this; 388 } 389}