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