TextEditorPane going clean when write fails.

General Discussion on RSyntaxTextArea.

Moderator: robert

TextEditorPane going clean when write fails.

Postby omadawn » Sat Aug 18, 2012 4:59 am

I'm trying to use TextEditorPane's clean/dirty functionality in my application.

In order to do this I've had to write my own outputStream so that I can use TextEditorPane.save(). The 'file' I am editing is being accessed via a proprietary API not a local file or even something well understood like FTP.

The problem I am encountering is that when I call save() and the save fails the TextEditorPane is still marking itself clean. What do I have to do so that it understands that the save failed? I have caused my output stream's flush() method to throw an IOException and TextEditorPane still marks itself as clean after the save()
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby robert » Sat Aug 18, 2012 3:01 pm

This shouldn't be possible. TextEditorPane.save() is what calls setDirty(false) when saving, but if saveImpl(FileLocation), which is what calls into your FileLocation (I assume you've created a custom subclass of this for your case?) throws an IOException, the dirty flag should not get set. Can you step through the save process with a debugger to see why this is happening?
User avatar
robert
 
Posts: 794
Joined: Sat May 10, 2008 5:16 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Sun Aug 19, 2012 8:19 pm

I've stepped through it with the debugger but I only see my own code not the RSTA so I can't confirm that RSTA is catching the exception.

Does saveImpl(FileLocation) Call anything on FileLocation or is it just getting the output stream and calling the write(int) and flush() methods?

I'm asking because I wonder if there's something in FileLocation I need to add. I have flush() thowing the IOException right now.


