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