001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.ui.apps.sitemanager; 033 034import org.opencms.file.CmsObject; 035import org.opencms.letsencrypt.CmsLetsEncryptConfiguration; 036import org.opencms.letsencrypt.CmsSiteConfigToLetsEncryptConfigConverter; 037import org.opencms.main.CmsLog; 038import org.opencms.main.OpenCms; 039import org.opencms.report.A_CmsReportThread; 040import org.opencms.report.I_CmsReport; 041import org.opencms.site.CmsSite; 042import org.opencms.site.CmsSiteMatcher; 043import org.opencms.ui.apps.Messages; 044import org.opencms.util.CmsStringUtil; 045 046import java.io.BufferedReader; 047import java.io.File; 048import java.io.FilenameFilter; 049import java.io.IOException; 050import java.io.InputStreamReader; 051import java.util.ArrayList; 052import java.util.LinkedList; 053import java.util.List; 054 055import org.apache.commons.io.FileUtils; 056import org.apache.commons.logging.Log; 057 058import org.antlr.stringtemplate.StringTemplate; 059 060/** 061 * Executes a script file.<p> 062 * 063 * @since 9.0.0 064 */ 065public class CmsSitesWebserverThread extends A_CmsReportThread { 066 067 /** The logger for this class. */ 068 static Log LOG = CmsLog.getLog(CmsSitesWebserverThread.class.getName()); 069 070 /** Constant for the "http" port. */ 071 private static final int PORT_HTTP = 80; 072 073 /** Constant for the "https" port. */ 074 private static final int PORT_HTTPS = 443; 075 076 /** The file path. */ 077 private String m_filePrefix; 078 079 /** The logging directory. */ 080 private String m_loggingDir; 081 082 /** The script path. */ 083 private String m_scriptPath; 084 085 /** The template to be used for secure site configurations. */ 086 private String m_secureTemplate; 087 088 /** The target path. */ 089 private String m_targetPath; 090 091 /** The template path. */ 092 private String m_templatePath; 093 094 /** The files that have been written. */ 095 private List<String> m_writtenFiles = new ArrayList<String>(); 096 097 /** 098 * Public constructor.<p> 099 * 100 * @param cms the cms object 101 * @param targetPath the target path 102 * @param templatePath the template path 103 * @param scriptPath the script path 104 * @param filePrefix the filename prefix 105 * @param loggingDir the logging directory 106 * @param secureTemplate the secure template 107 */ 108 public CmsSitesWebserverThread( 109 CmsObject cms, 110 String targetPath, 111 String templatePath, 112 String scriptPath, 113 String filePrefix, 114 String loggingDir, 115 String secureTemplate) { 116 117 super(cms, "write-to-webserver"); 118 119 if (targetPath != null) { 120 m_targetPath = targetPath.endsWith(File.separator) ? targetPath : targetPath + File.separator; 121 } 122 m_templatePath = templatePath; 123 m_scriptPath = scriptPath; 124 m_filePrefix = filePrefix; 125 m_loggingDir = loggingDir; 126 m_secureTemplate = secureTemplate; 127 initHtmlReport(cms.getRequestContext().getLocale()); 128 } 129 130 /** 131 * @see org.opencms.report.A_CmsReportThread#getReportUpdate() 132 */ 133 @Override 134 public String getReportUpdate() { 135 136 return getReport().getReportUpdate(); 137 } 138 139 /** 140 * @see java.lang.Thread#run() 141 */ 142 @Override 143 public void run() { 144 145 LOG.info( 146 "INFO thread for run of server script started by User: " 147 + getCms().getRequestContext().getCurrentUser().getName()); 148 if (CmsSiteManager.isLetsEncryptConfiguredForWebserverThread()) { 149 updateLetsEncrypt(); 150 } else { 151 try { 152 deleteAllWebserverConfigs(m_filePrefix); 153 createAllWebserverConfigs(); 154 executeScript(); 155 LOG.info("INFO server script finished successfully"); 156 } catch (Exception e) { 157 LOG.error("Exception on run CmsSitesWebserverThread", e); 158 getReport().println(e); 159 } 160 LOG.info("INFO server script thread closed"); 161 } 162 } 163 164 /** 165 * Creates the new web server configuration files from the given template file.<p> 166 * 167 * @throws IOException if something goes wrong 168 */ 169 private void createAllWebserverConfigs() throws IOException { 170 171 List<CmsSite> sites = OpenCms.getSiteManager().getAvailableSites(getCms(), true); 172 for (CmsSite site : sites) { 173 if ((site.getSiteMatcher() != null) && site.isWebserver()) { 174 175 String filename = m_targetPath 176 + m_filePrefix 177 + "_" 178 + generateWebserverConfigName(site.getSiteMatcher(), "_"); 179 getReport().println( 180 Messages.get().container(Messages.RPT_CREATING_CONFIG_FOR_SITE_2, filename, site), 181 I_CmsReport.FORMAT_OK); 182 File newFile = new File(filename); 183 if (!newFile.exists()) { 184 newFile.getParentFile().mkdirs(); 185 newFile.createNewFile(); 186 } 187 188 String content = createConfigForSite(site, FileUtils.readFileToString(new File(m_templatePath))); 189 if (site.hasSecureServer()) { 190 content += createConfigForSite(site, FileUtils.readFileToString(new File(m_secureTemplate))); 191 } 192 193 FileUtils.writeStringToFile(newFile, content); 194 m_writtenFiles.add(newFile.getAbsolutePath()); 195 } 196 } 197 } 198 199 /** 200 * Performs the template handling and returns the content.<p> 201 * 202 * @param site the site 203 * @param templateContent the configuration template content 204 * 205 * @return the file content for the configuration as String 206 */ 207 private String createConfigForSite(CmsSite site, String templateContent) { 208 209 StringTemplate config = new StringTemplate(templateContent); 210 211 // system info 212 String webappPath = OpenCms.getSystemInfo().getWebApplicationRfsPath(); 213 config.setAttribute("DOCUMENT_ROOT", webappPath.substring(0, webappPath.length() - 1)); 214 config.setAttribute("WEBAPP_NAME", OpenCms.getSystemInfo().getWebApplicationName()); 215 config.setAttribute("CONTEXT_PATH", OpenCms.getSystemInfo().getContextPath()); 216 config.setAttribute("SERVLET_PATH", OpenCms.getSystemInfo().getServletPath()); 217 config.setAttribute("DEFAULT_ENCODING", OpenCms.getSystemInfo().getDefaultEncoding()); 218 config.setAttribute("CONFIG_FILENAME", generateWebserverConfigName(site.getSiteMatcher(), "_")); 219 config.setAttribute("LOGGING_DIRECTORY", m_loggingDir); 220 221 // site info 222 config.setAttribute("SERVER_URL", site.getUrl()); 223 config.setAttribute("SERVER_PROTOCOL", site.getSiteMatcher().getServerProtocol()); 224 config.setAttribute("SERVER_NAME", site.getSiteMatcher().getServerName()); 225 config.setAttribute("SERVER_PORT", site.getSiteMatcher().getServerPort()); 226 config.setAttribute("SERVER_NAME_WITH_PORT", generateWebserverConfigName(site.getSiteMatcher(), ":")); 227 config.setAttribute("SITE_TITLE", site.getTitle()); 228 if (site.getErrorPage() != null) { 229 config.setAttribute("ERROR_PAGE", site.getErrorPage()); 230 } 231 232 // alias info 233 if ((site.getAliases() != null) && !site.getAliases().isEmpty()) { 234 config.setAttribute("ALIAS_DIRECTIVE", "ServerAlias"); 235 for (CmsSiteMatcher alias : site.getAliases()) { 236 config.setAttribute("SERVER_ALIASES", generateWebserverConfigName(alias, ":") + " "); 237 } 238 } 239 240 // secure info 241 if (site.hasSecureServer()) { 242 if (site.getSecureUrl() != null) { 243 config.setAttribute("SECURE_URL", site.getSecureUrl()); 244 } 245 if (site.getSecureServer() != null) { 246 config.setAttribute("SECURE_SRV_WITH_PORT", generateWebserverConfigName(site.getSecureServer(), ":")); 247 config.setAttribute("SECURE_SERVER_NAME", site.getSecureServer().getServerName()); 248 config.setAttribute("SECURE_SERVER_PORT", site.getSecureServer().getServerPort()); 249 config.setAttribute("SECURE_SERVER_PROTOCOL", site.getSecureServer().getServerProtocol()); 250 } 251 } 252 return config.toString(); 253 } 254 255 /** 256 * Deletes all web server's configuration files with the given prefix.<p> 257 * 258 * @param prefix a prefix used for the webserver configuration files 259 */ 260 private void deleteAllWebserverConfigs(final String prefix) { 261 262 File file = new File(m_targetPath); 263 if (file.exists() && file.isDirectory()) { 264 File[] configFiles = file.listFiles(new FilenameFilter() { 265 266 /** 267 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) 268 */ 269 public boolean accept(File dir, String name) { 270 271 if (name.startsWith(prefix)) { 272 return true; 273 } 274 return false; 275 } 276 }); 277 for (File f : configFiles) { 278 getReport().println(Messages.get().container(Messages.RPT_DELETING_FILE_1, f), I_CmsReport.FORMAT_OK); 279 f.delete(); 280 } 281 } 282 } 283 284 /** 285 * Executes the webserver script.<p> 286 * 287 * @throws IOException if something goes wrong 288 * @throws InterruptedException if something goes wrong 289 */ 290 private void executeScript() throws IOException, InterruptedException { 291 292 File script = new File(m_scriptPath); 293 List<String> params = new LinkedList<String>(); 294 params.add(script.getAbsolutePath()); 295 params.addAll(m_writtenFiles); 296 ProcessBuilder pb = new ProcessBuilder(params.toArray(new String[params.size()])); 297 pb.directory(new File(script.getParent())); 298 Process pr = pb.start(); 299 pr.waitFor(); 300 BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream())); 301 while (buf.ready()) { 302 String line = buf.readLine(); 303 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(line)) { 304 getReport().println( 305 Messages.get().container(Messages.RPT_OUTPUT_WEBSERVER_1, buf.readLine()), 306 I_CmsReport.FORMAT_OK); 307 } 308 } 309 } 310 311 /** 312 * Generates the web server configuration filename for the given site.<p> 313 * 314 * @param macther the site matcher of the site to get the web server configuration filename for 315 * @param separator for the generated file name 316 * 317 * @return the web server configuration filename 318 */ 319 private String generateWebserverConfigName(CmsSiteMatcher macther, String separator) { 320 321 int port = macther.getServerPort(); 322 String serverName = macther.getServerName(); 323 String portPart = ((port != PORT_HTTP) && (port != PORT_HTTPS)) ? separator + port : ""; 324 return serverName + portPart; 325 } 326 327 /** 328 * Updates LetsEncrypt configuration. 329 */ 330 private void updateLetsEncrypt() { 331 332 getReport().println(Messages.get().container(Messages.RPT_STARTING_LETSENCRYPT_UPDATE_0)); 333 334 CmsLetsEncryptConfiguration config = OpenCms.getLetsEncryptConfig(); 335 if ((config == null) || !config.isValidAndEnabled()) { 336 return; 337 } 338 CmsSiteConfigToLetsEncryptConfigConverter converter = new CmsSiteConfigToLetsEncryptConfigConverter(config); 339 boolean ok = converter.run(getReport(), OpenCms.getSiteManager()); 340 if (ok) { 341 getReport().println( 342 org.opencms.ui.apps.Messages.get().container(org.opencms.ui.apps.Messages.RPT_LETSENCRYPT_FINISHED_0), 343 I_CmsReport.FORMAT_OK); 344 } 345 346 } 347}