altos-map: Support version query from application
[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         public final static String protocol_version = "1.0.0";
29
30         String  query_string;
31         String  remote_addr;
32
33         public String reason_string(int code) {
34                 switch (code) {
35                 case 200:
36                         return "OK";
37                 case 400:
38                         return "Bad Request";
39                 case 403:
40                         return "Forbidden";
41                 case 404:
42                         return "Not Found";
43                 case 408:
44                         return "Request Timeout";
45                 default:
46                         return "Failure";
47                 }
48         }
49
50         public void write_status(int status) {
51                 System.out.printf("Status: %d %s\n", status, reason_string(status));
52         }
53
54         public void write_type(String type) {
55                 System.out.printf("Content-Type: %s\n", type);
56         }
57
58         public void fail(int status, String reason) {
59                 write_status(status);
60                 write_type("text/html");
61                 System.out.printf("\n");
62                 System.out.printf("<html>\n");
63                 System.out.printf("<head><title>Map Fetch Failure</title></head>\n");
64                 System.out.printf("<body>%s</body>\n", reason);
65                 System.out.printf("</html>\n");
66                 System.exit(1);
67         }
68
69         public void process() {
70                 query_string = System.getenv("QUERY_STRING");
71
72                 if (query_string == null)
73                         fail(400, "Missing query string");
74
75                 remote_addr = System.getenv("REMOTE_ADDR");
76
77                 if (remote_addr == null)
78                         fail(400, "Missing remote address");
79
80                 String[] queries = query_string.split("&");
81
82                 double  lon = AltosLib.MISSING;
83                 double  lat = AltosLib.MISSING;
84                 int     zoom = AltosLib.MISSING;
85                 String  version = null;
86
87                 try {
88                         for (String query : queries) {
89                                 String[] q = query.split("=");
90                                 if (q.length >= 2) {
91                                         String name = q[0];
92                                         String value = q[1];
93                                         if (name.equals("lon"))
94                                                 lon = AltosParse.parse_double_net(value);
95                                         else if (name.equals("lat"))
96                                                 lat = AltosParse.parse_double_net(value);
97                                         else if (name.equals("zoom"))
98                                                 zoom = AltosParse.parse_int(value);
99                                         else if (name.equals("version"))
100                                                 version = value;
101                                         else
102                                                 fail(400, String.format("Extra query param \"%s\"", query));
103                                 }
104                         }
105                 } catch (ParseException pe) {
106                         fail(400, String.format("Invalid query: %s", pe.toString()));
107                 }
108
109                 if (version != null) {
110                         System.out.printf("Content-Type: text/plain\n");
111                         System.out.printf("\n");
112                         System.out.printf("%s\n", protocol_version);
113                 } else {
114                         if (lon == AltosLib.MISSING)
115                                 fail(400, "Missing longitude");
116                         if (lat == AltosLib.MISSING)
117                                 fail(400, "Missing latitude");
118                         if (zoom == AltosLib.MISSING)
119                                 fail(400, "Missing zoom");
120
121                         try {
122                                 Socket  socket = null;
123                                 int tries = 0;
124
125                                 while (tries < 10 && socket == null) {
126                                         try {
127                                                 socket = new Socket(InetAddress.getLoopbackAddress(), port);
128                                         } catch (IOException ie) {
129                                                 Thread.sleep(100);
130                                                 tries++;
131                                         }
132                                 }
133
134                                 AltosJson       request = new AltosJson();
135
136                                 request.put("lat", lat);
137                                 request.put("lon", lon);
138                                 request.put("zoom", zoom);
139                                 request.put("remote_addr", remote_addr);
140
141                                 Writer writer = new PrintWriter(socket.getOutputStream());
142                                 request.write(writer);
143                                 writer.flush();
144
145                                 AltosJson       reply = AltosJson.fromInputStream(socket.getInputStream());
146
147                                 int status = reply.get_int("status", 400);
148
149                                 if (status != 200)
150                                         fail(status, "Bad cache status");
151
152                                 String filename = reply.get_string("filename", null);
153                                 try {
154                                         File file = new File(filename);
155                                         long length = file.length();
156                                         FileInputStream in = new FileInputStream(file);
157                                         String content_type = reply.get_string("content_type", null);
158                                         System.out.printf("Content-Type: %s\n", content_type);
159                                         System.out.printf("Content-Length: %d\n", file.length());
160                                         System.out.printf("\n");
161                                         byte[] buf = new byte[4096];
162                                         int bytes_read;
163                                         while ((bytes_read = in.read(buf)) > 0)
164                                                 System.out.write(buf);
165                                 } catch (IOException ie) {
166                                         fail(404, String.format("IO Exception: %s", ie.toString()));
167                                 }
168                         } catch (Exception e) {
169                                 fail(404, String.format("Exception %s", e.toString()));
170                         }
171                 }
172         }
173
174         public AltosMap() {
175         }
176
177         public static void main(final String[] args) {
178
179                 new AltosMap().process();
180
181         }
182 }