This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 44187 - OutputWriter.reset() broken on first call
Summary: OutputWriter.reset() broken on first call
Status: CLOSED FIXED
Alias: None
Product: platform
Classification: Unclassified
Component: Output Window (show other bugs)
Version: 4.x
Hardware: PC Linux
: P2 blocker (vote)
Assignee: _ tboudreau
URL:
Keywords: REGRESSION
: 45643 46046 47479 (view as bug list)
Depends on: 45126
Blocks: 45643
  Show dependency tree
 
Reported: 2004-06-02 13:33 UTC by dmladek
Modified: 2008-12-23 00:05 UTC (History)
4 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments
my XML file causing SOE (10.43 KB, text/plain)
2004-06-02 13:35 UTC, dmladek
Details
java.lang.StackOverflowError (1.25 KB, text/plain)
2004-06-29 14:12 UTC, zikmund
Details
Annotated log file (-J-Dnb.output.log.verbose=true) to show exactly what is going wrong and where (31.13 KB, text/plain)
2004-07-28 20:48 UTC, _ tboudreau
Details
This would be a better approach (1.35 KB, patch)
2004-08-05 15:39 UTC, _ tboudreau
Details | Diff
exception stacktrace (1.18 KB, text/plain)
2004-08-19 15:33 UTC, dmladek
Details

Note You need to log in before you can comment on or make changes to this bug.
Description dmladek 2004-06-02 13:33:53 UTC
Product Version       = NetBeans IDE Dev (Build
200406011800)
  Operating System      = Linux version
2.4.22-1.2115.nptl running on i386
  Java; VM; Vendor      = 1.4.2_04; Java
HotSpot(TM) Client VM 1.4.2_04-b05; Sun
Microsystems Inc.
  Java Home             =
/usr/local/java/j2sdk1.4.2_04/jre
  System Locale; Encod. = cs_CZ (nb); ISO-8859-2
  Home Dir; Current Dir = /usr/local/home/delphym;
/usr/local/forte/forte3/NBdev-last/netbeans/bin
-------------------------------------------------------------------------------

