package com.samknows.measurement.storage;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.commons.io.IOUtils;
import android.content.Context;
import android.util.Log;
import com.samknows.libcore.SKPorting;
import com.samknows.libcore.SKConstants;
import com.samknows.measurement.util.OtherUtils;
public class TestResultsManager {
private static File storage;
public static void setStorage(File storage) {
TestResultsManager.storage = storage;
}
//
// This is the main entry point for saving results json data.
// 1. Save-off via ExportFile (this creates an archive for future export)
// 2. Append to "test_results_to_submit" ... this might be malformed JSON data from what I
// can see.
// On iOS, the results are saved to separate .json files for subsequent upload, there is
// never any attempt to 'merge' them.
//
public static void saveResult(Context c, ResultsContainer rc) {
ExportFile.saveResults(rc.getJSON());
saveResult(c, rc.getJSON().toString());
}
public static void saveResult(Context c, List<String> results) {
//if there is nothing to save returns immediately
if (results.size() == 0) {
return;
}
DataOutputStream dos = openOutputFile(c);
if (dos == null) {
SKPorting.sAssertE(TestResultsManager.class, "Impossible to save results");
return;
}
try {
for (String outRes : results) {
dos.writeBytes(outRes);
dos.writeBytes("\r\n");
}
} catch (IOException ioe) {
SKPorting.sAssertE(TestResultsManager.class, "Error while saving results: " + ioe.getMessage());
} finally {
IOUtils.closeQuietly(dos);
}
}
//Tries to open output file, in case of failures returns null
private static DataOutputStream openOutputFile(Context c) {
DataOutputStream ret = null;
try {
FileOutputStream os = c.openFileOutput(SKConstants.TEST_RESULTS_TO_SUBMIT_FILE_NAME, Context.MODE_APPEND);
ret = new DataOutputStream(os);
} catch (FileNotFoundException fnfe) {
SKPorting.sAssertE(TestResultsManager.class, SKConstants.TEST_RESULTS_TO_SUBMIT_FILE_NAME + " not found!");
ret = null;
} catch (Exception e) {
SKPorting.sAssert(false);
}
return ret;
}
public static void saveResult(Context c, String jsonStr) {
if (OtherUtils.isDebuggable(c)) {
// Debuggable build - so dump-out the JSON string!
// You can use web services such as http://jsonformatter.curiousconcept.com/#jsonformatter to prettify
// the output from this Log.d statement; assuming it isn't truncated.
Log.d("TestResultsManager", "******** saveJSON jsonStr... (" + jsonStr + ")");
// Enable the following if you want prettified JSON output for a very long JSON string;
// useful sometimes, as the standard Log.d has a limited buffer size that it will output.
// try {
// // http://stackoverflow.com/questions/6185337/how-do-i-pretty-print-existing-json-data-with-java
// String prettyJsonString = new JSONObject(jsonStr).toString(2);
// SKLogger.d(TestResultsManager.class.getName(), prettyJsonString);
// } catch (JSONException e) {
// SKLogger.sAssert(TestResultsManager.class, false);
// }
}
DataOutputStream dos = openOutputFile(c);
if (dos == null) {
SKPorting.sAssertE(TestResultsManager.class, "Impossible to save results");
return;
}
try {
dos.write(jsonStr.getBytes("UTF-8"));
dos.writeBytes("\r\n");
} catch (IOException ioe) {
SKPorting.sAssertE(TestResultsManager.class, "Error while saving results: " + ioe.getMessage());
} finally {
IOUtils.closeQuietly(dos);
}
}
public static byte[] getJSONDataAsByteArray(Context c) {
InputStream is = null;
try {
is = c.openFileInput(SKConstants.TEST_RESULTS_TO_SUBMIT_FILE_NAME);
return IOUtils.toByteArray(is);
} catch (Exception e) {
Log.w(TestResultsManager.class.getName(), "no tests result file available");
return null;
} finally {
IOUtils.closeQuietly(is);
}
}
public static void clearResults(Context context) {
context.deleteFile(SKConstants.TEST_RESULTS_TO_SUBMIT_FILE_NAME);
}
public static void saveSubmittedLogs(Context c, byte[] logs) {
File logFile = new File(storage, SKConstants.TEST_RESULTS_SUBMITTED_FILE_NAME);
FileOutputStream is = null;
if (!logFile.exists()) {
try {
boolean bRes = logFile.createNewFile();
SKPorting.sAssert(bRes);
} catch (IOException e) {
SKPorting.sAssertE("TestResultsManager", "failed to save submitted logs to file", e);
return;
}
}
try {
if (!logFile.exists()) {
boolean bRes = logFile.createNewFile();
SKPorting.sAssert(bRes);
}
is = new FileOutputStream(logFile, true);
is.write(logs);
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
}
verifyReduceSize(logFile);
}
private static void verifyReduceSize(File logFile) {
if (logFile.length() > SKConstants.SUBMITED_LOGS_MAX_SIZE) {
File temp = new File(logFile.getAbsolutePath() + "_tmp");
BufferedReader reader = null;
FileWriter writer = null;
try {
reader = new BufferedReader(new FileReader(logFile));
reader.skip(logFile.length() - SKConstants.SUBMITED_LOGS_MAX_SIZE / 2);
reader.readLine();
writer = new FileWriter(temp);
IOUtils.copy(reader, writer);
writer.close();
reader.close();
//noinspection ResultOfMethodCallIgnored
logFile.delete();
//noinspection ResultOfMethodCallIgnored
temp.renameTo(logFile);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(writer);
}
}
}
public static String[] getJSONDataAsStringArray(Context context) {
// This might return MORE THAN ONE test batch, each one as JSON String on a separate line per batch!
byte[] data = getJSONDataAsByteArray(context);
if (data == null) {
return new String[]{};
}
String results = null;
try {
results = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
SKPorting.sAssert(false);
results = new String(data);
}
return results.split("\r\n");
}
}