I am developing a voice-based app in android and facing some problems please see below code,
Java File 1
file = .wav file
public static AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
return getAudioInputStreamImpl(file);
}
private static AudioInputStream getAudioInputStreamImpl(Object source) throws UnsupportedAudioFileException, IOException {
GetAudioInputStreamAudioFileReaderAction action = new GetAudioInputStreamAudioFileReaderAction(source);
doAudioFileReaderIteration(action);
AudioInputStream audioInputStream = action.getAudioInputStream();
if (audioInputStream != null) {
return audioInputStream;
}
throw new UnsupportedAudioFileException("format not supported");
}
private static void doAudioFileReaderIteration(AudioFileReaderAction action) throws IOException {
Iterator audioFileReaders = TAudioConfig.getAudioFileReaders();
boolean bCompleted = false;
while (audioFileReaders.hasNext() && !bCompleted) {
AudioFileReader audioFileReader = (AudioFileReader) audioFileReaders.next();
bCompleted = action.handleAudioFileReader(audioFileReader);
}
}
Java file 2 (TAudioConfig)
public static synchronized Iterator<AudioFileReader> getAudioFileReaders() {
Iterator<AudioFileReader> it;
synchronized (TAudioConfig.class) {
it = getAudioFileReadersImpl().iterator();
}
return it;
}
private static synchronized Set<AudioFileReader> getAudioFileReadersImpl() {
Set<AudioFileReader> set;
synchronized (TAudioConfig.class) {
if (sm_audioFileReaders == null) {
sm_audioFileReaders = new ArraySet();
registerAudioFileReaders();
}
set = sm_audioFileReaders;
}
return set;
}
private static void registerAudioFileReaders() {
TInit.registerClasses(AudioFileReader.class, new C00001());
}
Java File 3 (TInit)
public static void registerClasses(Class providerClass, ProviderRegistrationAction action) {
Iterator providers = Service.providers(providerClass);
if (providers != null) {
while (providers.hasNext()) {
try {
action.register(providers.next());
} catch (Throwable e) {
}
}
}
}
Java File 4 (Service)
public static Iterator<?> providers(Class<?> cls) {
String strFullName = "com/example/voiceautomator/AudioFileReader.class";
Iterator<?> iterator = createInstancesList(strFullName).iterator();
return iterator;
}
private static List<Object> createInstancesList(String strFullName) {
List<Object> providers = new ArrayList<Object>();
Iterator<?> classNames = createClassNames(strFullName);
if (classNames != null) {
while (classNames.hasNext()) {
String strClassName = (String) classNames.next();
try {
Class<?> cls = Class.forName(strClassName, REVERSE_ORDER, ClassLoader.getSystemClassLoader());
providers.add(0, cls.newInstance());
} catch (Throwable e) {
}
}
}
return providers;
}
private static Iterator<String> createClassNames(String strFullName) {
Set<String> providers = new ArraySet<String>();
Enumeration<?> configs = null;
try {
configs = Service.class.getClassLoader().getSystemResources(strFullName);
} catch (Throwable e) {
}
if (configs != null) {
while (configs.hasMoreElements()) {
URL configFileUrl = (URL) configs.nextElement();
InputStream input = null;
try {
input = configFileUrl.openStream();
} catch (Throwable e2) {
}
if (input != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try {
for (String strLine = reader.readLine(); strLine != null; strLine = reader.readLine()) {
strLine = strLine.trim();
int nPos = strLine.indexOf(35);
if (nPos >= 0) {
strLine = strLine.substring(0, nPos);
}
if (strLine.length() > 0) {
providers.add(strLine);
}
}
} catch (Throwable e22) {
}
}
}
}
Iterator<String> iterator = providers.iterator();
return iterator;
}
getClassLoader().getSystemResources in the Java File 4 (Service) gives me TwoEnumerationsInOne and configs.hasMoreElements() gives false so not able to go into while loop.
AudioFileReader.java is included in the package
Please guide me to resolve this issue?
Please don't forget I am working on this code in an android project
Please see the value of configs here
http://capsicumtech.in/Screenshot_1.png
Thanks in advance.
Related
I want to know some of the reasons that can cause below exception. I am unable to find this message Cannot find message in jsch-0.1.54.jar. There exists some straight forward messages like file not found and others that make sense. But I need more information about this one so that I can reach to the root cause.
SftpException while running get ---> 2: Cannot find message [/destination/file.txt]
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2289)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:1741)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:1758)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:786)
at com.jcraft.jsch.ChannelSftp.get(ChannelSftp.java:750)
at com.iyi.ftp.SFTP.get(SFTP.java:99)
Here is my calling method.
public boolean get(final String remoteFile, final String localFile) throws JSchException {
Vector connection = null;
Session session = null;
ChannelSftp c = null;
boolean status = false;
try {
connection = this.connect();
session = connection.get(0);
c = connection.get(1);
c.get(remoteFile, localFile);
status = true;
}
catch (JSchException e) {
SFTP.LGR.warn((Object)("JSchException in SFTP::get() ---> " + FTPFactory.getStackTrace((Throwable)e)));
throw e;
}
catch (SftpException e2) {
SFTP.LGR.warn((Object)("SftpException while running get ---> " + FTPFactory.getStackTrace((Throwable)e2)));
throw new JSchException(e2.getMessage());
}
catch (CredentialDecryptionException e3) {
SFTP.LGR.error((Object)"##CredentialDecryptionException##", (Throwable)e3);
throw new JSchException(e3.getMessage(), (Throwable)e3);
}
finally {
if (c != null) {
c.quit();
}
if (session != null) {
session.disconnect();
}
}
if (c != null) {
c.quit();
}
if (session != null) {
session.disconnect();
}
return status;
}
These methods are fetched from jsch-0.1.54.jar which is an open source utility.
public void get(String src, String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException {
boolean _dstExist = false;
String _dst = null;
try {
((MyPipedInputStream)this.io_in).updateReadSide();
src = this.remoteAbsolutePath(src);
dst = this.localAbsolutePath(dst);
final Vector v = this.glob_remote(src);
final int vsize = v.size();
if (vsize == 0) {
throw new SftpException(2, "No such file");
}
final File dstFile = new File(dst);
final boolean isDstDir = dstFile.isDirectory();
StringBuffer dstsb = null;
if (isDstDir) {
if (!dst.endsWith(ChannelSftp.file_separator)) {
dst += ChannelSftp.file_separator;
}
dstsb = new StringBuffer(dst);
}
else if (vsize > 1) {
throw new SftpException(4, "Copying multiple files, but destination is missing or a file.");
}
for (int j = 0; j < vsize; ++j) {
final String _src = v.elementAt(j);
final SftpATTRS attr = this._stat(_src);
if (attr.isDir()) {
throw new SftpException(4, "not supported to get directory " + _src);
}
_dst = null;
if (isDstDir) {
final int i = _src.lastIndexOf(47);
if (i == -1) {
dstsb.append(_src);
}
else {
dstsb.append(_src.substring(i + 1));
}
_dst = dstsb.toString();
if (_dst.indexOf("..") != -1) {
final String dstc = new File(dst).getCanonicalPath();
final String _dstc = new File(_dst).getCanonicalPath();
if (_dstc.length() <= dstc.length() || !_dstc.substring(0, dstc.length() + 1).equals(dstc + ChannelSftp.file_separator)) {
throw new SftpException(4, "writing to an unexpected file " + _src);
}
}
dstsb.delete(dst.length(), _dst.length());
}
else {
_dst = dst;
}
final File _dstFile = new File(_dst);
if (mode == 1) {
final long size_of_src = attr.getSize();
final long size_of_dst = _dstFile.length();
if (size_of_dst > size_of_src) {
throw new SftpException(4, "failed to resume for " + _dst);
}
if (size_of_dst == size_of_src) {
return;
}
}
if (monitor != null) {
monitor.init(1, _src, _dst, attr.getSize());
if (mode == 1) {
monitor.count(_dstFile.length());
}
}
FileOutputStream fos = null;
_dstExist = _dstFile.exists();
try {
if (mode == 0) {
fos = new FileOutputStream(_dst);
}
else {
fos = new FileOutputStream(_dst, true);
}
this._get(_src, fos, monitor, mode, new File(_dst).length());
}
finally {
if (fos != null) {
fos.close();
}
}
}
}
catch (Exception e) {
if (!_dstExist && _dst != null) {
final File _dstFile2 = new File(_dst);
if (_dstFile2.exists() && _dstFile2.length() == 0L) {
_dstFile2.delete();
}
}
if (e instanceof SftpException) {
throw (SftpException)e;
}
if (e instanceof Throwable) {
throw new SftpException(4, "", e);
}
throw new SftpException(4, "");
}
}
private SftpATTRS _stat(final byte[] path) throws SftpException {
try {
this.sendSTAT(path);
Header header = new Header();
header = this.header(this.buf, header);
final int length = header.length;
final int type = header.type;
this.fill(this.buf, length);
if (type != 105) {
if (type == 101) {
final int i = this.buf.getInt();
this.throwStatusError(this.buf, i);
}
throw new SftpException(4, "");
}
final SftpATTRS attr = SftpATTRS.getATTR(this.buf);
return attr;
}
catch (Exception e) {
if (e instanceof SftpException) {
throw (SftpException)e;
}
if (e instanceof Throwable) {
throw new SftpException(4, "", e);
}
throw new SftpException(4, "");
}
}
The error message comes from your server. It's indeed quite strange message, but I assume that it's some custom SFTP server that deals with some "messages" rather than plain files.
So the message basically translates to "Cannot find file" error of a traditional SFTP server. Even the error code 2 (SSH_FX_NO_SUCH_FILE) supports that.
Your path in remoteFile is probably wrong.
I'd like to use zuul to cache some requests. The Cache is stored in a Redis as a POJO and contains plaintext (not gzip compressed data).
For normal tests and integration tests, everything works pretty well. With a jmeter load test, some of the requests fails with
java.util.zip.ZipException: Not in GZIP format (from jmeter)
We figure out, that at this point, zuul is returning an empty response.
My PreFilter:
public class CachePreFilter extends CacheBaseFilter {
private static DynamicIntProperty INITIAL_STREAM_BUFFER_SIZE = DynamicPropertyFactory.getInstance().getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 8192);
#Autowired
CounterService counterService;
public CachePreFilter(RedisCacheManager redisCacheManager, Properties properties) {
super(redisCacheManager, properties);
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
CachedResponse data = getFromCache(ctx);
if (null != data) {
counterService.increment("counter.cached");
HttpServletResponse response = ctx.getResponse();
response.addHeader("X-Cache", "HIT");
if (null != data.getContentType()) {
response.setContentType(data.getContentType());
}
if (null != data.getHeaders()) {
for (Entry<String, String> header : data.getHeaders().entrySet()) {
if (!response.containsHeader(header.getKey())) {
response.addHeader(header.getKey(), header.getValue());
}
}
}
OutputStream outStream = null;
try {
outStream = response.getOutputStream();
boolean isGzipRequested = ctx.isGzipRequested();
if (null != data.getBody()) {
final String requestEncoding = ctx.getRequest().getHeader(ZuulHeaders.ACCEPT_ENCODING);
if (requestEncoding != null && HTTPRequestUtils.getInstance().isGzipped(requestEncoding)) {
isGzipRequested = true;
}
ByteArrayOutputStream byteArrayOutputStream = null;
ByteArrayInputStream is = null;
try {
if (isGzipRequested) {
byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(data.getBody().getBytes(StandardCharsets.UTF_8));
gzipOutputStream.flush();
gzipOutputStream.close();
ctx.setResponseGZipped(true);
is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
logger.debug(String.format("Send gzip content %s", data.getBody()));
response.setHeader(ZuulHeaders.CONTENT_ENCODING, "gzip");
} else {
logger.debug(String.format("Send content %s", data.getBody()));
is = new ByteArrayInputStream(data.getBody().getBytes(StandardCharsets.UTF_8));
}
writeResponse(is, outStream);
} catch (Exception e) {
logger.error("Error at sending response " + e.getMessage(), e);
throw new RuntimeException("Failed to send content", e);
} finally {
if (null != byteArrayOutputStream) {
byteArrayOutputStream.close();
}
if (null != is) {
is.close();
}
}
}
ctx.setSendZuulResponse(false);
} catch (IOException e) {
logger.error("Cannot read from Stream " + e.getMessage(), e.getMessage());
} finally {
// don't close the outputstream
}
ctx.set(CACHE_HIT, true);
return data;
} else {
counterService.increment("counter.notcached");
}
ctx.set(CACHE_HIT, false);
return null;
}
private ThreadLocal<byte[]> buffers = new ThreadLocal<byte[]>() {
#Override
protected byte[] initialValue() {
return new byte[INITIAL_STREAM_BUFFER_SIZE.get()];
}
};
private void writeResponse(InputStream zin, OutputStream out) throws Exception {
byte[] bytes = buffers.get();
int bytesRead = -1;
while ((bytesRead = zin.read(bytes)) != -1) {
out.write(bytes, 0, bytesRead);
}
}
#Override
public int filterOrder() {
return 99;
}
#Override
public String filterType() {
return "pre";
}
}
My Post Filter
public class CachePostFilter extends CacheBaseFilter {
public CachePostFilter(RedisCacheManager redisCacheManager, Properties properties) {
super(redisCacheManager, properties);
}
#Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return super.shouldFilter() && !ctx.getBoolean(CACHE_HIT);
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
HttpServletResponse res = ctx.getResponse();
if (isSuccess(res, ctx.getOriginResponseHeaders())) {
// Store only successful responses
String cacheKey = cacheKey(req);
if (cacheKey != null) {
String body = null;
if (null != ctx.getResponseBody()) {
body = ctx.getResponseBody();
} else if (null != ctx.getResponseDataStream()) {
InputStream is = null;
try {
is = ctx.getResponseDataStream();
final Long len = ctx.getOriginContentLength();
if (len == null || len > 0) {
if (ctx.getResponseGZipped()) {
is = new GZIPInputStream(is);
}
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
body = writer.toString();
if (null != body && !body.isEmpty()) {
ctx.setResponseDataStream(new ByteArrayInputStream(body.getBytes()));
ctx.setResponseGZipped(false);
ctx.setOriginContentLength(String.valueOf(body.getBytes().length));
} else {
ctx.setResponseBody("{}");
}
}
} catch (IOException e) {
logger.error("Cannot read body " + e.getMessage(), e);
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
}
}
}
saveToCache(ctx, cacheKey, body);
}
}
}
return null;
}
#Override
public int filterOrder() {
return 1;
}
#Override
public String filterType() {
return "post";
}
private boolean isSuccess(HttpServletResponse res, List<Pair<String, String>> originHeaders) {
if (res != null && res.getStatus() < 300) {
if (null != originHeaders) {
for (Pair<String, String> header : originHeaders) {
if (header.first().equals("X-CACHEABLE") && header.second().equals("1")) {
return true;
}
}
}
}
return false;
}
We test it without Redis (just store it into a local variable) and this is still the same. We logged always the response from cache (before gzip) and everything looks good.
(Posted on behalf of the question author).
Solution
We refactor our PostFilter and don't change so much in the Response for zuul. After this change, we don't see any problems any more:
Working Post Filter
public class CachePostFilter extends CacheBaseFilter {
public CachePostFilter(RedisCacheManager redisCacheManager, Properties properties) {
super(redisCacheManager, properties);
}
#Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return super.shouldFilter() && !ctx.getBoolean(CACHE_HIT);
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
HttpServletResponse res = ctx.getResponse();
if (isSuccess(res, ctx.getOriginResponseHeaders())) {
// Store only successful responses
String cacheKey = cacheKey(req);
if (cacheKey != null) {
String body = null;
if (null != ctx.getResponseBody()) {
body = ctx.getResponseBody();
} else if (null != ctx.getResponseDataStream()) {
InputStream rawInputStream = null;
InputStream gzipByteArrayInputStream = null;
try {
rawInputStream = ctx.getResponseDataStream();
gzipByteArrayInputStream = null;
// If origin tell it's GZipped but the content is ZERO
// bytes,
// don't try to uncompress
final Long len = ctx.getOriginContentLength();
if (len == null || len > 0) {
byte[] rawData = IOUtils.toByteArray(rawInputStream);
ctx.setResponseDataStream(new ByteArrayInputStream(rawData));
if (ctx.getResponseGZipped()) {
gzipByteArrayInputStream = new GZIPInputStream(new ByteArrayInputStream(rawData));
} else {
gzipByteArrayInputStream = new ByteArrayInputStream(rawData);
}
StringWriter writer = new StringWriter();
IOUtils.copy(gzipByteArrayInputStream, writer, "UTF-8");
body = writer.toString();
}
} catch (IOException e) {
logger.error("Cannot read body " + e.getMessage(), e);
} finally {
if (null != rawInputStream) {
try {
rawInputStream.close();
} catch (IOException e) {
}
}
if (null != gzipByteArrayInputStream) {
try {
gzipByteArrayInputStream.close();
} catch (IOException e) {
}
}
}
// if we read from the stream, the other filter cannot read
// and they dont' deliver any response
// ctx.setResponseBody(body);
// ctx.setResponseGZipped(false);
saveToCache(ctx, cacheKey, body);
}
}
}
return null;
}
#Override
public int filterOrder() {
return 1;
}
#Override
public String filterType() {
return "post";
}
private boolean isSuccess(HttpServletResponse res, List<Pair<String, String>> originHeaders) {
if (res != null && res.getStatus() == 200) {
if (null != originHeaders) {
for (Pair<String, String> header : originHeaders) {
if (header.first().equals("X-CACHEABLE") && header.second().equals("1")) {
return true;
}
}
}
}
return false;
}
}
I have a custom ListView that uses an object class for its data. The users can add new items to the listview, the arraylist is then saved in SharedPreferences. However, I also want to save each individual item so that I can use it in another Expandable ListView, how could I create a file for each individual item the user creates, or perhaps there is a better why to do it? Thanks in advance. Here is the object class:
public class Item implements Serializable{
String homework, date, classes;
public Item(String homework, String date, String classes){
this.homework = homework;
this.date = date;
this.classes = classes;
}
public String getHomework(){
return homework;
}
public String getDate(){
return date;
}
public String getClasses(){
return classes;
}
}
Why not use a database?There is a bit of setting up, but after the initial set up writing/reading data is very easy.
https://developer.android.com/training/basics/data-storage/databases.html
An example of serialize-deserialize class
public final class Serialize
{
private static final String className = Serialize.class.getName();
public static void save(Object saveThis, String serializeFileName, Context context)
{
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try
{
if(saveThis != null)
{
fos = context.openFileOutput(serializeFileName, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(saveThis);
}
}
catch(Throwable t)
{
//log it
}
finally
{
if(oos != null)
{
try{oos.close();}catch(Throwable t){}
}
if(fos != null)
{
try{fos.close();}catch(Throwable t){}
}
}
}
public static Object read(String serializeFileName, Context context)
{
FileInputStream fis = null;
ObjectInputStream ois = null;
Object readThis = null;
try
{
File file = context.getFileStreamPath(serializeFileName);
if(file != null && file.exists())
{
fis = context.openFileInput(serializeFileName);
ois = new ObjectInputStream(fis);
readThis = ois.readObject();
}
}
catch(Throwable t)
{
//log it
}
finally
{
if(ois != null)
{
try{ois.close();}catch(Throwable t){}
}
if(fis != null)
{
try{fis.close();}catch(Throwable t){}
}
}
return readThis;
}
public static boolean delete(String serializeFileName, Context context)
{
boolean deleted = false;
try
{
File file = context.getFileStreamPath(serializeFileName);
if(file != null && (file.exists()))
{
deleted = file.delete();
}
}
catch(Throwable t)
{
//log it
}
return deleted;
}
public static boolean exist(String serializeFileName, Context context)
{
boolean exist = false;
try
{
File file = context.getFileStreamPath(serializeFileName);
if(file != null && (file.exists()))
{
exist = true;
}
}
catch(Throwable t)
{
//log it
}
return exist;
}
}
Use the save method to save the serializable object in a file and the read method to read it.
I am trying to parse a csv and map the fields to a POJO class. However I can see that the mapping is not achieved correctly.
I am trying to map the header from a POJO file to the csv.
public class CarCSVFileInputBean {
private long Id;
private String shortName;
private String Name;
private String Type;
private String Environment;
//getter and setters
}
Can someone please take a look at my code:
public class carCSVUtil {
private static Log log = LogFactory.getLog(carCSVUtil.class);
private static final List<String> fileHeaderFields = new ArrayList<String>();
private static final String UTF8CHARSET = "UTF-8";
static {
for (Field f : carCSVFileInputBean.class.getDeclaredFields()) {
fileHeaderFields.add(f.getName());
}
}
public static List<carCSVFileInputBean> getCSVInputList(InputStream inputStream) {
CSVReader reader = null;
List<carCSVFileInputBean> csvList = null;
carCSVFileInputBean inputRecord = null;
String[] header = null;
String[] row = null;
try {
reader = new CSVReader(new InputStreamReader(inputStream, UTF8CHARSET));
csvList = new ArrayList<carCSVFileInputBean>();
header = reader.readNext();
boolean isEmptyLine = true;
while ((row = reader.readNext()) != null) {
isEmptyLine = true;
if (!(row.length == 1 && StringUtils.isBlank(row[0]))) { // not an empty line, not even containing ','
inputRecord = new carCSVFileInputBean();
isEmptyLine = populateFields(inputRecord, header, row);
if (!isEmptyLine)
csvList.add(inputRecord);
}
}
} catch (IOException e) {
log.debug("IOException while accessing carCSVFileInputBean: " + e);
return null;
} catch (IllegalAccessException e) {
log.debug("IllegalAccessException while accessing carCSVFileInputBean: " + e);
return null;
} catch (InvocationTargetException e) {
log.debug("InvocationTargetException while copying carCSVFileInputBean properties: " + e);
return null;
} catch (Exception e) {
log.debug("Exception while parsing CSV file: " + e);
return null;
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException ioe) {}
}
return csvList;
}
protected static boolean populateFields(carCSVFileInputBean inputRecord, String[] header, String[] row) throws IllegalAccessException, InvocationTargetException {
boolean isEmptyLine = true;
for (int i = 0; i < row.length; i++) {
String val = row[i];
if (!StringUtils.isBlank(val)) {
BeanUtilsBean.getInstance().copyProperty(inputRecord, header[i], val);
isEmptyLine = false;
}
}
return isEmptyLine;
}
}
I found the solution - the headers in the csv file are expected to begin with a lowercase.
I want the simplest logger there is to simply log errors, mostly exceptions, to a Log file in the android file system. for exemple, the easiest and most convinient (in my opinion at least) way that i used to log to a file on PC java was by simply printing all exceptions to console and redirecting system out to both console and my file, this doesnt really suffice on android as far as i know i guess its because of how Android OS is designed, so what is the simplest way of doing it in Android?
Note that the project has already lot of code in it and i really wouldnt like to go over it and add log calls on catch blocks or whatever to log my exceptions, as little i need to do for logging those exceptions is best for my use case...
Thanks ahead!
It's not finished but works quite stable. It saves human readable json array with exception name, time, stack trace and additional data. Also you can save logcat's logs.
Using:
ExceptionWriter ew = new ExceptionWriter(new File(Environment.getExternalStorageDirectory(), "debug.txt"));
ew.w(new IllegalArgumentException("some msg"), "additional message");
Source:
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* User: elevenetc
* Date: 10/9/13
* Time: 12:52 PM
*/
public class ExceptionWriter {
private final StringBuilder sb;
private final ExceptionWriter.WriteExceptionTask writeExceptionTask;
private final SimpleDateFormat dataFormat;
private int totalExceptions;
private StringBuilder stackBuilder = new StringBuilder();
public int getTotalExceptions(){return totalExceptions;}
public ExceptionWriter(File file) throws IOException {
if(file != null){
writeExceptionTask = new WriteExceptionTask(file);
sb = new StringBuilder();
dataFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
new Thread(writeExceptionTask).start();
}else{
sb = null;
writeExceptionTask = null;
dataFormat = null;
}
}
public synchronized int wLogcat(){
try {
writeExceptionTask.addStreamToRead(Runtime.getRuntime().exec("logcat -d -v time").getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
public int w(Exception debugException, String caughtMessage){
return w(debugException, caughtMessage, null);
}
public synchronized int w(Exception debugException, String caughtMessage, String additionalData){
if(writeExceptionTask == null) return -1;
sb.setLength(0);
StackTraceElement[] stackTrace = debugException == null ? null : debugException.getStackTrace();
sb.append("{\"date\":\"");sb.append(getTime());
sb.append("\",\"exceptionClassName\":\"");sb.append(debugException == null ? null : debugException.getClass());
sb.append("\",\"exceptionMessage:\":\"");sb.append(debugException == null ? null : debugException.getMessage());
sb.append("\",\"caughtMessage:\":\"");sb.append(caughtMessage);
if(additionalData != null) {sb.append("\",\"data:\":\"");sb.append(additionalData);}
sb.append("\",\"stack\":");sb.append(stackToString(stackTrace));
sb.append("},");
writeExceptionTask.stringQueue.add(sb.toString());
totalExceptions++;
return 0;
}
public void destroy() {
if(writeExceptionTask != null) {
writeExceptionTask.stop();
}
}
private String getTime(){
return dataFormat.format(System.currentTimeMillis());
}
private String stackToString(StackTraceElement[] stackTrace){
if(stackTrace == null) return null;
stackBuilder.setLength(0);
stackBuilder.append("[");
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement e = stackTrace[i];
stackBuilder.append("{\"");
stackBuilder.append(e.getLineNumber());
stackBuilder.append("\":\"");
stackBuilder.append(e.getClassName());
stackBuilder.append(".");
stackBuilder.append(e.getMethodName());
stackBuilder.append("\"}");
if(i != stackTrace.length -1) stackBuilder.append(",");
}
stackBuilder.append("]");
return stackBuilder.toString();
}
///////////////////////////////////////////////
/// Static classes
///////////////////////////////////////////////
private class WriteExceptionTask implements Runnable {
private final File file;
private boolean running;
private final ConcurrentLinkedQueue<String> stringQueue;
private final ConcurrentLinkedQueue<InputStream> isQueue;
private final FileWriter writer;
private WriteExceptionTask(File file) throws IOException {
this.file = file;
writer = new FileWriter(this.file, true);
stringQueue = new ConcurrentLinkedQueue<String>();
isQueue = new ConcurrentLinkedQueue<InputStream>();
running = true;
}
public void addStreamToRead(InputStream is){
if(is != null){
isQueue.add(is);
}
}
#Override
public void run() {
while(running){
if(!stringQueue.isEmpty()){
//TODO check file existence
try {
writer.append(stringQueue.poll());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
running = false;
}
}
if(!isQueue.isEmpty()){
InputStream is = isQueue.poll();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder("{\"catLog\":\"");
String aux;
try {
while ((aux = reader.readLine()) != null) {
//TODO view like array or \n
builder.append(aux);
}
} catch (IOException e) {
e.printStackTrace();
}
builder.append("\"},");
stringQueue.add(builder.toString());
}
}
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
running = false;
}
}
}