I am reading an RSS newsfeed and want to check if the calling App has been cancelled/stopped (eg device rotated). Most RSS feeds have a loop in them which allows a statement in the loop to check for isCancelled(). I am using what is described as a Simplified SAX read. There is no loop. I call the parse, and have handlers for different items. I have one of them, (end Element) to check for isCancelled().
I get "unhandled exception: org.xml.sax.SAXException", on the red underlined throw statement. It will not compile.
I have tried as many combinations as I can think of where the try/catch statements go, and putting in the org.xml.sax.
I presume one option I have is to use one of teh RSS feed read options that has a loop, but if possible, I would like to use this simplified SAX read as it is supposed to be the most efficient.
public ArrayList<FeedItem> GetWithSimplifiedSax(String theUrl)
throws SAXException {
try {
url= new URL(theUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream inputStream = connection.getInputStream();
final FeedItem currentItem = new FeedItem();
RootElement root = new RootElement("rss");
final ArrayList<FeedItem> feedItems = new ArrayList<>();
android.sax.Element channel = root.getChild("channel");
android.sax.Element item = channel.getChild("item");
item.setEndElementListener(new EndElementListener(){
public void end() {
feedItems.add(currentItem.myCopy());
if(isCancelled()){
throw new SAXException("cancel");
//<<DOES NOT LIKE ABOVE LINE
// *** Gives unhandled exception:org.xml.sax.SAXException
}
}
});
item.getChild("title").setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentItem.setTitle(body);
}
});
item.getChild("link").setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentItem.setLink(body);
}
});
item.getChild("description").setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentItem.setDescription(body);
}
});
item.getChild("pubdate").setEndTextElementListener(new EndTextElementListener(){
public void end(String body) {
currentItem.setPubDate(body);
}
});
try {
Xml.parse(inputStream, Xml.Encoding.UTF_8, root.getContentHandler());
} catch(SAXException e){
Log.e("SAX", e.getMessage());
return null;
}
return feedItems;
} catch ( IOException e) {
Log.e("MYERROR", e.getMessage());
//e.printStackTrace();
return null;
} //catch (org.xml.sax.SAXException e) {
// Log.e("SAX", e.getMessage());
// //e.printStackTrace();
// return null;
//} //try catch
} //method: public ... simplified SAX
Related
I have a application JSON -> XML converter. This application will take a List of events that are converted to XML one by one. Before conversion, the header for the final XML will be created using the start method, and later converted events are added to xmlEventWriter one-by-one, and finally after all the conversion the closing tags are added to the XML using end method.
I am facing an issue during the closing of tags and running into the error:
javax.xml.stream.XMLStreamException: No open start element, when trying to write end element
As per my understanding, everything is correct but still facing the issue don't know why.
Following is the class that will create the header body and closure tags in XML:
public class EventXMLStreamCollector implements EventsCollector<OutputStream> {
private final OutputStream stream;
private final XMLEventWriter xmlEventWriter;
private final XMLEventFactory events;
public EventXMLStreamCollector(OutputStream stream) {
this.stream = stream;
try {
xmlEventWriter = XMLOutputFactory.newInstance().createXMLEventWriter(stream);
events = XMLEventFactory.newInstance();
} catch (XMLStreamException e) {
throw new EventFormatConversionException("Error occurred during the creation of XMLEventWriter : " + e);
}
}
public void collect(Object event) {
System.out.println("COLLECT START");
try {
XMLEventReader xer = new EventReaderDelegate(XMLInputFactory.newInstance().createXMLEventReader(new StringReader(event.toString()))) {
#Override
public boolean hasNext() {
if (!super.hasNext())
return false;
try {
return !super.peek().isEndDocument();
} catch (XMLStreamException ignored) {
return true;
}
}
};
if (xer.peek().isStartDocument()) {
xer.nextEvent();
xmlEventWriter.add(xer);
}
} catch (XMLStreamException e) {
throw new EventFormatConversionException("Error occurred during the addition of events to XMLEventWriter: " + e);
}
System.out.println("COLLECT END");
}
#Override
public OutputStream get() {
return stream;
}
#Override
public void start(Map<String, String> context) {
System.out.println("START START");
try {
xmlEventWriter.add(events.createStartDocument());
xmlEventWriter.add(events.createStartElement(new QName("doc:Document"), null, null));
xmlEventWriter.add(events.createNamespace("doc", "urn:one"));
xmlEventWriter.add(events.createNamespace("xsi", "http://www.w3.org/2001/XMLSchem-instance"));
xmlEventWriter.add(events.createNamespace("cbvmda", "urn:two"));
for (Map.Entry<String, String> stringStringEntry : context.entrySet()) {
xmlEventWriter.add(events.createAttribute(stringStringEntry.getKey(), stringStringEntry.getValue()));
}
xmlEventWriter.add(events.createStartElement(new QName("Body"), null, null));
xmlEventWriter.add(events.createStartElement(new QName("EventList"), null, null));
} catch (XMLStreamException e) {
throw new EventFormatConversionException("Error occurred during the creation of final XML file header information " + e);
}
System.out.println("START END");
}
#Override
public void end() {
System.out.println("END START");
try {
System.out.println(xmlEventWriter.toString());
xmlEventWriter.add(events.createEndElement(new QName("EventList"), null));
xmlEventWriter.add(events.createEndElement(new QName("Body"), null));
xmlEventWriter.add(events.createEndElement(new QName("doc:Document"), null));
xmlEventWriter.add(events.createEndDocument());
xmlEventWriter.close();
} catch (XMLStreamException e) {
throw new EventFormatConversionException("Error occurred during the closing xmlEventWriter:" + e);
}
System.out.println("END END");
}
#Override
public void collectSingleEvent(Object event) {
try {
XMLEventReader xer = XMLInputFactory.newInstance().createXMLEventReader(new StringReader(event.toString()));
if (xer.peek().isStartDocument()) {
xer.nextEvent();
}
xmlEventWriter.add(xer);
} catch (XMLStreamException e) {
System.out.println("ADDED : " + e.getMessage());
throw new EventFormatConversionException("Error occurred during the addition of events to XMLEventWriter: " + e);
}
}
}
I am getting the error for this line:
xmlEventWriter.add(events.createEndElement(new QName("Body"), null));
I am not sure why I am getting this error. I am opening the Body tag and then trying to close it. I am sure that the flow is correct, I am calling start, collect, and then finally end. Following the output I am getting:
START START
START END
COLLECT START
COLLECT END
END START
I am not getting END END because of the error I am getting for the closing of Body tag. Can someone please help me understand this issue and provide some workaround and help.
I have this code which I want to test and get the max pit coverage but I am not able to kill the mutant for the negated condition if (close). I am also using mockito to throw some exception.
public static void copyBytes(InputStream in, OutputStream out, int buffSize, boolean close) throws IOException {
try {
copyBytes(in, out, buffSize);
if (close) {
out.close();
out = null;
in.close();
in = null;
}
} finally {
if (close) {
closeStream(out);
closeStream(in);
}
}
}
This is my case tests:
#Test
public void mockOutputCopyBytes1False(){
try{
OutputStream outputStream = Mockito.mock(OutputStream.class);
doThrow(new IOException()).when(outputStream).close();
copyBytes(createInputStream(), outputStream, 50, false);
outputStream.write(10);
}catch (Exception e){
e.printStackTrace();
Assert.assertEquals(IOException.class, e.getClass());
}
}
#Test
public void mockOutputCopyBytes1True(){
try{
OutputStream outputStream = Mockito.mock(OutputStream.class);
doThrow(new IOException()).when(outputStream).close();
copyBytes(createInputStream(), outputStream, 50, true);
outputStream.write(10);
}catch (Exception e){
e.printStackTrace();
Assert.assertEquals(IOException.class, e.getClass());
}
}
The finally clause is executed whether the code works or throws an exception, there is no need to code for both cases:
public static void copyBytes(InputStream in, OutputStream out, int buffSize, boolean close) throws IOException {
try {
copyBytes(in, out, buffSize);
// TODO - remove the following
//if (close) {
// out.close();
// out = null;
// in.close();
// in = null;
//}
} finally {
if (close) {
closeStream(out);
closeStream(in);
}
}
}
I trying to convert my Asynch task to JavaRx 2. I use google sheets api to download data from spreadsheets. (here is a link how this happens)
Here is a part of my code:
OnCreate:
/**
* JavaRx
*/
//Observable
Observable<String> observable
= Observable.create(
new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
//Use onNext to emit each item in the stream//
e.onNext("https://docs.google.com/spreadsheets/d/1W5S5W2QH6WHjUcL1VMwqIqOdFYVleTopJNryQJGw568/gviz/tq?tqx=out:QUERY&tq=select+B,X,Y,Z");
//Once the Observable has emitted all items in the sequence, call onComplete//
e.onComplete();
}
}
).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
//Create our subscription
Observer<String> observer = new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
Log.e(TAG, "onSubscribe " + Thread.currentThread().getName());
}
#Override
public void onNext(String value) {
try {
String data = getLeagueData(value);
mLeagues.add(autoProcessJsonLeague("Argentina Primera Division", returnJSON(data)));
} catch (IOException e) {
e.printStackTrace();
}
Log.e(TAG, "onNext: " + value + Thread.currentThread().getName());
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError: ");
}
#Override
public void onComplete() {
Log.e(TAG, "onComplete: All Done! " + Thread.currentThread().getName());
}
};
observable.subscribe(observer);
Other Methods:
private String getLeagueData(String urlString) throws IOException {
//Download JSON file
InputStream is = null;
try {
URL url = new URL(urlString);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setInstanceFollowRedirects(true); //you still need to handle redirect manually.
HttpsURLConnection.setFollowRedirects(true);
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setInstanceFollowRedirects(true);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect(); //ERROR HAPPENS HERE!
int responseCode = conn.getResponseCode();
is = conn.getInputStream();
String contentAsString = convertStreamToString(is);
//Log.d("contentAsString", contentAsString);
return contentAsString;
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
is.close();
}
}
return null;
}
private String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
private League autoProcessJsonLeague(String leagueName, JSONObject object) {
//Get the data from the JSON string
ArrayList<Team> teams = new ArrayList<>();
try {
JSONArray rows = object.getJSONArray("rows");
for (int r = 0; r < rows.length(); ++r) {
JSONObject row = rows.getJSONObject(r);
JSONArray columns = row.getJSONArray("c");
String name = columns.getJSONObject(0).getString("v");
int points = columns.getJSONObject(1).getInt("v");
double hGoalAv = columns.getJSONObject(2).getDouble("v");
double aGoalAv = columns.getJSONObject(3).getDouble("v");
hGoalAv = Utilities.round(hGoalAv, 2);
aGoalAv = Utilities.round(aGoalAv, 2);
teams.add(new Team(name, points, hGoalAv, aGoalAv));
//Log.d("Team", name + " " + hGoalAv + " " + aGoalAv);
}
} catch (JSONException e) {
e.printStackTrace();
e.printStackTrace();
}
return new League(leagueName, teams);
}
So I create an observable, I subscribe on IO thread and observeOn the main thread. With onNext I send the url link to the observer and then I try to connect to the server to download the json string file.
Error happens on method getLeagueData() on the line conn.connect();
It says java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
FULL STACK TRACE ERROR:
08-16 08:53:09.934 29841-29841/com.aresproductions.bettingtools E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.aresproductions.bettingtools, PID: 29841
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6195)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
Caused by: android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:86)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:74)
at java.net.InetAddress.getAllByName(InetAddress.java:752)
at com.android.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29)
at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:187)
at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:156)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:98)
at com.android.okhttp.internal.http.HttpEngine.createNextConnection(HttpEngine.java:346)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:329)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:247)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:126)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java)
at com.aresproductions.bettingtools.MainActivity.getLeagueData(MainActivity.java:307)
at com.aresproductions.bettingtools.MainActivity.access$000(MainActivity.java:80)
at com.aresproductions.bettingtools.MainActivity$2.onNext(MainActivity.java:180)
at com.aresproductions.bettingtools.MainActivity$2.onNext(MainActivity.java:171)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:198)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:250)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6195)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:874)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:764)
08-16 08:53:09.936 29841-29841/com.aresproductions.bettingtools E/MQSEventManagerDelegate: failed to get MQSService.
Thanks in advance!
The problem is that you are doing the network call on the main thread. Though you have subscribed on Schedulers.io(), the onNext() method where you are doing the network call will be called on main thread since you are observing on main thread observeOn(AndroidSchedulers.mainThread()).
The solution will be to call the getLeagueData(String urlString) inside subscribe() method of observable and call e.onNext(result) with the result of the network call.
I assume you get a network on main thread exception because the network call is at the wrong place. You should have moved it into the create thus it gets executed on the IO scheduler instead as part of observing the trivial string:
Observable<String> observable = Observable.create(
new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
String value = "https://docs.google.com/spreadsheets/d/1W5S5W2QH6WHjUcL1VM" +
"wqIqOdFYVleTopJNryQJGw568/gviz/tq?tqx=out:QUERY&tq=select+B,X,Y,Z";
String data = getLeagueData(value);
//Use onNext to emit the item in the stream//
e.onNext(data);
/* Once the Observable has emitted all items
in the sequence, call onComplete */
e.onComplete();
}
}
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
//Create our subscription
Observer<String> observer = new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
Log.e(TAG, "onSubscribe " + Thread.currentThread().getName());
}
#Override
public void onNext(String data) {
try {
mLeagues.add(autoProcessJsonLeague(
"Argentina Primera Division", returnJSON(data)));
} catch (IOException e) {
e.printStackTrace();
}
Log.e(TAG, "onNext: " + value + Thread.currentThread().getName());
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError: ");
}
#Override
public void onComplete() {
Log.e(TAG, "onComplete: All Done! " + Thread.currentThread().getName());
}
};
observable.subscribe(observer);
You may also want to move
autoProcessJsonLeague(
"Argentina Primera Division", returnJSON(data))
into the ObservableOnSubscribe in case the processing is expensive.
In my code,first I access an address and I got the text file. In that, there are many picture links, such as http://dnight-math.stor.sinaapp.com/%E5%9C%B0%E7%90%861_img004.jpg. I use regular expression to find all the links to make a arraylist. Then I use downloadService to download all the pictures. When I first press a button to download ,it can run successfully. But it doesn't work if the button is pressed again and throws error. I think this bug is about thread but I don't know how to solve it.
HttpUtil.sendHttpRequest(address,
new HttpCallbackListener() {
#Override
public void onFinish(String response) {
try {
ArrayList<String> urlList = new ArrayList<>();
Pattern p = Pattern.compile("http:.*?.com/(.*?.(jpg|png))");
Matcher m = p.matcher(response);
StringBuffer buffer = new StringBuffer();
while (m.find()) {
m.appendReplacement(buffer, "<T>" + + m.group(1) + "</T>");
urlList.add(m.group());
}
m.appendTail(buffer);
response = buffer.toString();
Message m2 = Message.obtain();
m2.obj = response;
m2.what = 1;
mHandler.sendMessage(m2);
new DownloadService("/data/data/com.baodian/files",
urlList,
new DownloadStateListener() {
#Override
public void onFinish() {
}
#Override
public void onFailed() {
}
}, context).startDownload();
;
// JSONObject singleChoice=all.getjson
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onError(Exception e) {
}
});
public class HttpUtil {
public static void sendHttpRequest(final String address,
final HttpCallbackListener listener) {
new Thread(new Runnable() {
#Override
public void run() {
HttpURLConnection connection=null;
try {
URL url=new URL(address);
connection=(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
InputStream in=connection.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(in,"gbk"));
StringBuilder response=new StringBuilder();
String line=null;
while ((line=reader.readLine())!=null) {
response.append(line);
}
if (listener!=null) {
listener.onFinish(response.toString());
}
} catch (Exception e) {
if (listener != null) {
listener.onError(e);
}
}
}
}).start();
}
}
If you look at SimY4's answer here,
he says that the error you're getting "means the thread pool is busy and queue is full as well".
What you currently do is call onFailed when you encounter the error. What you can do is implement
a supplementary enqueing scheme. You can cache the newer urls until the thread queue has space, create and enqueue
the new threads at that point.
The following thread might prove useful : Java executors: how to be notified, without blocking, when a task completes?
I added in the MainActivity a button click event:
public void addListenerOnButton()
{
btnClick = (Button) findViewById(R.id.checkipbutton);
btnClick.setOnClickListener(new OnClickListener()
{
byte[] response = null;
#Override
public void onClick(View arg0)
{
text = (TextView) findViewById(R.id.textView2);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
for (int i = 0; i < ipaddresses.length; i++)
{
try
{
response = Get(ipaddresses[i]);
break;
} catch (Exception e)
{
text.setText("Connection Failed");
}
}
if (response!=null)
{
String a = null;
try
{
a = new String(response,"UTF-8");
text.setText(a);
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
Logger.getLogger("MainActivity(inside thread)").info(a);
}
}
});
t.start();
}
});
}
I wanted to create a break when it's entering the try block after doing the response = Get(ipaddresses[i]); in order to stop the for loop.
The problem is that after it's done the response = Get(ipaddresses[i]); when it's supposed to be doing the break, my program crashes.
On the android device I get the message:
unfortunately myapp has stopped
And when I click ok on the message the program just closes.
I can't figure out why the break makes the program crash.
This is the Get method:
private byte[] Get(String urlIn)
{
URL url = null;
String urlStr = urlIn;
if (urlIn!=null)
urlStr=urlIn;
try
{
url = new URL(urlStr);
} catch (MalformedURLException e)
{
e.printStackTrace();
return null;
}
HttpURLConnection urlConnection = null;
try
{
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
byte[] buf=new byte[10*1024];
int szRead = in.read(buf);
byte[] bufOut;
if (szRead==10*1024)
{
throw new AndroidRuntimeException("the returned data is bigger than 10*1024.. we don't handle it..");
}
else
{
bufOut = Arrays.copyOf(buf, szRead);
}
return bufOut;
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
finally
{
if (urlConnection!=null)
urlConnection.disconnect();
}
}
The reason for the crash is most likely apparent from the stacktrace that you haven't shown us.
But the logic of that loop is pretty dubious ... to me.
Without the break, the loop iterates over all of the IP addresses, and tries Get on each one. At the end, response will be the last value returned by a Get call, which may or may not be null.
With the break, the loop terminates after the first IP address for which Get doesn't throw an exception ... irrespective of what the Get call returns. (That could be null.)
These could be the cause of your crash, but it could be something else. Either way, the logic is suspicious. (And calling a method Get is bad style!)
UPDATE
Given that the Get method catches exceptions and returns null on failure, the recommended structure for the code that calls it is:
for (int i = 0; i < ipaddresses.length; i++) {
response = Get(ipaddresses[i]);
if (response != null) {
break;
}
}
if (response == null) {
// notify connection failed
} else {
// process response
}
There is not need for a "belt and braces" try {...} catch in the calling code ... if you have already dealt with the expected exceptions in Get. And (IMO) you should (almost) never catch Exception, because that is liable to conceal bugs.