Line data Source code
1 : // Copyright (C) 2016 The Android Open Source Project
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : package com.google.gerrit.server.mail.send;
16 :
17 : import static com.google.common.base.Preconditions.checkArgument;
18 :
19 : import com.google.common.io.CharStreams;
20 : import com.google.gerrit.server.config.SitePaths;
21 : import com.google.gerrit.server.plugincontext.PluginSetContext;
22 : import com.google.inject.Inject;
23 : import com.google.inject.ProvisionException;
24 : import com.google.inject.Singleton;
25 : import com.google.template.soy.SoyFileSet;
26 : import com.google.template.soy.jbcsrc.api.SoySauce;
27 : import com.google.template.soy.shared.SoyAstCache;
28 : import java.io.IOException;
29 : import java.io.Reader;
30 : import java.net.URL;
31 : import java.nio.charset.StandardCharsets;
32 : import java.nio.file.Files;
33 : import java.nio.file.Path;
34 :
35 : /**
36 : * Configures and loads Soy Sauce object for rendering email templates.
37 : *
38 : * <p>It reloads templates each time when {@link #load()} is called.
39 : */
40 : @Singleton
41 : class MailSoySauceLoader {
42 :
43 : // Note: will fail to construct the tofu object if this array is empty.
44 152 : private static final String[] TEMPLATES = {
45 : "Abandoned.soy",
46 : "AbandonedHtml.soy",
47 : "AddKey.soy",
48 : "AddKeyHtml.soy",
49 : "AddToAttentionSet.soy",
50 : "AddToAttentionSetHtml.soy",
51 : "ChangeFooter.soy",
52 : "ChangeFooterHtml.soy",
53 : "ChangeHeader.soy",
54 : "ChangeHeaderHtml.soy",
55 : "ChangeSubject.soy",
56 : "Comment.soy",
57 : "CommentHtml.soy",
58 : "CommentFooter.soy",
59 : "CommentFooterHtml.soy",
60 : "DeleteKey.soy",
61 : "DeleteKeyHtml.soy",
62 : "DeleteReviewer.soy",
63 : "DeleteReviewerHtml.soy",
64 : "DeleteVote.soy",
65 : "DeleteVoteHtml.soy",
66 : "InboundEmailRejection.soy",
67 : "InboundEmailRejectionHtml.soy",
68 : "Footer.soy",
69 : "FooterHtml.soy",
70 : "HttpPasswordUpdate.soy",
71 : "HttpPasswordUpdateHtml.soy",
72 : "Merged.soy",
73 : "MergedHtml.soy",
74 : "NewChange.soy",
75 : "NewChangeHtml.soy",
76 : "NoReplyFooter.soy",
77 : "NoReplyFooterHtml.soy",
78 : "Private.soy",
79 : "RegisterNewEmail.soy",
80 : "RegisterNewEmailHtml.soy",
81 : "RemoveFromAttentionSet.soy",
82 : "RemoveFromAttentionSetHtml.soy",
83 : "ReplacePatchSet.soy",
84 : "ReplacePatchSetHtml.soy",
85 : "Restored.soy",
86 : "RestoredHtml.soy",
87 : "Reverted.soy",
88 : "RevertedHtml.soy",
89 : "SetAssignee.soy",
90 : "SetAssigneeHtml.soy",
91 : };
92 :
93 : private final SitePaths site;
94 : private final SoyAstCache cache;
95 : private final PluginSetContext<MailSoyTemplateProvider> templateProviders;
96 :
97 : @Inject
98 : MailSoySauceLoader(
99 : SitePaths site,
100 : SoyAstCache cache,
101 152 : PluginSetContext<MailSoyTemplateProvider> templateProviders) {
102 152 : this.site = site;
103 152 : this.cache = cache;
104 152 : this.templateProviders = templateProviders;
105 152 : }
106 :
107 : public SoySauce load() {
108 106 : SoyFileSet.Builder builder = SoyFileSet.builder();
109 106 : builder.setSoyAstCache(cache);
110 106 : for (String name : TEMPLATES) {
111 106 : addTemplate(builder, "com/google/gerrit/server/mail/", name);
112 : }
113 106 : templateProviders.runEach(
114 0 : e -> e.getFileNames().forEach(p -> addTemplate(builder, e.getPath(), p)));
115 106 : return builder.build().compileTemplates();
116 : }
117 :
118 : private void addTemplate(SoyFileSet.Builder builder, String resourcePath, String name)
119 : throws ProvisionException {
120 106 : if (!resourcePath.endsWith("/")) {
121 0 : resourcePath += "/";
122 : }
123 106 : String logicalPath = resourcePath + name;
124 :
125 : // Load as a file in the mail templates directory if present.
126 106 : Path tmpl = site.mail_dir.resolve(name);
127 106 : if (Files.isRegularFile(tmpl)) {
128 : String content;
129 : // TODO(davido): Consider using JGit's FileSnapshot to cache based on
130 : // mtime.
131 0 : try (Reader r = Files.newBufferedReader(tmpl, StandardCharsets.UTF_8)) {
132 0 : content = CharStreams.toString(r);
133 0 : } catch (IOException err) {
134 0 : throw new ProvisionException(
135 0 : "Failed to read template file " + tmpl.toAbsolutePath().toString(), err);
136 0 : }
137 0 : builder.add(content, logicalPath);
138 0 : return;
139 : }
140 :
141 : // Otherwise load the template as a resource.
142 106 : URL resource = this.getClass().getClassLoader().getResource(logicalPath);
143 106 : checkArgument(resource != null, "resource %s not found.", logicalPath);
144 106 : builder.add(resource, logicalPath);
145 106 : }
146 : }
|