| // Copyright (C) 2013 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.httpd.template; |
| |
| import static com.google.gerrit.common.FileUtil.lastModified; |
| |
| import com.google.common.base.Strings; |
| import com.google.gerrit.httpd.HtmlDomUtil; |
| import com.google.gerrit.server.config.GerritServerConfig; |
| import com.google.gerrit.server.config.SitePaths; |
| import com.google.inject.Inject; |
| import com.google.inject.Singleton; |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import org.eclipse.jgit.lib.Config; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| @Singleton |
| public class SiteHeaderFooter { |
| private static final Logger log = LoggerFactory.getLogger(SiteHeaderFooter.class); |
| |
| private final boolean refreshHeaderFooter; |
| private final SitePaths sitePaths; |
| private volatile Template template; |
| |
| @Inject |
| SiteHeaderFooter(@GerritServerConfig Config cfg, SitePaths sitePaths) { |
| this.refreshHeaderFooter = cfg.getBoolean("site", "refreshHeaderFooter", true); |
| this.sitePaths = sitePaths; |
| |
| try { |
| Template t = new Template(sitePaths); |
| t.load(); |
| template = t; |
| } catch (IOException e) { |
| log.warn("Cannot load site header or footer", e); |
| } |
| } |
| |
| public Document parse(Class<?> clazz, String name) throws IOException { |
| Template t = template; |
| if (refreshHeaderFooter && t.isStale()) { |
| t = new Template(sitePaths); |
| try { |
| t.load(); |
| template = t; |
| } catch (IOException e) { |
| log.warn("Cannot refresh site header or footer", e); |
| t = template; |
| } |
| } |
| |
| Document doc = HtmlDomUtil.parseFile(clazz, name); |
| injectCss(doc, "gerrit_sitecss", t.css); |
| injectXml(doc, "gerrit_header", t.header); |
| injectXml(doc, "gerrit_footer", t.footer); |
| return doc; |
| } |
| |
| private void injectCss(Document doc, String id, String content) { |
| Element e = HtmlDomUtil.find(doc, id); |
| if (e != null) { |
| if (!Strings.isNullOrEmpty(content)) { |
| while (e.getFirstChild() != null) { |
| e.removeChild(e.getFirstChild()); |
| } |
| e.removeAttribute("id"); |
| e.appendChild(doc.createCDATASection("\n" + content + "\n")); |
| } else { |
| e.getParentNode().removeChild(e); |
| } |
| } |
| } |
| |
| private void injectXml(Document doc, String id, Element d) { |
| Element e = HtmlDomUtil.find(doc, id); |
| if (e != null) { |
| if (d != null) { |
| while (e.getFirstChild() != null) { |
| e.removeChild(e.getFirstChild()); |
| } |
| e.appendChild(doc.importNode(d, true)); |
| } else { |
| e.getParentNode().removeChild(e); |
| } |
| } |
| } |
| |
| private static class Template { |
| private final FileInfo cssFile; |
| private final FileInfo headerFile; |
| private final FileInfo footerFile; |
| |
| String css; |
| Element header; |
| Element footer; |
| |
| Template(SitePaths site) { |
| cssFile = new FileInfo(site.site_css); |
| headerFile = new FileInfo(site.site_header); |
| footerFile = new FileInfo(site.site_footer); |
| } |
| |
| void load() throws IOException { |
| css = HtmlDomUtil.readFile(cssFile.path.getParent(), cssFile.path.getFileName().toString()); |
| header = readXml(headerFile); |
| footer = readXml(footerFile); |
| } |
| |
| boolean isStale() { |
| return cssFile.isStale() || headerFile.isStale() || footerFile.isStale(); |
| } |
| |
| private static Element readXml(FileInfo src) throws IOException { |
| Document d = HtmlDomUtil.parseFile(src.path); |
| return d != null ? d.getDocumentElement() : null; |
| } |
| } |
| |
| private static class FileInfo { |
| final Path path; |
| final long time; |
| |
| FileInfo(Path p) { |
| path = p; |
| time = lastModified(p); |
| } |
| |
| boolean isStale() { |
| return time != lastModified(path); |
| } |
| } |
| } |