I have written my own FileLocation for this as well as my own outputStream to handle the getting and saving of the file since it is across a custom API not local or even some understood file transfer mechanism like FTP. (It's a SOAP method to be specific.)


Actually if the source for this is open I suppose I could download the source for RSTA and attach it to my project so I can step through RSTA and see what it is getting back from me.
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Sun Aug 19, 2012 8:30 pm

One thing I can see is that TextEditorPane.save() isn't throwing an IOException. Would it throw one if it caught one from downstream? IE from my outputstream?
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Sun Aug 19, 2012 8:58 pm

Is it possible that TextEditorPane is missing the error because I'm buffering?

In order to save the iRule I need to get the whole rule as text and call an iControl method which takes the iRule name and a String which is the rule Definition (the actual iRule code) as arguments

So I can't thrown an exception from write(int) since that only gets a single byte at a time. I take the input in write(int) and stuff it into a ByteArrayOutputStream. Then when flush() is called I call a write(String) method with the ByteArrayOutputStream's .toString() method.


Here are the methods in question.

public void write(int output) {
baos.write(output);
}

public void flush() throws IOException {
write(baos.toString());
}

public void write(String ruleDefinition) throws IOException{
LocalLBRuleRuleDefinition[] saveRules = new LocalLBRuleRuleDefinition[1]; // Create a list of iRules in order to write them back. We only have one so we only need a tiny list
saveRules[0] = new LocalLBRuleRuleDefinition();
saveRules[0].setRule_definition(ruleDefinition);
saveRules[0].setRule_name(iRuleName);

try {
if (local) {
//Rule doesn't exist on the server so create it instead of modifying it.
ic.getLocalLBRule().create(saveRules);
} else {
ic.getLocalLBRule().modify_rule(saveRules);
}
} catch (RemoteException e1) {
f5ExceptionHandler exceptionHandler = new f5ExceptionHandler(e1, owner, log);
exceptionHandler.processException();
throw new IOException();
} catch (Exception e1) {
f5ExceptionHandler exceptionHandler = new f5ExceptionHandler(e1, owner, log);
exceptionHandler.processException();
throw new IOException();
}
}
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby robert » Tue Aug 21, 2012 4:28 am

Is your flush() method getting called when you're saving? Perhaps it isn't and that is the problem. I believe PrintWriter should call flush() implicitly when you close it, but if you have checked out the RSTA source you can try this simple fix to see if it corrects your problem. Around line 547 of TextEditorPane.java:

java code:

private void saveImpl(FileLocation loc) throws IOException {
OutputStream out = loc.getOutputStream();
PrintWriter w = new PrintWriter(
new BufferedWriter(new UnicodeWriter(out, getEncoding())));
try {
write(w);
w.flush(); // <-- This line is added, and is the only change
} finally {
w.close();
}
}


If that fixes things I'll commit it to SVN for everyone to enjoy. :)
User avatar
robert
 
Posts: 794
Joined: Sat May 10, 2008 5:16 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Wed Aug 22, 2012 2:24 am

Interesting, flush has to be called since that's the only part of the code that actually saves my rules up to the server. However if it wasn't there flush probably being called when you call close(). In which case I wonder if the exception isn't being bubbled up through the close() method. I'll give the change a try and let you know. I suppose it's probably better to have RSTA call flush anyway just as a safety in case someone ends up using an output stream which doesn't call flush on it's own.
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Thu Aug 23, 2012 4:04 am

Totally crazy


So I just spent a couple hours banging my head against this to no avail before I finally located the culprit. I even modified the TextEditorPane's source to try and see if we were getting the IOException and tried creating the IOException three different ways no joy. I even tried catching a generic Exception with no joy.

private void saveImpl(FileLocation loc) throws IOException {
OutputStream out = loc.getOutputStream();
PrintWriter w = new PrintWriter(
new BufferedWriter(new UnicodeWriter(out, getEncoding())));
try {
write(w);
w.flush(); // <-- This line is added, and is the only change
} catch (IOException E) {
throw new IOException("Got an IOException from Aaron's code");
} catch (Exception e) {
throw new IOException("Got a generic exception from Aaron's code");
} finally {
w.close();
}
}

Then I was looking at the classes involved and I realized that neither PrintWriter nor BufferendWriter throw an IOException. I figured since I'm buffering mine and because PrinterWriter says "With automatic line flushing" but the current code has a call to flush() I might be able to get by without them so I tried going straight to the UnicodeWriter like so:

private void saveImpl(FileLocation loc) throws IOException {
OutputStream out = loc.getOutputStream();
UnicodeWriter w = new UnicodeWriter(out, getEncoding());
try {
write(w);
w.flush(); // <-- This line is added, and is the only change
} catch (IOException E) {
throw new IOException("Got an IOException from Aaron's code"); //GUESS WHAT GETS CALLED NOW?
} catch (Exception e) {
throw new IOException("Got a generic exception from Aaron's code");
} finally {
w.close();
}
}

Guess who's code no longer has this issue?

So it looks like your saveImpl() will never actually throw an IOException. I'm not sure if there is some other buffered writer which would bubble up the IOException instead of discarding it silently. I'm not sure what other sort of issues going straight to UniCodeWriter is going to cause.

I think the PrinterWriter was only buying you not having to call w.flush() explicitely. Before I removed the printwriter and bufferedwriter I was seeing my flush() method being called twice. Now It's only being called once.
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby omadawn » Thu Aug 23, 2012 4:07 am

So actually I cleaned it back up so that I'm not Catching IOException and re-throwing a new IOException. Left the commented out code in there for reference. This still works for both saving actual files and for not marking a failed save clean.
private void saveImpl(FileLocation loc) throws IOException {
OutputStream out = loc.getOutputStream();
// PrintWriter w = new PrintWriter(
// new BufferedWriter(
UnicodeWriter w = new UnicodeWriter(out, getEncoding());
// ));
try {
write(w);
w.flush();
} finally {
w.close();
}
}
omadawn
 
Posts: 38
Joined: Sat Jul 21, 2012 7:39 pm

Re: TextEditorPane going clean when write fails.

Postby robert » Tue Aug 28, 2012 12:06 am

It was definitely the PrintWriter causing the IOExceptions not to be percolated up. Since it was unnecessary, I removed it. However, I still believe that BufferedWriter should be closing the underlying (Unicode)Writer, which in turn closes the underlying stream. Java OutputStreams by contract should ensure they flush all output before closing themselves. For this reason I didn't keep the "w.flush()" line in there, as the OutputStream should be doing that by itself.

A BufferedWriter is needed to efficiently write very large files (limit the number of writes to the native OS resource).
User avatar
robert
 
Posts: 794
Joined: Sat May 10, 2008 5:16 pm


Return to Open Discussion

Who is online

Users browsing this forum: No registered users and 4 guests

cron