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