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.jetty; 014 015import java.io.*; 016import java.util.*; 017import java.util.logging.*; 018 019import javax.servlet.*; 020 021import org.apache.juneau.*; 022import org.apache.juneau.config.*; 023import org.apache.juneau.config.store.*; 024import org.apache.juneau.internal.*; 025import org.apache.juneau.microservice.*; 026import org.apache.juneau.microservice.console.*; 027import org.apache.juneau.rest.*; 028import org.apache.juneau.rest.annotation.*; 029import org.apache.juneau.svl.*; 030import org.apache.juneau.utils.*; 031import org.eclipse.jetty.server.*; 032 033/** 034 * Builder for {@link JettyMicroservice} class. 035 * 036 * <p> 037 * Instances of this class are created using {@link JettyMicroservice#create()}. 038 */ 039public class JettyMicroserviceBuilder extends MicroserviceBuilder { 040 041 String jettyXml; 042 int[] ports; 043 Boolean jettyXmlResolveVars; 044 Map<String,Servlet> servlets = new LinkedHashMap<>(); 045 Map<String,Object> servletAttributes = new LinkedHashMap<>(); 046 JettyMicroserviceListener listener; 047 JettyServerFactory factory; 048 049 /** 050 * Constructor. 051 */ 052 protected JettyMicroserviceBuilder() {} 053 054 /** 055 * Copy constructor. 056 * 057 * @param copyFrom The builder to copy settings from. 058 */ 059 protected JettyMicroserviceBuilder(JettyMicroserviceBuilder copyFrom) { 060 super(copyFrom); 061 this.jettyXml = copyFrom.jettyXml; 062 this.ports = copyFrom.ports; 063 this.jettyXmlResolveVars = copyFrom.jettyXmlResolveVars; 064 this.servlets = new LinkedHashMap<>(copyFrom.servlets); 065 this.servletAttributes = new LinkedHashMap<>(copyFrom.servletAttributes); 066 this.listener = copyFrom.listener; 067 } 068 069 @Override /* MicroserviceBuilder */ 070 public JettyMicroserviceBuilder copy() { 071 return new JettyMicroserviceBuilder(this); 072 } 073 074 /** 075 * Specifies the contents or location of the <c>jetty.xml</c> file used by the Jetty server. 076 * 077 * <p> 078 * If you do not specify this value, it is pulled from the following in the specified order: 079 * <ul class='spaced-list'> 080 * <li> 081 * <c>Jetty/config</c> setting in the config file. 082 * <c>Jetty-Config</c> setting in the manifest file. 083 * </ul> 084 * 085 * <p> 086 * By default, we look for the <c>jetty.xml</c> file in the following locations: 087 * <ul class='spaced-list'> 088 * <li><c>jetty.xml</c> in home directory. 089 * <li><c>files/jetty.xml</c> in home directory. 090 * <li><c>/jetty.xml</c> in classpath. 091 * <li><c>/files/jetty.xml</c> in classpath. 092 * </ul> 093 * 094 * @param jettyXml 095 * The contents or location of the file. 096 * <br>Can be any of the following: 097 * <ul> 098 * <li>{@link String} - Relative path to file on file system or classpath. 099 * <li>{@link File} - File on file system. 100 * <li>{@link InputStream} - Raw contents as <c>UTF-8</c> encoded stream. 101 * <li>{@link Reader} - Raw contents. 102 * </ul> 103 * 104 * @param resolveVars 105 * If <jk>true</jk>, SVL variables in the file will automatically be resolved. 106 * @return This object (for method chaining). 107 * @throws IOException Thrown by underlying stream. 108 */ 109 public JettyMicroserviceBuilder jettyXml(Object jettyXml, boolean resolveVars) throws IOException { 110 if (jettyXml instanceof String) 111 this.jettyXml = IOUtils.read(resolveFile(jettyXml.toString())); 112 else if (jettyXml instanceof File) 113 this.jettyXml = IOUtils.read((File)jettyXml); 114 else if (jettyXml instanceof InputStream) 115 this.jettyXml = IOUtils.read((InputStream)jettyXml); 116 else if (jettyXml instanceof Reader) 117 this.jettyXml = IOUtils.read((Reader)jettyXml); 118 else 119 throw new FormattedRuntimeException("Invalid object type passed to jettyXml(Object)", jettyXml == null ? null : jettyXml.getClass().getName()); 120 this.jettyXmlResolveVars = resolveVars; 121 return this; 122 } 123 124 /** 125 * Specifies the ports to use for the web server. 126 * 127 * <p> 128 * You can specify multiple ports. The first available will be used. <js>'0'</js> indicates to try a random port. 129 * The resulting available port gets set as the system property <js>"availablePort"</js> which can be referenced in the 130 * <c>jetty.xml</c> file as <js>"$S{availablePort}"</js> (assuming resolveVars is enabled). 131 * 132 * <p> 133 * If you do not specify this value, it is pulled from the following in the specified order: 134 * <ul class='spaced-list'> 135 * <li> 136 * <c>Jetty/port</c> setting in the config file. 137 * <li> 138 * <c>Jetty-Port</c> setting in the manifest file. 139 * <li> 140 * <c>8000</c> 141 * </ul> 142 * 143 * Jetty/port", mf.getWithDefault("Jetty-Port", new int[]{8000} 144 * @param ports The ports to use for the web server. 145 * @return This object (for method chaining). 146 */ 147 public JettyMicroserviceBuilder ports(int...ports) { 148 this.ports = ports; 149 return this; 150 } 151 152 /** 153 * Adds a servlet to the servlet container. 154 * 155 * <p> 156 * This method can only be used with servlets with no-arg constructors. 157 * <br>The path is pulled from the {@link Rest#path()} annotation. 158 * 159 * @param c The servlet to add to the servlet container. 160 * @return This object (for method chaining). 161 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 162 */ 163 public JettyMicroserviceBuilder servlet(Class<? extends RestServlet> c) throws ExecutableException { 164 RestServlet rs; 165 try { 166 rs = c.newInstance(); 167 } catch (InstantiationException | IllegalAccessException e) { 168 throw new ExecutableException(e); 169 } 170 return servlet(rs, '/' + rs.getPath()); 171 } 172 173 /** 174 * Adds a servlet to the servlet container. 175 * 176 * <p> 177 * This method can only be used with servlets with no-arg constructors. 178 * 179 * @param c The servlet to add to the servlet container. 180 * @param path The servlet path spec. 181 * @return This object (for method chaining). 182 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 183 */ 184 public JettyMicroserviceBuilder servlet(Class<? extends Servlet> c, String path) throws ExecutableException { 185 try { 186 return servlet(c.newInstance(), path); 187 } catch (InstantiationException | IllegalAccessException e) { 188 throw new ExecutableException(e); 189 } 190 } 191 192 /** 193 * Adds a servlet instance to the servlet container. 194 * 195 * @param servlet The servlet to add to the servlet container. 196 * @param path The servlet path spec. 197 * @return This object (for method chaining). 198 */ 199 public JettyMicroserviceBuilder servlet(Servlet servlet, String path) { 200 servlets.put(path, servlet); 201 return this; 202 } 203 204 /** 205 * Adds a set of servlets to the servlet container. 206 * 207 * @param servlets 208 * A map of servlets to add to the servlet container. 209 * <br>Keys are path specs for the servlet. 210 * @return This object (for method chaining). 211 */ 212 public JettyMicroserviceBuilder servlets(Map<String,Servlet> servlets) { 213 if (servlets != null) 214 this.servlets.putAll(servlets); 215 return this; 216 } 217 218 /** 219 * Adds a servlet attribute to the servlet container. 220 * 221 * @param name The attribute name. 222 * @param value The attribute value. 223 * @return This object (for method chaining). 224 */ 225 public JettyMicroserviceBuilder servletAttribute(String name, Object value) { 226 this.servletAttributes.put(name, value); 227 return this; 228 } 229 230 /** 231 * Adds a set of servlet attributes to the servlet container. 232 * 233 * @param values The map of attributes. 234 * @return This object (for method chaining). 235 */ 236 public JettyMicroserviceBuilder servletAttribute(Map<String,Object> values) { 237 if (values != null) 238 this.servletAttributes.putAll(values); 239 return this; 240 } 241 242 /** 243 * Specifies the factory to use for creating the Jetty {@link Server} instance. 244 * 245 * <p> 246 * If not specified, uses {@link BasicJettyServerFactory}. 247 * 248 * @param value The new value for this property. 249 * @return This object (for method chaining). 250 */ 251 public JettyMicroserviceBuilder jettyServerFactory(JettyServerFactory value) { 252 this.factory = value; 253 return this; 254 } 255 256 //----------------------------------------------------------------------------------------------------------------- 257 // Inherited from MicroserviceBuilder 258 //----------------------------------------------------------------------------------------------------------------- 259 260 @Override /* MicroserviceBuilder */ 261 public JettyMicroservice build() throws Exception { 262 return new JettyMicroservice(this); 263 } 264 265 @Override /* MicroserviceBuilder */ 266 public JettyMicroserviceBuilder args(Args args) { 267 super.args(args); 268 return this; 269 } 270 271 @Override /* MicroserviceBuilder */ 272 public JettyMicroserviceBuilder args(String...args) { 273 super.args(args); 274 return this; 275 } 276 277 @Override /* MicroserviceBuilder */ 278 public JettyMicroserviceBuilder manifest(Object manifest) throws IOException { 279 super.manifest(manifest); 280 return this; 281 } 282 283 @Override /* MicroserviceBuilder */ 284 public JettyMicroserviceBuilder logger(Logger logger) { 285 super.logger(logger); 286 return this; 287 } 288 289 @Override /* MicroserviceBuilder */ 290 public JettyMicroserviceBuilder logConfig(LogConfig logConfig) { 291 return this; 292 } 293 294 @Override /* MicroserviceBuilder */ 295 public JettyMicroserviceBuilder config(Config config) { 296 super.config(config); 297 return this; 298 } 299 300 @Override /* MicroserviceBuilder */ 301 public JettyMicroserviceBuilder configName(String configName) { 302 super.configName(configName); 303 return this; 304 } 305 306 @Override /* MicroserviceBuilder */ 307 public JettyMicroserviceBuilder configStore(ConfigStore configStore) { 308 super.configStore(configStore); 309 return this; 310 } 311 312 @Override /* MicroserviceBuilder */ 313 public JettyMicroserviceBuilder consoleEnabled(boolean consoleEnabled) { 314 super.consoleEnabled(consoleEnabled); 315 return this; 316 } 317 318 @Override /* MicroserviceBuilder */ 319 public JettyMicroserviceBuilder consoleCommands(ConsoleCommand...consoleCommands) { 320 super.consoleCommands(consoleCommands); 321 return this; 322 } 323 324 @Override /* MicroserviceBuilder */ 325 public JettyMicroserviceBuilder console(Scanner consoleReader, PrintWriter consoleWriter) { 326 super.console(consoleReader, consoleWriter); 327 return this; 328 } 329 330 @Override /* MicroserviceBuilder */ 331 @SuppressWarnings("unchecked") 332 public JettyMicroserviceBuilder vars(Class<? extends Var>...vars) { 333 super.vars(vars); 334 return this; 335 } 336 337 @Override /* MicroserviceBuilder */ 338 public JettyMicroserviceBuilder varContext(String name, Object object) { 339 super.varContext(name, object); 340 return this; 341 } 342 343 @Override /* MicroserviceBuilder */ 344 public JettyMicroserviceBuilder workingDir(File path) { 345 super.workingDir(path); 346 return this; 347 } 348 349 @Override /* MicroserviceBuilder */ 350 public JettyMicroserviceBuilder workingDir(String path) { 351 super.workingDir(path); 352 return this; 353 } 354 355 /** 356 * Registers an event listener for this microservice. 357 * 358 * @param listener An event listener for this microservice. 359 * @return This object (for method chaining). 360 */ 361 public JettyMicroserviceBuilder listener(JettyMicroserviceListener listener) { 362 super.listener(listener); 363 this.listener = listener; 364 return this; 365 } 366}