I've got a XML file which I wan't to Check and
Validate.
But Checkin' this file cause StackOVerFlowError
:-( (without any stacktrace)

I'm attaching my XML file which causing it.


BTW: reproduction is not as easy as it seems.
First Checking will probably pass, theb you have
to perform "Validate XML" and after that again
"Check XML". No the SOE occures.
Comment 1 dmladek 2004-06-02 13:35:23 UTC
Created attachment 15423 [details]
my XML file causing SOE
Comment 2 zikmund 2004-06-29 14:10:45 UTC
It's 100% reproducible on every 2nd validation of new created XML
document.
Exception attached.
Comment 3 zikmund 2004-06-29 14:12:36 UTC
Created attachment 16059 [details]
java.lang.StackOverflowError
Comment 4 Petr Pisl 2004-07-13 14:01:46 UTC
It can be connected with the issue #45643
Comment 5 Milan Kuchtiak 2004-07-13 16:57:03 UTC
The loop comes from
org.netbeans.core.output2.OutputDocument class - see the second
attachement.

This is caused by calling the reset() method on
org.openide.windows.OutputWriter class.
If the reset() action is commented out, the StackOverflowError doesn't
occure.

The method is called from "InitInputOutput(String name)" method
(org.netbeans.modues.xml.core.actions.InputOutputReporter class,
xml/core module). It seems that reset() is called correctly from there.
Comment 6 Petr Jiricka 2004-07-13 17:58:44 UTC
Changing component to core/output.
Comment 7 _ tboudreau 2004-07-20 15:47:03 UTC
Endless loop fixed.

Checking in src/org/netbeans/core/output2/OutputDocument.java;
/cvs/core/output2/src/org/netbeans/core/output2/OutputDocument.java,v  <--  
OutputDocument.java
new revision: 1.3; previous revision: 1.2
Comment 8 _ tboudreau 2004-07-20 18:53:13 UTC
*** Issue 46046 has been marked as a duplicate of this issue. ***
Comment 9 Jiri Skrivanek 2004-07-28 14:32:43 UTC
The fix solved StackOverflowError but now it behaves strange:

- call Check XML => it prints something to output window
- call Check XML again => it clear output but prints nothing
- call Check XML once more  => it prints correct output
- and so on in a loop
Comment 10 _ tboudreau 2004-07-28 20:47:03 UTC
Here is what the XML module is doing:

First run:
Call IOProvider.getIO() to get an instance of InputOutput.
Call InputOutput.getOut() to write to.  This creates an instance of 
OutputWriter (a stream to write to).

Second run:
Call InputOutput.reset().  This disposes the instance of 
OutputWriter it had (all future writes to it will go to /dev/null)
Call IOProvider.getIO() - as it should do.  This constructs a new 
InputOutput to write to.
But then the XML module keeps trying to write to the old, dead 
InputOutput, instead of the new one it went so far as to ask for.


Safest is to simply call InputOutput.getOut() everywhere - that way 
you'll always get the right instance (if reset() is not called, the 
same one will be returned).  But even if doing it this way worked in 
the old output window, it was at the very least a memory leak.  
There is no way to get a reference to the old OutWriter - it had to 
be held, and shouldn't have been.
Comment 11 _ tboudreau 2004-07-28 20:48:21 UTC
Created attachment 16534 [details]
Annotated log file (-J-Dnb.output.log.verbose=true) to show exactly what is going wrong and where
Comment 12 Petr Jiricka 2004-07-29 07:21:45 UTC
Tim, thanks for a useful and helpful evaluation. 
Comment 13 _ pkuzel 2004-07-30 12:19:59 UTC
*** Issue 45643 has been marked as a duplicate of this issue. ***
Comment 14 _ pkuzel 2004-07-30 16:31:56 UTC
Tim OutputWriter.reset() JavaDoc claims that is just erases written
data i.e. API alternative to "Clear All".

From your description it seems that there is new semantics more close
to closing stream as wanted in issue #45126. 

