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.resources; 014 015import static org.apache.juneau.dto.html5.HtmlBuilder.*; 016 017import java.io.*; 018import java.util.Map; 019 020import org.apache.juneau.annotation.*; 021import org.apache.juneau.collections.*; 022import org.apache.juneau.dto.html5.*; 023import org.apache.juneau.html.annotation.*; 024import org.apache.juneau.http.annotation.*; 025import org.apache.juneau.http.annotation.Content; 026import org.apache.juneau.http.response.*; 027import org.apache.juneau.rest.annotation.*; 028import org.apache.juneau.rest.servlet.*; 029 030/** 031 * Shows contents of the microservice configuration file. 032 * 033 * <h5 class='section'>See Also:</h5><ul> 034 * <li class='link'><a class="doclink" href="../../../../../index.html#juneau-microservice-core">juneau-microservice-core</a> 035 * </ul> 036 * 037 * @serial exclude 038 */ 039@Rest( 040 path="/config", 041 title="Configuration", 042 description="Contents of configuration file." 043) 044@HtmlDocConfig( 045 navlinks={ 046 "up: request:/..", 047 "api: servlet:/api", 048 "stats: servlet:/stats", 049 "edit: servlet:/edit" 050 }, 051 resolveBodyVars="true" 052) 053@SuppressWarnings("javadoc") 054public class ConfigResource extends BasicRestServlet { 055 private static final long serialVersionUID = 1L; 056 057 @RestGet( 058 path="/", 059 summary="Get config file contents", 060 description="Show contents of config file as a JsonMap.", 061 swagger=@OpSwagger( 062 responses={ 063 "200:{ description:'Config file as a map of map of objects.', example:{'':{defaultKey:'defaultValue'},'Section1':{key1:'val1',key2:123}}}" 064 } 065 ) 066 ) 067 public JsonMap getConfig() { 068 return getContext().getConfig().toMap(); 069 } 070 071 @RestGet( 072 path="/edit", 073 summary="Render form entry page for editing config file", 074 description="Renders a form entry page for editing the raw text of a config file." 075 ) 076 public Form getConfigEditForm() { 077 return form().id("form").action("servlet:/").method("POST").enctype("application/x-www-form-urlencoded").children( 078 div()._class("data").children( 079 table( 080 tr(td().style("text-align:right").children(button("submit","Submit"),button("reset","Reset"))), 081 tr(th().child("Contents")), 082 tr(th().child( 083 textarea().name("contents").rows(40).cols(120).style("white-space:pre;word-wrap:normal;overflow-x:scroll;font-family:monospace;") 084 .text(getContext().getConfig().toString())) 085 ) 086 ) 087 ) 088 ); 089 } 090 091 @RestGet( 092 path="/{section}", 093 summary="Get config file section contents", 094 description="Show contents of config file section as a JsonMap.", 095 swagger=@OpSwagger( 096 responses={ 097 "200:{ description:'Config file section as a map of objects.', example:{key1:'val1',key2:123}}" 098 } 099 ) 100 ) 101 public JsonMap getConfigSection( 102 @Path("section") @Schema(d="Section name in config file.") String section 103 ) throws SectionNotFound { 104 105 return getSection(section); 106 } 107 108 @RestGet( 109 path="/{section}/{key}", 110 summary="Get config file entry value", 111 description="Show value of config file entry as a simple string.", 112 swagger=@OpSwagger( 113 responses={ 114 "200:{ description:'Entry value.', example:'servlet:/htdocs/themes/dark.css'}" 115 } 116 ) 117 ) 118 public String getConfigEntry( 119 @Path("section") @Schema(d="Section name in config file.") String section, 120 @Path("key") @Schema(d="Key name in section.") String key 121 ) throws SectionNotFound { 122 123 return getSection(section).getString(key); 124 } 125 126 @RestPost( 127 path="/", 128 summary="Update config file contents", 129 description="Update the contents of the config file from a FORM post.", 130 swagger=@OpSwagger( 131 responses={ 132 "200:{ description:'Config file section as a map of objects.', example:{key1:'val1',key2:123}}" 133 } 134 ) 135 ) 136 public JsonMap setConfigContentsFormPost( 137 @FormData("contents") @Schema(d="New contents in INI file format.") String contents 138 ) throws Exception { 139 140 return setConfigContents(new StringReader(contents)); 141 } 142 143 @RestPut( 144 path="/", 145 summary="Update config file contents", 146 description="Update the contents of the config file from raw text.", 147 swagger=@OpSwagger( 148 responses={ 149 "200:{ description:'Config file section as a map of objects.', example:{key1:'val1',key2:123}}" 150 } 151 ) 152 ) 153 public JsonMap setConfigContents( 154 @Content @Schema(d="New contents in INI file format.") Reader contents 155 ) throws Exception { 156 157 return getContext().getConfig().load(contents, true).toMap(); 158 } 159 160 @RestPut( 161 path="/{section}", 162 summary="Update config section contents", 163 description="Add or overwrite a config file section.", 164 swagger=@OpSwagger( 165 responses={ 166 "200:{ description:'Config file section as a map of objects.', example:{key1:'val1',key2:123}}" 167 } 168 ) 169 ) 170 public JsonMap setConfigSection( 171 @Path("section") @Schema(d="Section name in config file.") String section, 172 @Content @Schema(d="New contents of config section as a simple map of key/value pairs.") 173 Map<String,Object> contents 174 ) throws Exception { 175 176 getContext().getConfig().setSection(section, null, contents); 177 return getSection(section); 178 } 179 180 @RestPut( 181 path="/{section}/{key}", 182 summary="Update config entry value", 183 description="Add or overwrite a config file entry.", 184 swagger=@OpSwagger( 185 responses={ 186 "200:{ description:'The updated value.', example:'servlet:/htdocs/themes/dark.css'}" 187 } 188 ) 189 ) 190 public String setConfigValue( 191 @Path("section") @Schema(d="Section name in config file.") String section, 192 @Path("key") @Schema(d="Key name in section.") String key, 193 @Content @Schema(d="New value for entry.") String value 194 ) throws SectionNotFound { 195 196 getContext().getConfig().set(section + '/' + key, value); 197 return getSection(section).getString(key); 198 } 199 200 //----------------------------------------------------------------------------------------------------------------- 201 // Helper beans 202 //----------------------------------------------------------------------------------------------------------------- 203 204 @Response @Schema(description="Section not found.") 205 private class SectionNotFound extends NotFound { 206 private static final long serialVersionUID = 1L; 207 208 SectionNotFound() { 209 super("Section not found."); 210 } 211 } 212 213 //----------------------------------------------------------------------------------------------------------------- 214 // Helper methods 215 //----------------------------------------------------------------------------------------------------------------- 216 217 private JsonMap getSection(String name) throws SectionNotFound { 218 return getContext().getConfig().getSection(name).asMap().orElseThrow(SectionNotFound::new); 219 } 220}