/** * Copyright (C) 2008 - 2014 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * icense version 2 and the aforementioned licenses. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. */ package org.n52.ses.common; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.n52.ses.util.common.ConfigurationRegistry; import org.n52.ses.util.common.SESProperties; /** * Servlet which provides access to all properties of the * {@link ConfigurationRegistry} (per se, ses_config.properties). * * It should be wrapped with a authentication mechanism inside the * web.xml. * * @author matthes rieke <m.rieke@52north.org> * */ public class ServiceConfigurationServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 8033668772111543668L; private static Set<Object> secretParameters; private static Set<Object> hiddenParameters; private static Set<Object> optionParameters; private String configDefaultsRowMarkup; private String configRowMarkup; private String html; private static final String KEY_STRING = "${key}"; private static final String VALUE_STRING = "${value}"; private static final String TYPE_STRING = "${type}"; private static final String NOTE_STRING = "${note}"; private static final String ROW_MARKUP = "<tr><td class=\"config_label\">"+KEY_STRING+"</td><td>" + "<input type=\""+TYPE_STRING+"\" name=\""+KEY_STRING+"\" value=\""+VALUE_STRING+"\" /></td>" + "<td>${note}</td></tr>"; static { /* * set some parameters as secret/hidden */ secretParameters = new HashSet<Object>(); secretParameters.add(ConfigurationRegistry.POSTGRES_PWD_KEY); secretParameters.add(ConfigurationRegistry.BASIC_AUTH_PASSWORD); hiddenParameters = new HashSet<Object>(); hiddenParameters.add(ConfigurationRegistry.USED_FILTER_ENGINE); optionParameters = new HashSet<Object>(); optionParameters.add(ConfigurationRegistry.EML_CONTROLLER); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { URL f = getClass().getResource("/"+ConfigurationRegistry.CONFIG_FILE); File file; try { file = new File(f.toURI()); } catch (URISyntaxException e) { throw new ServletException(e); } FileInputStream fis = new FileInputStream(file); Properties props = new SESProperties(); props.load(fis); if (req.getParameterMap().size() == 0) { /* * return config page */ if (this.html == null) { InputStreamReader isr = new InputStreamReader(getClass().getResourceAsStream("/config_page.html")); BufferedReader br = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); while (br.ready()) { sb.append(br.readLine()); } html = sb.toString(); isr.close(); } generateRowMarkup(props); /* * replace the rows */ synchronized (this) { String configPage = html.replace("${config_rows}", this.configRowMarkup); configPage = configPage.replace("${default_rows}", this.configDefaultsRowMarkup); String reqUrl = URLDecoder.decode(req.getRequestURL().toString(), (req.getCharacterEncoding() == null ? Charset.defaultCharset().name() : req.getCharacterEncoding())); String sesUrl = reqUrl.substring(0, reqUrl.indexOf(req.getContextPath())) + req.getContextPath(); configPage = configPage.replace("${SES_URL}", sesUrl).replace("${SES_CONFIG}", req.getServletPath()); resp.setContentType("text/html"); resp.getWriter().print(configPage.replace("${action}", req.getRequestURL().substring(0, req.getRequestURL().indexOf(req.getServletPath()))+req.getServletPath())); } } } private void generateRowMarkup(Properties props) { /* * go through the underlying keyset. * this holds all user-setted parameters */ List<String> list = new ArrayList<String>(props.stringPropertyNames()); Collections.sort(list); /* * go through the all. check if default or not. */ StringBuilder cfgSb = new StringBuilder(); StringBuilder defSb = new StringBuilder(); for (String key : list) { if (hiddenParameters.contains(key)) continue; boolean secret = secretParameters.contains(key); if (props.keySet().contains(key)) { if (optionParameters.contains(key)) { cfgSb.append(generateOneOptionMarkup(key.toString(), props.getProperty(key))); } else { cfgSb.append(generateOneRowMarkup(key.toString(), props.getProperty(key), secret)); } } else { if (optionParameters.contains(key)) { defSb.append(generateOneOptionMarkup(key.toString(), props.getProperty(key))); } else { defSb.append(generateOneRowMarkup(key, props.getProperty(key), secret)); } } } this.configRowMarkup = cfgSb.toString(); this.configDefaultsRowMarkup = defSb.toString(); } private String generateOneOptionMarkup(String key, Object value) { List<String> options = getOptionValuesForKey(key); StringBuilder sb = new StringBuilder(); sb.append("<tr><td class=\"config_label\">"); sb.append(key); sb.append("</td><td>"); sb.append("<select name=\""); sb.append(key); sb.append("\">"); for (String op : options) { sb.append("<option value=\""); sb.append(op); sb.append("\""); if (value.toString().equals(op)){ sb.append(" selected=\"selected\""); } sb.append(">"); sb.append(op); sb.append("</option>"); } sb.append("</select></td><td></td></tr>"); return sb.toString(); } private List<String> getOptionValuesForKey(String key) { List<String> result = new ArrayList<String>(); if (key.equals(ConfigurationRegistry.EML_CONTROLLER)) { result.add(ConfigurationRegistry.EML_001_IMPL); result.add(ConfigurationRegistry.EML_002_IMPL); } return result; } private String generateOneRowMarkup(String key, Object value, boolean secret) { return ROW_MARKUP.replace(KEY_STRING, key).replace(VALUE_STRING, secret ? "" : (value == null) ? "" : value.toString()) .replace(TYPE_STRING, secret ? "password" : "text") .replace(NOTE_STRING, secret ? "(security-related parameter, not provided; leave blank if you do not want to change it.)" : ""); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { URL f = getClass().getResource("/"+ConfigurationRegistry.CONFIG_FILE); File file; try { file = new File(f.toURI()); } catch (URISyntaxException e) { throw new ServletException(e); } FileInputStream fis = new FileInputStream(file); Properties props = new SESProperties(); props.load(fis); boolean changed = false; synchronized (this) { /* * check if we have any changes */ Map<?, ?> map = req.getParameterMap(); String[] tmp; for (Object key : map.keySet()) { String str; if (key != null && key instanceof String) { str = (String) key; } else continue; Object val = map.get(str); String strVal; if (val instanceof String[]) { tmp = (String[]) val; if (tmp.length > 0 ) { strVal = tmp[0]; } else continue; } else continue; /* * is it a hidden one and is it empty? * then the user did not change it */ if (secretParameters.contains(str) && strVal.trim().isEmpty()) { continue; } if (!strVal.equals(props.getProperty(str))) { changed = true; props.put(str, strVal); } } if (changed) { FileWriter fw = new FileWriter(file); props.store(fw, null); String reqUrl = URLDecoder.decode(req.getRequestURL().toString(), (req.getCharacterEncoding() == null ? Charset.defaultCharset().name() : req.getCharacterEncoding())); String reloadLink = reqUrl.substring(0, reqUrl.indexOf(req.getContextPath())) + "/manager/html/reload?path="+ req.getContextPath(); resp.setContentType("text/html"); resp.getWriter().append("<html><body><p>succesfully changed. a restart of the service is needed to make changes affect.</p>" + "<p><a href=\""+ reloadLink +"\">Click here to reload the SES webapp.</a></p></body></html>"); } else { resp.setContentType("text/html"); resp.getWriter().append("<html><body><p>no changes.</p></body></html>"); } } } }