2121import com .google .gson .Gson ;
2222import com .google .gson .GsonBuilder ;
2323import com .google .gson .JsonParser ;
24-
25- import okhttp3 .OkHttpClient ;
26- import okhttp3 .Request ;
27- import okhttp3 .Response ;
28-
2924import java .io .IOException ;
30- import java .io .PrintWriter ;
3125import java .util .Enumeration ;
3226import java .util .Map ;
3327import java .util .Properties ;
28+ import java .util .TreeMap ;
3429import java .util .concurrent .TimeUnit ;
3530import javax .servlet .annotation .WebServlet ;
3631import javax .servlet .http .Cookie ;
3732import javax .servlet .http .HttpServlet ;
3833import javax .servlet .http .HttpServletRequest ;
3934import 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]
4647 urlPatterns = "/gaeinfo" )
4748public 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