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()

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?

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.

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);

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:

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.

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.

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:

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.

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(); } }

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).