XML code wants to reuse single OW.
Comment 15 _ tboudreau 2004-07-31 00:24:07 UTC
You can reuse a single output tab.  You just can't use a single writer.  The thing you want 
to hold onto (though you don't need to, you can just ask using the same name) is the 
InputOutput instance, not the writer itself.

This should be a simple global search and replace, either to hold InputOutput and call 
getOut() when you need to write something (in which case you'll always get the right 
OutputWriter back), or just retain the name you want to use and always call 
IOProvider.getDefault().getIO("whatever").getOut().  Either will work fine, the latter also 
reduces the risk of memory leaks.

The core problem is that the reset() method is on the wrong interface (do you ever really 
want to reset *only* the stdOut, but not the stdErr?), but we can't really change that.  It's a 
bit of an ambiguous API.
Comment 16 Jesse Glick 2004-07-31 19:19:08 UTC
Tim since the current documentation in IOProvider, InputOutput, and
OutputWriter are clearly inadequate after the core/output2 rewrite, I
suggest you update the Javadoc of these classes to include detailed
hints (<div class="nonnormative">) on how the methods should be used
to work nicely with the current OW implementation. If possible, give
hints  that will not break usage on the old core/output, so that it
remains feasible to swap in a different terminal impl.
Comment 17 _ pkuzel 2004-08-02 18:30:29 UTC
Tim, I propably did not get it. My best approximation is:

    /** Set output writer used by this displayer.
    * Share existing, clear content on reuse. #44187
    */
    private void initInputOutput (String name) {
        xmlInputOutput = IOProvider.getDefault().getIO(name, false);
        xmlInputOutput.setFocusTaken (false);
        activeOutputWriter = xmlInputOutput.getOut();

        // clear previous output        
        try {
            activeOutputWriter.reset();
            activeOutputWriter.close();
        } catch (IOException e) {
            ErrorManager.getDefault().notify(e);
        }
        activeOutputWriter = xmlInputOutput.getOut();
    }

but it ignores first attempt to write anything. All subsequent
attempts are OK.
Comment 18 _ tboudreau 2004-08-02 20:20:38 UTC
Get rid of the call to close() first - if you're resetting it, you don't need it.  You should call 
close() when you're done writing to the stream.

The simplest solution to all of this is to simply never hold a reference to anything.  When 
you want to write, call

IOProvider.getInputOutput(name).getOut().println("whatever");

When you want to clear/reset, just call
IOProvider.getInputOutput(name).getOut().clear/reset/close/whatever

and you shouldn't have any problems.  The lookup of the output writer by name is very 
fast - there is rarely more than 1-2 instances around anyway.
Comment 19 _ tboudreau 2004-08-02 20:23:33 UTC
Just to clarify, based on issue 45126:  If you're calling reset(), don't call close() - resetting 
will automatically discard the stream, the data, everything.  The problem is not calling 
close() when something's done writing - so the tab name stays bold (and the memory 
mapped file you were writing to can't be deleted).
Comment 20 _ pkuzel 2004-08-03 10:49:05 UTC
Search and replace did not help.

The trick is that I need to call auxiliary print() before reset().
Otherwise it ignores all print()s until next reset(). Please check
reset() logic.

Workarounded in XML.

InputOutputReporter.java
new revision: 1.17
Comment 21 _ tboudreau 2004-08-04 01:02:38 UTC
As I suggested earlier, delete line 246 of InputOutputReporter (244 
can go too):

244: out().write ("Reset");
245: out().reset();  <-- This disposes the old writer - its 
resources are cleaned up, and the next call to InputOutput.getOut() 
will give you a new one to use
246: out().close();  <-- Here you are creating the new writer and 
immediately telling it it's closed and should send any future writes 
to /dev/null.  

Call close() when you are done *writing* output and know you won't 
write anymore, not when you want to start writing something.  Once 
you close it, it's closed.
Comment 22 _ pkuzel 2004-08-05 08:51:02 UTC
Workaround removed. It works as expected even without it if always
calling static IOProvider.

InputOutputReporter.java
new revision: 1.18
Comment 23 _ pkuzel 2004-08-05 09:09:11 UTC
Tim

it works but I still do not understand your explanation:

> 246: out().close();  <-- Here you are creating the new writer and 
> immediately telling it it's closed and should send any future writes 
> to /dev/null.

Fact: close() was called always. 

But only for the very first invocation after creating new InputOutput
it behaves as you describe. On subsequent invocations it feels like it
disposes the old writer - its resources are cleaned up, and the next
call to InputOutput.getOut() will give me a new one to use.

This anomaly was somehow workarounded by
out().println();out().reset();out().close() sequence. Then next call
to out() i.e. InputOutput.getOut() always return new writer instance.
Comment 24 _ pkuzel 2004-08-05 09:20:57 UTC
Finally,

there is confusing reset() logic. Why does it destroy the stream? It
should rewind it - erase previous output but keep it opened.
Convetionally close() is the operation that closes streams. reset()
rewinds() to marked state.

It's described in Javadoc note on output2 implementation. But can
implementation note prevail generic method contact - clears output pane?

Now, I hope I have said everything I have wanted :-).
Comment 25 _ tboudreau 2004-08-05 12:54:06 UTC
The reason is really thread safety:  The writer operates over a memory mapped file full of 
data.  The output window is a swing Document implmented over that memory mapped 
file.  There are a number of optimizations that make a huge performance difference, which 
can only be done because it is known that the number of lines always goes up and never 
goes down.

