altos-map: Retry connection to cache service
[fw/altos] / map-server / altos-map / AltosMap.java
1 /*
2  * Copyright © 2018 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 package altosmap;
16
17 import java.net.*;
18 import java.io.*;
19 import java.util.*;
20 import java.text.*;
21
22 import org.altusmetrum.altoslib_13.*;
23
24 public class AltosMap {
25
26         public final static int port = 16717;
27
28         String  query_string;
29         String  remote_addr;
30
31         public String reason_string(int code) {
32                 switch (code) {
33                 case 200:
34                         return "OK";
35                 case 400:
36                         return "Bad Request";
37                 case 403:
38                         return "Forbidden";
39                 case 404:
40                         return "Not Found";
41                 case 408:
42                         return "Request Timeout";
43                 default:
44                         return "Failure";
45                 }
46         }
47
48         public void write_status(int status) {
49                 System.out.printf("Status: %d %s\n", status, reason_string(status));
50         }
51
52         public void write_type(String type) {
53                 System.out.printf("Content-Type: %s\n", type);
54         }
55
56         public void fail(int status, String reason) {
57                 write_status(status);
58                 write_type("text/html");
59                 System.out.printf("\n");
60                 System.out.printf("<html>\n");
61                 System.out.printf("<head><title>Map Fetch Failure</title></head>\n");
62                 System.out.printf("<body>%s</body>\n", reason);
63                 System.out.printf("</html>\n");
64                 System.exit(1);
65         }
66
67         public void process() {
68                 query_string = System.getenv("QUERY_STRING");
69
70                 if (query_string == null)
71                         fail(400, "Missing query string");
72
73                 remote_addr = System.getenv("REMOTE_ADDR");
74
75                 if (remote_addr == null)
76                         fail(400, "Missing remote address");
77
78                 String[] queries = query_string.split("&");
79
80                 double  lon = AltosLib.MISSING;
81                 double  lat = AltosLib.MISSING;
82                 int     zoom = AltosLib.MISSING;
83
84                 try {
85                         for (String query : queries) {
86                                 String[] q = query.split("=");
87                                 if (q.length >= 2) {
88                                         String name = q[0];
89                                         String value = q[1];
90                                         if (name.equals("lon"))
91                                                 lon = AltosParse.parse_double_net(value);
92                                         else if (name.equals("lat"))
93                                                 lat = AltosParse.parse_double_net(value);
94                                         else if (name.equals("zoom"))
95                                                 zoom = AltosParse.parse_int(value);
96                                         else
97                                                 fail(400, String.format("Extra query param \"%s\"", query));
98                                 }
99                         }
100                 } catch (ParseException pe) {
101                         fail(400, String.format("Invalid query: %s", pe.toString()));
102                 }
103
104                 if (lon == AltosLib.MISSING)
105                         fail(400, "Missing longitude");
106                 if (lat == AltosLib.MISSING)
107                         fail(400, "Missing latitude");
108                 if (zoom == AltosLib.MISSING)
109                         fail(400, "Missing zoom");
110
111                 try {
112                         Socket  socket = null;
113                         int tries = 0;
114
115                         while (tries < 10 && socket == null) {
116                                 try {
117                                         socket = new Socket(InetAddress.getLoopbackAddress(), port);
118                                 } catch (IOException ie) {
119                                         Thread.sleep(100);
120                                         tries++;
121                                 }
122                         }
123
124                         AltosJson       request = new AltosJson();
125
126                         request.put("lat", lat);
127                         request.put("lon", lon);
128                         request.put("zoom", zoom);
129                         request.put("remote_addr", remote_addr);
130
131                         Writer writer = new PrintWriter(socket.getOutputStream());
132                         request.write(writer);
133                         writer.flush();
134
135                         AltosJson       reply = AltosJson.fromInputStream(socket.getInputStream());
136
137                         int status = reply.get_int("status", 400);
138
139                         if (status != 200)
140                                 fail(status, "Bad cache status");
141
142                         String filename = reply.get_string("filename", null);
143                         try {
144                                 File file = new File(filename);
145                                 long length = file.length();
146                                 FileInputStream in = new FileInputStream(file);
147                                 String content_type = reply.get_string("content_type", null);
148                                 System.out.printf("Content-Type: %s\n", content_type);
149                                 System.out.printf("Content-Length: %d\n", file.length());
150                                 System.out.printf("\n");
151                                 byte[] buf = new byte[4096];
152                                 int bytes_read;
153                                 while ((bytes_read = in.read(buf)) > 0)
154                                         System.out.write(buf);
155                         } catch (IOException ie) {
156                                 fail(404, String.format("IO Exception: %s", ie.toString()));
157                         }
158                 } catch (Exception e) {
159                         fail(404, String.format("Exception %s", e.toString()));
160                 }
161         }
162
163         public AltosMap() {
164         }
165
166         public static void main(final String[] args) {
167
168                 new AltosMap().process();
169
170         }
171 }