Skip to content

Commit 17f6cd5

Browse files
authored
Add Templating (GoogleCloudPlatform#792)
* Add Templating 1. App Engine Sockets (moved from GoogleArchive) 2. J8 GAE Info now uses ThymeLeaf templating 3. Flex GAE Info for combat (WL’d only) sample 4. J8 Metadata - Only uses the Metadata server * add to parent 1. add a few things to the parent pom.xml (both app engine & appengine-java8) 2. Fix some copyrights.
1 parent 0a46f17 commit 17f6cd5

File tree

27 files changed

+1548
-99
lines changed

27 files changed

+1548
-99
lines changed

appengine-java8/gaeinfo/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ Copyright 2017 Google Inc.
6262
<version>2.8.1</version>
6363
</dependency>
6464

65+
<dependency>
66+
<groupId>org.thymeleaf</groupId>
67+
<artifactId>thymeleaf</artifactId>
68+
<version>3.0.7.RELEASE</version>
69+
</dependency>
70+
6571
</dependencies>
6672

6773
<build>

appengine-java8/gaeinfo/src/main/java/com/example/appengine/standard/GaeInfoServlet.java

+90-99
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,23 @@
2121
import com.google.gson.Gson;
2222
import com.google.gson.GsonBuilder;
2323
import com.google.gson.JsonParser;
24-
25-
import okhttp3.OkHttpClient;
26-
import okhttp3.Request;
27-
import okhttp3.Response;
28-
2924
import java.io.IOException;
30-
import java.io.PrintWriter;
3125
import java.util.Enumeration;
3226
import java.util.Map;
3327
import java.util.Properties;
28+
import java.util.TreeMap;
3429
import java.util.concurrent.TimeUnit;
3530
import javax.servlet.annotation.WebServlet;
3631
import javax.servlet.http.Cookie;
3732
import javax.servlet.http.HttpServlet;
3833
import javax.servlet.http.HttpServletRequest;
3934
import javax.servlet.http.HttpServletResponse;
35+
import okhttp3.OkHttpClient;
36+
import okhttp3.Request;
37+
import okhttp3.Response;
38+
import org.thymeleaf.TemplateEngine;
39+
import org.thymeleaf.context.WebContext;
40+
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
4041

4142

4243
// [START example]
@@ -46,7 +47,7 @@
4647
urlPatterns = "/gaeinfo")
4748
public class GaeInfoServlet extends HttpServlet {
4849

49-
final String[] v1 = {
50+
private final String[] metaPath = {
5051
"/computeMetadata/v1/project/numeric-project-id", // (pending)
5152
"/computeMetadata/v1/project/project-id",
5253
"/computeMetadata/v1/instance/zone",
@@ -57,44 +58,30 @@ public class GaeInfoServlet extends HttpServlet {
5758
// "/computeMetadata/v1/instance/service-accounts/default/token"
5859
};
5960

60-
final String[] v1Acct = {
61+
final String[] metaServiceAcct = {
6162
"/computeMetadata/v1/instance/service-accounts/{account}/aliases",
6263
"/computeMetadata/v1/instance/service-accounts/{account}/email",
6364
"/computeMetadata/v1/instance/service-accounts/{account}/scopes",
6465
// Tokens work - but are a security risk to display
6566
// "/computeMetadata/v1/instance/service-accounts/{account}/token"
6667
};
6768

68-
final String metadata = "http://metadata.google.internal";
69+
private final String metadata = "http://metadata.google.internal";
70+
private TemplateEngine templateEngine;
6971

70-
public final OkHttpClient ok = new OkHttpClient.Builder()
72+
// Use OkHttp from Square as it's quite easy to use for simple fetches.
73+
private final OkHttpClient ok = new OkHttpClient.Builder()
7174
.readTimeout(500, TimeUnit.MILLISECONDS) // Don't dawdle
7275
.writeTimeout(500, TimeUnit.MILLISECONDS)
7376
.build();
7477

75-
public Gson gson = new GsonBuilder()
78+
// Setup to pretty print returned json
79+
private final Gson gson = new GsonBuilder()
7680
.setPrettyPrinting()
7781
.create();
78-
public JsonParser jp = new JsonParser();
79-
80-
StringBuilder table(String title, String c) {
81-
StringBuilder sb = new StringBuilder();
82-
sb.append("<h3>");
83-
sb.append(title);
84-
sb.append("</h3><table>");
85-
sb.append(c);
86-
sb.append("</table>");
87-
return sb;
88-
}
89-
90-
String tr(String c) {
91-
return "<tr>" + c + "</tr>";
92-
}
93-
94-
String td(String s) {
95-
return "<td>" + s + "</td>";
96-
}
82+
private final JsonParser jp = new JsonParser();
9783

84+
// Fetch Metadata
9885
String fetchMetadata(String key) throws IOException {
9986
Request request = new Request.Builder()
10087
.url(metadata + key)
@@ -106,122 +93,126 @@ String fetchMetadata(String key) throws IOException {
10693
return response.body().string();
10794
}
10895

109-
String recursMetadata(String prefix) throws IOException {
96+
String fetchJsonMetadata(String prefix) throws IOException {
11097
Request request = new Request.Builder()
111-
.url(metadata + prefix + "?recursive=true")
98+
.url(metadata + prefix )
11299
.addHeader("Metadata-Flavor", "Google")
113100
.get()
114101
.build();
115102

116103
Response response = ok.newCall(request).execute();
117104

105+
// Convert json to prety json
118106
return gson.toJson(jp.parse(response.body().string()));
119107
}
120108

121-
122109
@Override
123-
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
124-
resp.setContentType("text/html");
125-
PrintWriter p = resp.getWriter();
126-
StringBuilder sb = new StringBuilder(4096);
110+
public void init() {
111+
// Setup ThymeLeaf
112+
ServletContextTemplateResolver templateResolver =
113+
new ServletContextTemplateResolver(this.getServletContext());
114+
115+
templateResolver.setPrefix("/WEB-INF/templates/");
116+
templateResolver.setSuffix(".html");
117+
templateResolver.setCacheTTLMs(Long.valueOf(1200000L)); // TTL=20m
127118

128-
p.print("<html><body>");
119+
// Cache is set to true by default. Set to false if you want templates to
120+
// be automatically updated when modified.
121+
templateResolver.setCacheable(true);
122+
123+
templateEngine = new TemplateEngine();
124+
templateEngine.setTemplateResolver(templateResolver);
125+
}
129126

127+
128+
@Override
129+
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
130+
String key ="";
130131
final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService();
132+
WebContext ctx = new WebContext(req, resp, getServletContext(), req.getLocale());
131133

132-
sb.append(table("AppIdentity",
133-
tr(td("ServiceAccountName") + td(appIdentity.getServiceAccountName()))
134-
+ tr(td("GCS Bucket") + td(appIdentity.getDefaultGcsBucketName()))
135-
));
134+
resp.setContentType("text/html");
135+
136+
ctx.setVariable("production", SystemProperty.environment.value().name());
137+
ctx.setVariable("ServiceAccountName", appIdentity.getServiceAccountName());
138+
ctx.setVariable("gcs", appIdentity.getDefaultGcsBucketName());
136139

137-
sb.append(table("SystemProperties",
138-
tr(td("appId") + td(SystemProperty.applicationId.get()))
139-
+ tr(td("appVer") + td(SystemProperty.applicationVersion.get()))
140-
+ tr(td("version") + td(SystemProperty.version.get()))
141-
+ tr(td("environment") + td(SystemProperty.environment.get()))
142-
));
140+
ctx.setVariable("appId", SystemProperty.applicationId.get());
141+
ctx.setVariable("appVer", SystemProperty.applicationVersion.get());
142+
ctx.setVariable("version", SystemProperty.version.get());
143+
ctx.setVariable("environment", SystemProperty.environment.get());
143144

144145
// Environment Atributes
145146
ApiProxy.Environment env = ApiProxy.getCurrentEnvironment();
146147
Map<String, Object> attr = env.getAttributes();
148+
TreeMap<String, String> m = new TreeMap<>();
147149

148-
StringBuilder c = new StringBuilder(1024);
149-
for (String key : attr.keySet()) {
150-
Object o = attr.get(key);
150+
for (String k : attr.keySet()) {
151+
Object o = attr.get(k);
151152

152153
if (o.getClass().getCanonicalName().equals("java.lang.String")) {
153-
c.append(tr(td(key) + td((String) o)));
154+
m.put(k, (String) o);
155+
} else if (o.getClass().getCanonicalName().equals("java.lang.Boolean")) {
156+
m.put(k, ((Boolean) o).toString());
154157
} else {
155-
c.append(tr(td(key) + td(o.getClass().getCanonicalName())));
158+
m.put(k, "a " + o.getClass().getCanonicalName());
156159
}
157160
}
158-
sb.append(table("Environment Attributes", c.toString()));
161+
ctx.setVariable("attribs", m);
159162

160-
c = new StringBuilder(1024);
163+
m = new TreeMap<>();
161164
for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements(); ) {
162-
String key = e.nextElement();
163-
String val = req.getHeader(key);
164-
c.append(tr(td(key) + td(val)));
165+
key = e.nextElement();
166+
m.put(key, req.getHeader(key));
165167
}
166-
sb.append(table("Headers", c.toString()));
168+
ctx.setVariable("headers", m);
167169

168170
Cookie[] cookies = req.getCookies();
171+
m = new TreeMap<>();
169172
if (cookies != null && cookies.length != 0) {
170-
c = new StringBuilder();
171173
for (Cookie co : cookies) {
172-
c.append(tr(td(co.getName()) + td(co.getValue()) + td(co.getComment())
173-
+ td(co.getPath()) + td(Integer.toString(co.getMaxAge()))));
174+
m.put(co.getName(), co.getValue());
174175
}
175-
sb.append(table("Cookies", c.toString()));
176176
}
177+
ctx.setVariable("cookies", m);
177178

178179
Properties properties = System.getProperties();
179-
c = new StringBuilder(1024);
180+
m = new TreeMap<>();
180181
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
181-
String key = (String) e.nextElement();
182-
c.append(tr(td(key) + td((String) properties.get(key))));
182+
key = (String) e.nextElement();
183+
m.put(key, (String) properties.get(key));
183184
}
184-
sb.append(table("Java SystemProperties", c.toString()));
185+
ctx.setVariable("systemprops", m);
185186

186187
Map<String, String> envVar = System.getenv();
187-
c = new StringBuilder(1024);
188-
for (String key : envVar.keySet()) {
189-
c.append(tr(td(key) + td(envVar.get(key))));
190-
}
191-
sb.append(table("Envirionment Variables", c.toString()));
188+
m = new TreeMap<>(envVar);
189+
ctx.setVariable("envvar", m);
192190

191+
// The metadata server is only on a production system
193192
if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production) {
194-
c = new StringBuilder(1024);
195-
for (String key : v1) {
196-
String val = fetchMetadata(key);
197-
if (val != null) {
198-
c.append(tr(td(key) + td(val)));
199-
}
193+
194+
m = new TreeMap<>();
195+
for (String k : metaPath) {
196+
m.put(k, fetchMetadata(key));
200197
}
201-
sb.append(table("Metadata", c.toString()));
202-
203-
c = new StringBuilder(1024);
204-
for (String key : v1Acct) {
205-
key = key.replace("{account}", appIdentity.getServiceAccountName());
206-
String val = fetchMetadata(key);
207-
if (val != null) {
208-
c.append(tr(td(key) + td(val)));
209-
}
198+
ctx.setVariable("Metadata", m.descendingMap());
199+
200+
m = new TreeMap<>();
201+
for (String k : metaServiceAcct) {
202+
// substitute a service account for {account}
203+
k = k.replace("{account}", appIdentity.getServiceAccountName());
204+
m.put(k, fetchMetadata(k));
210205
}
211-
sb.append(table("ServiceAccount Metadata", c.toString()));
212-
213-
sb.append("<h3>Recursive service-accounts</h3><pre><code>"
214-
+ recursMetadata("/computeMetadata/v1/instance/service-accounts/")
215-
+ "</code></pre>");
216-
sb.append("<h3>Recursive all metadata</h3><pre><code>"
217-
+ recursMetadata("/")
218-
+ "</code></pre>");
219-
}
206+
ctx.setVariable("sam", m.descendingMap());
220207

221-
sb.append("</body></html>");
222-
p.append(sb);
223-
p.close();
208+
// Recursivly get all info about service accounts -- Note tokens are leftout by default.
209+
ctx.setVariable("rsa",
210+
fetchJsonMetadata("/computeMetadata/v1/instance/service-accounts/?recursive=true"));
211+
// Recursivly get all data on Metadata server.
212+
ctx.setVariable("ram", fetchJsonMetadata("/?recursive=true"));
213+
}
224214

215+
templateEngine.process("index", ctx, resp.getWriter());
225216
}
226217
}
227218
// [END example]

0 commit comments

Comments
 (0)