When the reset() is called, the data is going to be replaced BUT reset() can be called from 
any thread.  When it is called, the Document being viewed will be replaced with a new one 
- but Swing is not thread safe, and this must be done in the EQ.  So if the writer were 
"rewound", there would be a period of time when the Document was still visible (because 
the InvocationEvent to replace it hadn't run yet), but it was no longer backed by anything.  
One PaintEvent running before the InvocationEvent runs would do quite nasty things.

I'm contemplating possibly wrapping the writer in a proxy writer, so it is always usable, 
and the Document is implemented over its wrapped writer, but I'm not sure this is even a 
good idea - the only reason people are having problems is by trying to do things that are 
either way too clever or clearly wrong (calling reset(); close(); was always a bug - it just 
didn't do anything bad in the old implementation). 
Comment 26 _ pkuzel 2004-08-05 13:34:34 UTC
Bloody issue, it randomly appeared again. I have reworkarounded using
auxiliary println.
Comment 27 _ tboudreau 2004-08-05 15:39:28 UTC
Created attachment 16662 [details]
This would be a better approach
Comment 28 _ tboudreau 2004-08-05 15:41:00 UTC
The problem is calling reset() on a writer that has never been used.  I'll do something to 
make that a no-op.  But anyway, that's your problem; the attached patch will fix it in a 
cleaner way.
Comment 29 Jiri Skrivanek 2004-08-06 09:27:17 UTC
Until it is fixed properly I am reopening this issue. In the current
build the Check XML action prints nothing when it was called for the
first time, then it appears randomly.
Comment 30 _ pkuzel 2004-08-09 08:58:07 UTC
Tim, your patch does not work. It never reset()s.
Comment 31 _ tboudreau 2004-08-11 12:06:14 UTC
OutWriter will now check if it's ever been written and ignore calls 
to reset() if it is unused.

Checking in src/org/netbeans/core/output2/OutWriter.java;
/cvs/core/output2/src/org/netbeans/core/output2/OutWriter.java,v  <--
  OutWriter.java
new revision: 1.9; previous revision: 1.8
done
Comment 32 Jiri Skrivanek 2004-08-12 09:34:26 UTC
Verified in build 20040812-0503.
Comment 33 dmladek 2004-08-19 14:49:17 UTC
please see issue #47479 if it is not possible dup. In this case this
one should be reopen
Comment 34 dmladek 2004-08-19 15:02:12 UTC
IMHO, it doesn't work in Beta1 candidate nor in current DEV (4.0)
#20040818-1800

After you start ide and before you open any file in editor (but it
might be left open from your previous session) and want to 
Check/Validate any xml/dtd file ... nothing is written into OutputWindow.


You must first open any file in editor and then you've got result into
lastly checked xml file.
Comment 35 dmladek 2004-08-19 15:02:41 UTC
*** Issue 47479 has been marked as a duplicate of this issue. ***
Comment 36 dmladek 2004-08-19 15:31:57 UTC
And in the console (when using TRUNK) is printed java.lang.Exception
stacktrace which I'm attaching
Comment 37 dmladek 2004-08-19 15:33:36 UTC
Created attachment 16958 [details]
exception stacktrace
Comment 38 _ tboudreau 2004-08-24 14:36:15 UTC
Fixed in trunk.  Now uses a wrapper writer class, so you can reuse a 
writer after calling reset() on it.


Checking in demosrc/org/netbeans/core/output2/TestFrame.java;
/cvs/core/output2/demosrc/org/netbeans/core/output2/TestFrame.java,v  
<--  TestFrame.java
new revision: 1.13; previous revision: 1.12
done
Processing log script arguments...
More commits to come...
Checking in src/org/netbeans/core/output2/AbstractLines.java;
/cvs/core/output2/src/org/netbeans/core/output2/AbstractLines.java,v  
<--  AbstractLines.java
new revision: 1.2; previous revision: 1.1
done
Checking in src/org/netbeans/core/output2/Bundle.properties;
/cvs/core/output2/src/org/netbeans/core/output2/Bundle.properties,v  
<--  Bundle.properties
new revision: 1.7; previous revision: 1.6
done
Checking in src/org/netbeans/core/output2/Controller.java;
/cvs/core/output2/src/org/netbeans/core/output2/Controller.java,v  <--
  Controller.java
new revision: 1.19; previous revision: 1.18
done
Checking in src/org/netbeans/core/output2/ErrWriter.java;
/cvs/core/output2/src/org/netbeans/core/output2/ErrWriter.java,v  <--
  ErrWriter.java
new revision: 1.4; previous revision: 1.3
done
Checking in src/org/netbeans/core/output2/FileMapStorage.java;
/cvs/core/output2/src/org/netbeans/core/output2/FileMapStorage.java,v 
 <--  FileMapStorage.java
new revision: 1.7; previous revision: 1.6
done
Checking in src/org/netbeans/core/output2/HeapStorage.java;
/cvs/core/output2/src/org/netbeans/core/output2/HeapStorage.java,v  <-
-  HeapStorage.java
new revision: 1.4; previous revision: 1.3
done
Checking in src/org/netbeans/core/output2/IOEvent.java;
/cvs/core/output2/src/org/netbeans/core/output2/IOEvent.java,v  <--  
IOEvent.java
new revision: 1.4; previous revision: 1.3
done
Checking in src/org/netbeans/core/output2/NbIO.java;
/cvs/core/output2/src/org/netbeans/core/output2/NbIO.java,v  <--  
NbIO.java
new revision: 1.4; previous revision: 1.3
done
Checking in src/org/netbeans/core/output2/NbIOProvider.java;
/cvs/core/output2/src/org/netbeans/core/output2/NbIOProvider.java,v  
<--  NbIOProvider.java
new revision: 1.6; previous revision: 1.5
done
RCS 
file: /cvs/core/output2/src/org/netbeans/core/output2/NbWriter.java,v
done
Checking in src/org/netbeans/core/output2/NbWriter.java;
/cvs/core/output2/src/org/netbeans/core/output2/NbWriter.java,v  <--  
NbWriter.java
initial revision: 1.1
done
Checking in src/org/netbeans/core/output2/OutWriter.java;
/cvs/core/output2/src/org/netbeans/core/output2/OutWriter.java,v  <--
  OutWriter.java
new revision: 1.13; previous revision: 1.12
done
Checking in src/org/netbeans/core/output2/OutputDocument.java;
/cvs/core/output2/src/org/netbeans/core/output2/OutputDocument.java,v 
 <--  OutputDocument.java
new revision: 1.7; previous revision: 1.6
done
Checking in src/org/netbeans/core/output2/OutputTab.java;
/cvs/core/output2/src/org/netbeans/core/output2/OutputTab.java,v  <--
  OutputTab.java
new revision: 1.5; previous revision: 1.4
done
Processing log script arguments...
More commits to come...
Checking in src/org/netbeans/core/output2/ui/AbstractOutputPane.java;
/cvs/core/output2/src/org/netbeans/core/output2/ui/AbstractOutputPane.
java,v  <--  AbstractOutputPane.java
new revision: 1.18; previous revision: 1.17
done
Processing log script arguments...
More commits to come...
RCS 
file: /cvs/core/output2/test/unit/src/org/netbeans/core/output2/Lifecy
cleTest.java,v
done
Checking in 
test/unit/src/org/netbeans/core/output2/LifecycleTest.java;
/cvs/core/output2/test/unit/src/org/netbeans/core/output2/LifecycleTes
t.java,v  <--  LifecycleTest.java
initial revision: 1.1
done
Checking in 
test/unit/src/org/netbeans/core/output2/WrappedTextViewTest.java;
/cvs/core/output2/test/unit/src/org/netbeans/core/output2/WrappedTextV
iewTest.java,v  <--  WrappedTextViewTest.java
new revision: 1.3; previous revision: 1.2
done
Comment 39 Tomas Danek 2005-08-02 11:28:03 UTC
TM=4.0 -> closing.