~opensatnav-admins/opensatnav/release-1.0

« back to all changes in this revision

Viewing changes to src/org/opensatnav/android/contribute/output/OSMUploader.java

  • Committer: Kieran Fleming
  • Date: 2010-12-13 13:13:48 UTC
  • Revision ID: kieran.fleming@gmail.com-20101213131348-pixo12i0wjf11jk3
Add all the missing stuff from the failed package rename

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.opensatnav.android.contribute.output;
 
2
 
 
3
/**
 
4
 * Copyright by Christof Dallermassl
 
5
 * This program is free software and licensed under GPL.
 
6
 * 
 
7
 * Original JAVA-Code ported for Android compatibility by Nicolas 'plusminus' Gramlich.
 
8
 */
 
9
 
 
10
 
 
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;
 
18
import java.net.URL;
 
19
import java.text.SimpleDateFormat;
 
20
import java.util.ArrayList;
 
21
import java.util.GregorianCalendar;
 
22
 
 
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;
 
27
 
 
28
import android.content.Context;
 
29
import android.location.Location;
 
30
import android.util.Log;
 
31
 
 
32
 
 
33
/**
 
34
 * Small java class that allows to upload gpx files to www.openstreetmap.org via its api call.
 
35
 * 
 
36
 * @author cdaller
 
37
 * @author ngramlich
 
38
 */
 
39
public class OSMUploader implements OSMConstants{
 
40
        // ===========================================================
 
41
        // Constants
 
42
        // ===========================================================
 
43
        
 
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";
 
49
        
 
50
        
 
51
        private static final String DEFAULT_TAGS = "OpenSatNav";
 
52
        
 
53
        public static final SimpleDateFormat pseudoFileNameFormat = new SimpleDateFormat("yyyyMMdd'_'HHmmss'_'SSS");
 
54
        private static final SimpleDateFormat autoTagFormat = new SimpleDateFormat("MMMM yyyy");
 
55
        
 
56
        // ===========================================================
 
57
        // Fields
 
58
        // ===========================================================
 
59
 
 
60
        // ===========================================================
 
61
        // Methods
 
62
        // ===========================================================
 
63
        
 
64
        /**
 
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.
 
69
         * @throws IOException
 
70
         */
 
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);
 
73
        }
 
74
        
 
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);
 
77
        }
 
78
        
 
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);
 
81
        }*/
 
82
        
 
83
        /**
 
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.
 
91
         * @throws IOException
 
92
         */
 
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);
 
95
        }
 
96
        
 
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);
 
99
        }
 
100
 
 
101
 
 
102
        /**
 
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
 
112
         */
 
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"));
 
119
 
 
120
                new Thread(new Runnable(){
 
121
 
 
122
                        @Override
 
123
                        public void run() {
 
124
                                String tagsToUse = tags;
 
125
                                if(addDateTags || tagsToUse == null)
 
126
                                        if(tagsToUse == null)
 
127
                                                tagsToUse = autoTagFormat.format(new GregorianCalendar().getTime());
 
128
                                        else
 
129
                                                tagsToUse = tagsToUse + " " + autoTagFormat.format(new GregorianCalendar().getTime());
 
130
                                
 
131
                                Log.d(OpenSatNavConstants.LOG_TAG, "Uploading " + pseudoFileName + " to openstreetmap.org");
 
132
                                try {
 
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", "");
 
150
 
 
151
                                        con.connect();
 
152
                                        DataOutputStream out  = new DataOutputStream(new BufferedOutputStream(con.getOutputStream()));
 
153
                                        //            DataOutputStream out  = new DataOutputStream(System.out);
 
154
 
 
155
                                        writeContentDispositionFile(out, "file", gpxInputStream, pseudoFileName);
 
156
                                        writeContentDisposition(out, "description", urlDesc);
 
157
                                        writeContentDisposition(out, "tags", urlTags);
 
158
                                        
 
159
                                        writeContentDisposition(out, "visibility", visibility);
 
160
 
 
161
                                        out.writeBytes("--" + BOUNDARY + "--" + LINE_END);
 
162
                                        out.flush();
 
163
 
 
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");
 
171
                                                con.disconnect();
 
172
                                                throw new RuntimeException(retCode+" "+retMsg);
 
173
                                        }
 
174
                                        out.close();
 
175
                                        con.disconnect();
 
176
                                } catch(Exception e) {
 
177
                                        Log.e(OpenSatNavConstants.LOG_TAG, "OSMUpload Error", e);
 
178
                                        
 
179
                                }
 
180
                        }
 
181
                        
 
182
                }, "OSMUpload-Thread").start();
 
183
        }
 
184
        
 
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);
 
187
        }
 
188
 
 
189
        /**
 
190
         * @param out
 
191
         * @param string
 
192
         * @param gpxFile
 
193
         * @throws IOException 
 
194
         */
 
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);
 
200
 
 
201
                final byte[] buffer = new byte[BUFFER_SIZE];
 
202
                //int fileLen = (int)gpxFile.length();
 
203
                int read;
 
204
                int sumread = 0;
 
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);
 
209
                        out.flush();
 
210
                        sumread += read;
 
211
                }
 
212
                in.close();        
 
213
                out.writeBytes(LINE_END);
 
214
        }
 
215
 
 
216
        /**
 
217
         * @param string
 
218
         * @param urlDesc
 
219
         * @throws IOException 
 
220
         */
 
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);
 
226
        }
 
227
 
 
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) : '=');
 
237
                }
 
238
                return out.toString();
 
239
        }
 
240
}