1
package org.opensatnav.android.contribute.output;
4
* Copyright by Christof Dallermassl
5
* This program is free software and licensed under GPL.
7
* Original JAVA-Code ported for Android compatibility by Nicolas 'plusminus' Gramlich.
11
import java.io.BufferedInputStream;
12
import java.io.BufferedOutputStream;
13
import java.io.ByteArrayInputStream;
14
import java.io.DataOutputStream;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.net.HttpURLConnection;
19
import java.text.SimpleDateFormat;
20
import java.util.ArrayList;
21
import java.util.GregorianCalendar;
23
import org.andnav.osm.views.util.HttpUserAgentHelper;
24
import org.opensatnav.android.OpenSatNavConstants;
25
import org.opensatnav.android.contribute.util.RecordedRouteGPXFormatter;
26
import org.opensatnav.android.contribute.util.constants.OSMConstants;
28
import android.content.Context;
29
import android.location.Location;
30
import android.util.Log;
34
* Small java class that allows to upload gpx files to www.openstreetmap.org via its api call.
39
public class OSMUploader implements OSMConstants{
40
// ===========================================================
42
// ===========================================================
44
public static final String API_VERSION = "0.6";
45
private static final int BUFFER_SIZE = 65535;
46
private static final String BASE64_ENC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47
private static final String BOUNDARY = "----------------------------d10f7aa230e8";
48
private static final String LINE_END = "\r\n";
51
private static final String DEFAULT_TAGS = "OpenSatNav";
53
public static final SimpleDateFormat pseudoFileNameFormat = new SimpleDateFormat("yyyyMMdd'_'HHmmss'_'SSS");
54
private static final SimpleDateFormat autoTagFormat = new SimpleDateFormat("MMMM yyyy");
56
// ===========================================================
58
// ===========================================================
60
// ===========================================================
62
// ===========================================================
65
* Uses OSMConstants.OSM_USERNAME and OSMConstants.OSM_PASSWORD as username/password.
66
* Description will be <code>DEFAULT_DESCRIPTION</code>, tags will be automatically generated (i.e. "<code>October 2008</code>")
67
* NOTE: This method is not blocking!
68
* @param gpxInputStream the InputStream containing the gpx-data.
71
public static void uploadAsync(final Context context, final ArrayList<Location> locations, String username, String password, String description, String visibility) throws IOException{
72
uploadAsync(context, new ByteArrayInputStream(RecordedRouteGPXFormatter.create(locations, username).getBytes()), username, password, description, visibility);
75
public static void uploadAsync(final Context context, final InputStream gpxInputStream, String username, String password, String description, String visibility) throws IOException{
76
uploadAsync(context, description, DEFAULT_TAGS, true, gpxInputStream, username, password, visibility);
79
/*public static void uploadAsync(final ArrayList<RecordedGeoPoint> recordedGeoPoints, String username, String password, String description) throws IOException{
80
uploadAsync(new ByteArrayInputStream(RecordedRouteGPXFormatter.create(recordedGeoPoints, username).getBytes()), username, password, description);
84
* Uses OSMConstants.OSM_USERNAME and OSMConstants.OSM_PASSWORD as username/password.
85
* The 'filename' will be the current <code>timestamp.gpx</code> (i.e. "20081231_234815_912.gpx")
86
* NOTE: This method is not blocking!
87
* @param description <code>not null</code>
88
* @param tags <code>not null</code>
89
* @param addDateTags adds Date Tags to the existing Tags (i.e. "October 2008")
90
* @param gpxInputStreaman the InputStream containing the gpx-data.
93
public static void uploadAsync(final Context context, final String description, final String tags, final boolean addDateTags, final InputStream gpxInputStream, String username, String password, String visibility) throws IOException {
94
uploadAsync(context, username, password, description, tags, true, gpxInputStream, pseudoFileNameFormat.format(new GregorianCalendar().getTime()) + "_" + username + ".gpx", visibility);
97
public static void uploadAsync(final Context context, final String description, final String tags, final boolean addDateTags, final ArrayList<Location> recordedGeoPoints, String username, String password, String visibility) throws IOException{
98
uploadAsync(context, description, tags, addDateTags, new ByteArrayInputStream(RecordedRouteGPXFormatter.create(recordedGeoPoints, username).getBytes()), username, password, visibility);
103
* NOTE: This method is not blocking! (Code runs in thread)
104
* @param username <code>not null</code> and <code>not empty</code>. Valid OSM-username
105
* @param password <code>not null</code> and <code>not empty</code>. Valid password to the OSM-username.
106
* @param description <code>not null</code>
107
* @param tags if <code>null</code> addDateTags is treated as <code>true</code>
108
* @param addDateTags adds Date Tags to the existing Tags (i.e. "<code>October 2008</code>")
109
* @param gpxInputStream the InputStream containing the gpx-data.
110
* @param pseudoFileName ending with "<code>.gpx</code>"
111
* @throws IOException
113
public static void uploadAsync(final Context context, final String username, final String password, final String description, final String tags, final boolean addDateTags, final InputStream gpxInputStream, final String pseudoFileName, final String visibility) {
114
assert(username != null && username.length() > 0);
115
assert(password != null && password.length() > 0);
116
assert(description == null || description.length() > 0);
117
assert(tags == null || tags.length() > 0);
118
assert(pseudoFileName != null && pseudoFileName.endsWith(".gpx"));
120
new Thread(new Runnable(){
124
String tagsToUse = tags;
125
if(addDateTags || tagsToUse == null)
126
if(tagsToUse == null)
127
tagsToUse = autoTagFormat.format(new GregorianCalendar().getTime());
129
tagsToUse = tagsToUse + " " + autoTagFormat.format(new GregorianCalendar().getTime());
131
Log.d(OpenSatNavConstants.LOG_TAG, "Uploading " + pseudoFileName + " to openstreetmap.org");
133
//String urlGpxName = URLEncoder.encode(gpxName.replaceAll("\\.;&?,/","_"), "UTF-8");
134
final String urlDesc = description.replaceAll("\\.;&?,/","_");
135
final String urlTags = (tagsToUse == null) ? DEFAULT_TAGS : tagsToUse.replaceAll("\\\\.;&?,/","_");
136
final URL url = new URL("http://www.openstreetmap.org/api/" + API_VERSION + "/gpx/create");
137
//final URL url = new URL("http://192.168.10.210:3000/gpstracks");
138
Log.d(OpenSatNavConstants.LOG_TAG, "Destination Url: " + url);
139
final HttpURLConnection con = (HttpURLConnection) url.openConnection();
140
String userAgent = HttpUserAgentHelper.getUserAgent(context);
141
if (userAgent != null)
142
con.setRequestProperty("User-Agent", userAgent);
143
con.setConnectTimeout(15000);
144
con.setRequestMethod("POST");
145
con.setDoOutput(true);
146
con.addRequestProperty("Authorization", "Basic "+encodeBase64(username+":"+password));
147
con.addRequestProperty("Content-Type", "multipart/form-data; boundary="+BOUNDARY);
148
con.addRequestProperty("Connection", "close"); // counterpart of keep-alive
149
con.addRequestProperty("Expect", "");
152
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(con.getOutputStream()));
153
// DataOutputStream out = new DataOutputStream(System.out);
155
writeContentDispositionFile(out, "file", gpxInputStream, pseudoFileName);
156
writeContentDisposition(out, "description", urlDesc);
157
writeContentDisposition(out, "tags", urlTags);
159
writeContentDisposition(out, "visibility", visibility);
161
out.writeBytes("--" + BOUNDARY + "--" + LINE_END);
164
final int retCode = con.getResponseCode();
165
String retMsg = con.getResponseMessage();
166
Log.d(OpenSatNavConstants.LOG_TAG, "\nreturn code: "+retCode + " " + retMsg);
167
if (retCode != 200) {
168
// Look for a detailed error message from the server
169
if (con.getHeaderField("Error") != null)
170
retMsg += "\n" + con.getHeaderField("Error");
172
throw new RuntimeException(retCode+" "+retMsg);
176
} catch(Exception e) {
177
Log.e(OpenSatNavConstants.LOG_TAG, "OSMUpload Error", e);
182
}, "OSMUpload-Thread").start();
185
public static void upload(final Context context, final String username, final String password, final String description, final String tags, final boolean addDateTags, final ArrayList<Location> recordedGeoPoints, final String pseudoFileName, String visibility) throws IOException{
186
uploadAsync(context, username, password, description, tags, addDateTags, new ByteArrayInputStream(RecordedRouteGPXFormatter.create(recordedGeoPoints, username).getBytes()), pseudoFileName, visibility);
193
* @throws IOException
195
private static void writeContentDispositionFile(final DataOutputStream out, final String name, final InputStream gpxInputStream, final String pseudoFileName) throws IOException {
196
out.writeBytes("--" + BOUNDARY + LINE_END);
197
out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + pseudoFileName + "\"" + LINE_END);
198
out.writeBytes("Content-Type: application/octet-stream" + LINE_END);
199
out.writeBytes(LINE_END);
201
final byte[] buffer = new byte[BUFFER_SIZE];
202
//int fileLen = (int)gpxFile.length();
205
final InputStream in = new BufferedInputStream(gpxInputStream);
206
Log.d(OpenSatNavConstants.LOG_TAG, "Transferring data to server");
207
while((read = in.read(buffer)) >= 0) {
208
out.write(buffer, 0, read);
213
out.writeBytes(LINE_END);
219
* @throws IOException
221
private static void writeContentDisposition(final DataOutputStream out, final String name, final String value) throws IOException {
222
out.writeBytes("--" + BOUNDARY + LINE_END);
223
out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + LINE_END);
224
out.writeBytes(LINE_END);
225
out.writeBytes(value + LINE_END);
228
private static String encodeBase64(final String s) {
229
StringBuilder out = new StringBuilder();
230
for (int i = 0; i < (s.length()+2)/3; ++i) {
231
int l = Math.min(3, s.length()-i*3);
232
final String buf = s.substring(i*3, i*3+l);
233
out.append(BASE64_ENC.charAt(buf.charAt(0)>>2));
234
out.append(BASE64_ENC.charAt((buf.charAt(0) & 0x03) << 4 | (l==1?0:(buf.charAt(1) & 0xf0) >> 4)));
235
out.append(l>1 ? BASE64_ENC.charAt((buf.charAt(1) & 0x0f) << 2 | (l==2 ? 0 : (buf.charAt(2) & 0xc0) >> 6)) : '=');
236
out.append(l>2 ? BASE64_ENC.charAt(buf.charAt(2) & 0x3f) : '=');
238
return out.toString();