use of org.opendatakit.httpclientandroidlib.protocol.HttpContext in project collect by opendatakit.
the class DownloadFormListTask method downloadMediaFileList.
private List<MediaFile> downloadMediaFileList(String manifestUrl) {
if (manifestUrl == null) {
return null;
}
// get shared HttpContext so that authentication and cookies are retained.
HttpContext localContext = Collect.getInstance().getHttpContext();
HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
DocumentFetchResult result = WebUtils.getXmlDocument(manifestUrl, localContext, httpclient);
if (result.errorMessage != null) {
return null;
}
String errMessage = Collect.getInstance().getString(R.string.access_error, manifestUrl);
if (!result.isOpenRosaResponse) {
errMessage += Collect.getInstance().getString(R.string.manifest_server_error);
Timber.e(errMessage);
return null;
}
// Attempt OpenRosa 1.0 parsing
Element manifestElement = result.doc.getRootElement();
if (!manifestElement.getName().equals("manifest")) {
errMessage += Collect.getInstance().getString(R.string.root_element_error, manifestElement.getName());
Timber.e(errMessage);
return null;
}
String namespace = manifestElement.getNamespace();
if (!DownloadFormsTask.isXformsManifestNamespacedElement(manifestElement)) {
errMessage += Collect.getInstance().getString(R.string.root_namespace_error, namespace);
Timber.e(errMessage);
return null;
}
int elements = manifestElement.getChildCount();
List<MediaFile> files = new ArrayList<>();
for (int i = 0; i < elements; ++i) {
if (manifestElement.getType(i) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element mediaFileElement = manifestElement.getElement(i);
if (!DownloadFormsTask.isXformsManifestNamespacedElement(mediaFileElement)) {
// someone else's extension?
continue;
}
String name = mediaFileElement.getName();
if (name.equalsIgnoreCase("mediaFile")) {
String filename = null;
String hash = null;
String downloadUrl = null;
// don't process descriptionUrl
int childCount = mediaFileElement.getChildCount();
for (int j = 0; j < childCount; ++j) {
if (mediaFileElement.getType(j) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element child = mediaFileElement.getElement(j);
if (!DownloadFormsTask.isXformsManifestNamespacedElement(child)) {
// someone else's extension?
continue;
}
String tag = child.getName();
switch(tag) {
case "filename":
filename = XFormParser.getXMLText(child, true);
if (filename != null && filename.length() == 0) {
filename = null;
}
break;
case "hash":
hash = XFormParser.getXMLText(child, true);
if (hash != null && hash.length() == 0) {
hash = null;
}
break;
case "downloadUrl":
downloadUrl = XFormParser.getXMLText(child, true);
if (downloadUrl != null && downloadUrl.length() == 0) {
downloadUrl = null;
}
break;
}
}
if (filename == null || downloadUrl == null || hash == null) {
errMessage += Collect.getInstance().getString(R.string.manifest_tag_error, Integer.toString(i));
Timber.e(errMessage);
return null;
}
files.add(new MediaFile(filename, hash, downloadUrl));
}
}
return files;
}
use of org.opendatakit.httpclientandroidlib.protocol.HttpContext in project collect by opendatakit.
the class DownloadFormsTask method downloadFile.
/**
* Common routine to download a document from the downloadUrl and save the contents in the file
* 'file'. Shared by media file download and form file download.
* <p>
* SurveyCTO: The file is saved into a temp folder and is moved to the final place if everything
* is okay, so that garbage is not left over on cancel.
*
* @param file the final file
* @param downloadUrl the url to get the contents from.
*/
private void downloadFile(File file, String downloadUrl) throws IOException, TaskCancelledException, URISyntaxException, Exception {
File tempFile = File.createTempFile(file.getName(), TEMP_DOWNLOAD_EXTENSION, new File(Collect.CACHE_PATH));
URI uri;
try {
// assume the downloadUrl is escaped properly
URL url = new URL(downloadUrl);
uri = url.toURI();
} catch (MalformedURLException | URISyntaxException e) {
Timber.e(e, "Unable to get a URI for download URL : %s due to %s : ", downloadUrl, e.getMessage());
throw e;
}
// WiFi network connections can be renegotiated during a large form download sequence.
// This will cause intermittent download failures. Silently retry once after each
// failure. Only if there are two consecutive failures do we abort.
boolean success = false;
int attemptCount = 0;
final int MAX_ATTEMPT_COUNT = 2;
while (!success && ++attemptCount <= MAX_ATTEMPT_COUNT) {
if (isCancelled()) {
throw new TaskCancelledException(tempFile);
}
Timber.i("Started downloading to %s from %s", tempFile.getAbsolutePath(), downloadUrl);
// get shared HttpContext so that authentication and cookies are retained.
HttpContext localContext = Collect.getInstance().getHttpContext();
HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
// set up request...
HttpGet req = WebUtils.createOpenRosaHttpGet(uri);
req.addHeader(WebUtils.ACCEPT_ENCODING_HEADER, WebUtils.GZIP_CONTENT_ENCODING);
HttpResponse response;
try {
response = httpclient.execute(req, localContext);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
WebUtils.discardEntityBytes(response);
if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
// clear the cookies -- should not be necessary?
Collect.getInstance().getCookieStore().clear();
}
String errMsg = Collect.getInstance().getString(R.string.file_fetch_failed, downloadUrl, response.getStatusLine().getReasonPhrase(), String.valueOf(statusCode));
Timber.e(errMsg);
throw new Exception(errMsg);
}
// write connection to file
InputStream is = null;
OutputStream os = null;
try {
HttpEntity entity = response.getEntity();
is = entity.getContent();
Header contentEncoding = entity.getContentEncoding();
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase(WebUtils.GZIP_CONTENT_ENCODING)) {
is = new GZIPInputStream(is);
}
os = new FileOutputStream(tempFile);
byte[] buf = new byte[4096];
int len;
while ((len = is.read(buf)) > 0 && !isCancelled()) {
os.write(buf, 0, len);
}
os.flush();
success = true;
} finally {
if (os != null) {
try {
os.close();
} catch (Exception e) {
Timber.e(e);
}
}
if (is != null) {
try {
// ensure stream is consumed...
final long count = 1024L;
while (is.skip(count) == count) {
// skipping to the end of the http entity
}
} catch (Exception e) {
// no-op
}
try {
is.close();
} catch (Exception e) {
Timber.e(e);
}
}
}
} catch (Exception e) {
Timber.e(e.toString());
// silently retry unless this is the last attempt,
// in which case we rethrow the exception.
FileUtils.deleteAndReport(tempFile);
if (attemptCount == MAX_ATTEMPT_COUNT) {
throw e;
}
}
if (isCancelled()) {
FileUtils.deleteAndReport(tempFile);
throw new TaskCancelledException(tempFile);
}
}
Timber.d("Completed downloading of %s. It will be moved to the proper path...", tempFile.getAbsolutePath());
FileUtils.deleteAndReport(file);
String errorMessage = FileUtils.copyFile(tempFile, file);
if (file.exists()) {
Timber.w("Copied %s over %s", tempFile.getAbsolutePath(), file.getAbsolutePath());
FileUtils.deleteAndReport(tempFile);
} else {
String msg = Collect.getInstance().getString(R.string.fs_file_copy_error, tempFile.getAbsolutePath(), file.getAbsolutePath(), errorMessage);
Timber.w(msg);
throw new RuntimeException(msg);
}
}
use of org.opendatakit.httpclientandroidlib.protocol.HttpContext in project collect by opendatakit.
the class DownloadFormsTask method downloadManifestAndMediaFiles.
private String downloadManifestAndMediaFiles(String tempMediaPath, String finalMediaPath, FormDetails fd, int count, int total) throws Exception {
if (fd.getManifestUrl() == null) {
return null;
}
publishProgress(Collect.getInstance().getString(R.string.fetching_manifest, fd.getFormName()), String.valueOf(count), String.valueOf(total));
List<MediaFile> files = new ArrayList<MediaFile>();
// get shared HttpContext so that authentication and cookies are retained.
HttpContext localContext = Collect.getInstance().getHttpContext();
HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);
DocumentFetchResult result = WebUtils.getXmlDocument(fd.getManifestUrl(), localContext, httpclient);
if (result.errorMessage != null) {
return result.errorMessage;
}
String errMessage = Collect.getInstance().getString(R.string.access_error, fd.getManifestUrl());
if (!result.isOpenRosaResponse) {
errMessage += Collect.getInstance().getString(R.string.manifest_server_error);
Timber.e(errMessage);
return errMessage;
}
// Attempt OpenRosa 1.0 parsing
Element manifestElement = result.doc.getRootElement();
if (!manifestElement.getName().equals("manifest")) {
errMessage += Collect.getInstance().getString(R.string.root_element_error, manifestElement.getName());
Timber.e(errMessage);
return errMessage;
}
String namespace = manifestElement.getNamespace();
if (!isXformsManifestNamespacedElement(manifestElement)) {
errMessage += Collect.getInstance().getString(R.string.root_namespace_error, namespace);
Timber.e(errMessage);
return errMessage;
}
int elements = manifestElement.getChildCount();
for (int i = 0; i < elements; ++i) {
if (manifestElement.getType(i) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element mediaFileElement = manifestElement.getElement(i);
if (!isXformsManifestNamespacedElement(mediaFileElement)) {
// someone else's extension?
continue;
}
String name = mediaFileElement.getName();
if (name.equalsIgnoreCase("mediaFile")) {
String filename = null;
String hash = null;
String downloadUrl = null;
// don't process descriptionUrl
int childCount = mediaFileElement.getChildCount();
for (int j = 0; j < childCount; ++j) {
if (mediaFileElement.getType(j) != Element.ELEMENT) {
// e.g., whitespace (text)
continue;
}
Element child = mediaFileElement.getElement(j);
if (!isXformsManifestNamespacedElement(child)) {
// someone else's extension?
continue;
}
String tag = child.getName();
switch(tag) {
case "filename":
filename = XFormParser.getXMLText(child, true);
if (filename != null && filename.length() == 0) {
filename = null;
}
break;
case "hash":
hash = XFormParser.getXMLText(child, true);
if (hash != null && hash.length() == 0) {
hash = null;
}
break;
case "downloadUrl":
downloadUrl = XFormParser.getXMLText(child, true);
if (downloadUrl != null && downloadUrl.length() == 0) {
downloadUrl = null;
}
break;
}
}
if (filename == null || downloadUrl == null || hash == null) {
errMessage += Collect.getInstance().getString(R.string.manifest_tag_error, Integer.toString(i));
Timber.e(errMessage);
return errMessage;
}
files.add(new MediaFile(filename, hash, downloadUrl));
}
}
// OK we now have the full set of files to download...
Timber.i("Downloading %d media files.", files.size());
int mediaCount = 0;
if (files.size() > 0) {
File tempMediaDir = new File(tempMediaPath);
File finalMediaDir = new File(finalMediaPath);
FileUtils.checkMediaPath(tempMediaDir);
FileUtils.checkMediaPath(finalMediaDir);
for (MediaFile toDownload : files) {
++mediaCount;
publishProgress(Collect.getInstance().getString(R.string.form_download_progress, fd.getFormName(), String.valueOf(mediaCount), String.valueOf(files.size())), String.valueOf(count), String.valueOf(total));
// try {
File finalMediaFile = new File(finalMediaDir, toDownload.getFilename());
File tempMediaFile = new File(tempMediaDir, toDownload.getFilename());
if (!finalMediaFile.exists()) {
downloadFile(tempMediaFile, toDownload.getDownloadUrl());
} else {
String currentFileHash = FileUtils.getMd5Hash(finalMediaFile);
String downloadFileHash = getMd5Hash(toDownload.getHash());
if (currentFileHash != null && downloadFileHash != null && !currentFileHash.contentEquals(downloadFileHash)) {
// if the hashes match, it's the same file
// otherwise delete our current one and replace it with the new one
FileUtils.deleteAndReport(finalMediaFile);
downloadFile(tempMediaFile, toDownload.getDownloadUrl());
} else {
// exists, and the hash is the same
// no need to download it again
Timber.i("Skipping media file fetch -- file hashes identical: %s", finalMediaFile.getAbsolutePath());
}
}
// } catch (Exception e) {
// return e.getLocalizedMessage();
// }
}
}
return null;
}
use of org.opendatakit.httpclientandroidlib.protocol.HttpContext in project collect by opendatakit.
the class Collect method getHttpContext.
/**
* Construct and return a session context with shared cookieStore and credsProvider so a user
* does not have to re-enter login information.
*/
public synchronized HttpContext getHttpContext() {
// context holds authentication state machine, so it cannot be
// shared across independent activities.
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
localContext.setAttribute(HttpClientContext.CREDS_PROVIDER, credsProvider);
return localContext;
}
use of org.opendatakit.httpclientandroidlib.protocol.HttpContext in project collect by opendatakit.
the class InstanceServerUploader method processChunk.
private boolean processChunk(int low, int high, Outcome outcome, Long... values) {
if (values == null) {
// don't try anything if values is null
return false;
}
StringBuilder selectionBuf = new StringBuilder(InstanceColumns._ID + " IN (");
String[] selectionArgs = new String[high - low];
for (int i = 0; i < (high - low); i++) {
if (i > 0) {
selectionBuf.append(",");
}
selectionBuf.append("?");
selectionArgs[i] = values[i + low].toString();
}
selectionBuf.append(")");
String selection = selectionBuf.toString();
String deviceId = new PropertyManager(Collect.getInstance().getApplicationContext()).getSingularProperty(PropertyManager.withUri(PropertyManager.PROPMGR_DEVICE_ID));
// get shared HttpContext so that authentication and cookies are retained.
HttpContext localContext = Collect.getInstance().getHttpContext();
Map<Uri, Uri> uriRemap = new HashMap<Uri, Uri>();
Cursor c = null;
try {
c = new InstancesDao().getInstancesCursor(selection, selectionArgs);
if (c != null && c.getCount() > 0) {
c.moveToPosition(-1);
while (c.moveToNext()) {
if (isCancelled()) {
return false;
}
publishProgress(c.getPosition() + 1 + low, values.length);
String instance = c.getString(c.getColumnIndex(InstanceColumns.INSTANCE_FILE_PATH));
String id = c.getString(c.getColumnIndex(InstanceColumns._ID));
Uri toUpdate = Uri.withAppendedPath(InstanceColumns.CONTENT_URI, id);
// Use the app's configured URL unless the form included a submission URL
int subIdx = c.getColumnIndex(InstanceColumns.SUBMISSION_URI);
String urlString = c.isNull(subIdx) ? getServerSubmissionURL() : c.getString(subIdx).trim();
// add the deviceID to the request...
try {
urlString += "?deviceID=" + URLEncoder.encode(deviceId, "UTF-8");
} catch (UnsupportedEncodingException e) {
// unreachable...
Timber.i(e, "Error encoding URL for device id : %s", deviceId);
}
if (!uploadOneSubmission(urlString, id, instance, toUpdate, localContext, uriRemap, outcome)) {
// get credentials...
return false;
}
}
}
} finally {
if (c != null) {
c.close();
}
}
return true;
}
Aggregations