Project

General

Profile

Bug #2700

Bug #2677: fix drawing and functional differences between P2J GUI and 4GL GUI

gui_btn_test4.p abend with "Invalid frame ID 4"

Added by Greg Shah over 8 years ago. Updated over 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Start date:
Due date:
% Done:

100%

billable:
No
vendor_id:
GCD
case_num:

Related issues

Related to User Interface - Bug #2735: fix WindowGuiImpl.truncateWindowHeightQuirk() New

History

#1 Updated by Greg Shah over 8 years ago

When running the button/gui_btn_test4.p in the Swing GUI client (using trunk revision 10933), the program abends just after the default window flashes up but before displaying the actual program windows. This is the exception in the stderr log:

java.lang.RuntimeException: Invalid frame ID 4
        at com.goldencode.p2j.ui.chui.ThinClient.getFrame(ThinClient.java:12142)
        at com.goldencode.p2j.ui.chui.ThinClient.getChanges(ThinClient.java:11745)
        at com.goldencode.p2j.net.Protocol.attachChanges(Protocol.java:274)
        at com.goldencode.p2j.net.Queue.enqueueOutbound(Queue.java:810)
        at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:765)
        at com.goldencode.p2j.net.Conversation.block(Conversation.java:319)
        at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257)
        at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128)
        at com.goldencode.p2j.net.Queue.transact(Queue.java:585)
        at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:223)
        at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:163)
        at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1424)
        at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:97)
        at com.sun.proxy.$Proxy4.standardEntry(Unknown Source)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:277)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100)
        at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201)
        at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398)
        at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:95)
        at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267)

#2 Updated by Greg Shah over 8 years ago

I wonder if this is related to running multiple testcases in the same session from ask-gui.p. I have seen another reliable recreate:

1. Run ask-gui.p.
2. Type ./rectangle/rect_test2.p and ENTER.
3. Type SPACE, SPACE, SPACE, Y, ENTER.
4. Change ./rectangle/rect_test2.p to ./rectangle/rect_test6.p and press ENTER.
5. Press SPACE again (probably because of some implicit hiding) and then the program abends.

Here is the abend:

java.lang.RuntimeException: Invalid frame ID 9
        at com.goldencode.p2j.ui.chui.ThinClient.getFrame(ThinClient.java:12161)
        at com.goldencode.p2j.ui.chui.ThinClient.getChanges(ThinClient.java:11764)
        at com.goldencode.p2j.net.Protocol.attachChanges(Protocol.java:274)
        at com.goldencode.p2j.net.Queue.enqueueOutbound(Queue.java:810)
        at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:765)
        at com.goldencode.p2j.net.Conversation.block(Conversation.java:319)
        at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257)
        at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128)
        at com.goldencode.p2j.net.Queue.transact(Queue.java:585)
        at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:223)
        at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:163)
        at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1424)
        at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:97)
        at com.sun.proxy.$Proxy4.standardEntry(Unknown Source)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:277)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100)
        at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201)
        at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398)
        at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:95)
        at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267)

If you run ./rectangle/rect_test6.p without first having run ./rectangle/rect_test2.p (in the same session), it will work without an abend.

#3 Updated by Constantin Asofiei over 8 years ago

The root cause for gui_btn_test4.p is this:

Caused by: java.lang.NullPointerException
    at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.truncateWindowHeightQuirk(WindowGuiImpl.java:1507)
    at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.updateSizeWorker(WindowGuiImpl.java:1455)
    at com.goldencode.p2j.ui.client.widget.AbstractWidget.afterConfigUpdateBase(AbstractWidget.java:1870)
    at com.goldencode.p2j.ui.client.Window.afterConfigUpdate(Window.java:2263)
    at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.afterConfigUpdate(WindowGuiImpl.java:1260)
    at com.goldencode.p2j.ui.client.Window.afterConfigUpdate(Window.java:1)
    at com.goldencode.p2j.ui.ConfigSyncManager.markScopeEnd(ConfigSyncManager.java:247)
    at com.goldencode.p2j.ui.ConfigManager.syncConfigChanges(ConfigManager.java:497)
    at com.goldencode.p2j.ui.ConfigManager.replaceConfig(ConfigManager.java:365)
    at com.goldencode.p2j.ui.client.Window.pushConfig(Window.java:807)
    at com.goldencode.p2j.ui.chui.ThinClient$20.run(ThinClient.java:7317)
    at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13510)
    at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13459)
    at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13391)
    at com.goldencode.p2j.ui.chui.ThinClient.pushWindow(ThinClient.java:7312)
    ... 21 more

The stacktrace was obtained by using a breakpoint in Dispatcher.processInbound:712 and evaluating t.printStackTrace() expression. Otherwise, the exception gets "eaten" and never logged. We should fixed this too.

#4 Updated by Greg Shah over 8 years ago

The stacktrace was obtained by using a breakpoint in Dispatcher.processInbound:712 and evaluating t.printStackTrace() expression. Otherwise, the exception gets "eaten" and never logged. We should fixed this too.

The code deliberately avoids logging at that point because so many normal use cases involve exception processing (e.g. all the ConditionException cases) that should silently return the exception to the other side.

What do you suggest here?

#5 Updated by Greg Shah over 8 years ago

Updated stack trace using some overaggressive logging:

Sep 22, 2015 11:52:07 AM Dispatcher.processInbound() 
SEVERE: {main} Exception caught.
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76)
        at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694)
        at com.goldencode.p2j.net.Conversation.block(Conversation.java:319)
        at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257)
        at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128)
        at com.goldencode.p2j.net.Queue.transact(Queue.java:585)
        at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:223)
        at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:163)
        at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1425)
        at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:97)
        at com.sun.proxy.$Proxy4.standardEntry(Unknown Source)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:277)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100)
        at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201)
        at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398)
        at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:95)
        at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267)
Caused by: java.lang.NullPointerException
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.truncateWindowHeightQuirk(WindowGuiImpl.java:1532)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.updateSizeWorker(WindowGuiImpl.java:1480)
        at com.goldencode.p2j.ui.client.widget.AbstractWidget.afterConfigUpdateBase(AbstractWidget.java:1827)
        at com.goldencode.p2j.ui.client.Window.afterConfigUpdate(Window.java:2251)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.afterConfigUpdate(WindowGuiImpl.java:1276)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.afterConfigUpdate(WindowGuiImpl.java:99)
        at com.goldencode.p2j.ui.ConfigSyncManager.markScopeEnd(ConfigSyncManager.java:247)
        at com.goldencode.p2j.ui.ConfigManager.syncConfigChanges(ConfigManager.java:497)
        at com.goldencode.p2j.ui.ConfigManager.replaceConfig(ConfigManager.java:365)
        at com.goldencode.p2j.ui.client.Window.pushConfig(Window.java:808)
        at com.goldencode.p2j.ui.chui.ThinClient$20.run(ThinClient.java:7318)
        at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13523)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13472)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13404)
        at com.goldencode.p2j.ui.chui.ThinClient.pushWindow(ThinClient.java:7313)
        ... 21 more

#6 Updated by Greg Shah over 8 years ago

The WindowGuiImpl.truncateWindowHeightQuirk() code that fails is this:

      int truncWorkAreaHeight = area.height() - 2*GuiConstants.BORDER_SIZE - 
                                getTitleBar().physicalDimension().height;   <-- this line

I guess that getTitleBar() is returning null, perhaps because it is called before WindowGuiImpl.init()? We are processing in the 2nd ConfigManager.replaceConfig() path from Window.pushConfig(). This means the window is not the default window AND it already exists. But why would it already be existing AND yet the init() has not been called?

Hynek: any ideas?

#7 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

The WindowGuiImpl.truncateWindowHeightQuirk() code that fails is this:

[...]

I guess that getTitleBar() is returning null, perhaps because it is called before WindowGuiImpl.init()? We are processing in the 2nd ConfigManager.replaceConfig() path from Window.pushConfig(). This means the window is not the default window AND it already exists. But why would it already be existing AND yet the init() has not been called?

Hynek: any ideas?

WindowGuiImpl.init() is called from doLayout() and draw(). This is relatively late. Maybe the window which fails has not gotten that far in its life cycle?

#8 Updated by Greg Shah over 8 years ago

WindowGuiImpl.init() is called from doLayout() and draw(). This is relatively late. Maybe the window which fails has not gotten that far in its life cycle?

Yes, I would say that is correct. The failure occurs here:

      externalProcedure(new Block()
      {
         handle hwin = new handle();

         public void init()
         {
            TransactionManager.registerUndo(hwin);
         }

         public void body()
         {
            frFrame.openScope();
            DynamicWidgetFactory.createWindow(hwin);
            hwin.unwrapSizeable().setWidthChars(new integer(60));
            hwin.unwrapSizeable().setHeightChars(new integer(15));  <--- FAIL
            hwin.unwrapWidget().setRow(new integer(10));
            hwin.unwrapWidget().setColumn(new integer(50));
            hwin.unwrapWindow().loadIcon("gclogo.ico");
            hwin.unwrapWidget().setVisible(new logical(true));
            message("One fish,", hwin);
            message("Two fish,", hwin);
            message("Red fish,");
            message("Blue fish!");
            pause();
...

Here is the original code:

def var hwin as handle.
create window hwin
   assign width-chars  = 60
          height-chars = 15    <--- FAIL
          row          = 10
          column       = 50.

hwin:load-icon("gclogo.ico").

hwin:visible = true.

message "One fish," in window hwin.
message "Two fish," in window hwin.
message "Red fish,".
message "Blue fish!".
pause.
...

#9 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

WindowGuiImpl.init() is called from doLayout() and draw(). This is relatively late. Maybe the window which fails has not gotten that far in its life cycle?

Yes, I would say that is correct. The failure occurs here:

[...]

Here is the original code:

[...]

Greg, this makes sense. When config is updated truncateWindowHeightQuirk() is executed. But only when height is assigned the execution gets passed:

      if (!config.heightAssigned)
      {
         return;
      }

The init method should be executed sooner, maybe already when initialize() is called?

#10 Updated by Greg Shah over 8 years ago

It seems reasonable. The only question is whether there are things that cannot be calculated or accessed at that point.

My simple test did not work well. I moved init() to inside of initialize() like this:

   public void initialize(WidgetId id, WindowConfig cfg)
   {
      // when window is creating at runtime it should register itself with renderer prior to
      // the base init routines
      OutputManager.instance().realizeWindow(id.asInt());

      // call for base initialization
      super.initialize(id, cfg);

      init();

      updateFullSizeAttributes();
   }

With this change, now even the hello.p fails immediately:

java.lang.NullPointerException
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.afterConfigUpdate(WindowGuiImpl.java:1300)
        at com.goldencode.p2j.ui.client.gui.WindowGuiImpl.afterConfigUpdate(WindowGuiImpl.java:99)
        at com.goldencode.p2j.ui.ConfigSyncManager.markScopeEnd(ConfigSyncManager.java:247)
        at com.goldencode.p2j.ui.ConfigManager.syncConfigChanges(ConfigManager.java:497)
        at com.goldencode.p2j.ui.ConfigManager.replaceConfig(ConfigManager.java:365)
        at com.goldencode.p2j.ui.client.Window.pushConfig(Window.java:763)
        at com.goldencode.p2j.ui.chui.ThinClient$20.run(ThinClient.java:7318)
        at com.goldencode.p2j.ui.chui.ThinClient.eventBracket(ThinClient.java:13523)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13472)
        at com.goldencode.p2j.ui.chui.ThinClient.eventDrawingBracket(ThinClient.java:13404)
        at com.goldencode.p2j.ui.chui.ThinClient.pushWindow(ThinClient.java:7313)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76)
        at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694)
        at com.goldencode.p2j.net.Conversation.block(Conversation.java:319)
        at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:257)
        at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1128)
        at com.goldencode.p2j.net.Queue.transact(Queue.java:585)
        at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:223)
        at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:163)
        at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1425)
        at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:97)
        at com.sun.proxy.$Proxy2.getSessionTooltips(Unknown Source)
        at com.goldencode.p2j.ui.chui.ThinClient.initializePost(ThinClient.java:2817)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:216)
        at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:100)
        at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:201)
        at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:398)
        at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:95)
        at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:267)

Did you intend for the init() to be placed somewhere else?

#11 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

It seems reasonable. The only question is whether there are things that cannot be calculated or accessed at that point.

My simple test did not work well. I moved init() to inside of initialize() like this:

[...]

With this change, now even the hello.p fails immediately:

[...]

Did you intend for the init() to be placed somewhere else?

I meant the location you moved init() to. There is another problem though. WindowGuiImpl.initialize() is not called at all, at least for the default window. I don't see any reason why it shouldn't be called for all the window instances.

#12 Updated by Greg Shah over 8 years ago

There is another problem though. WindowGuiImpl.initialize() is not called at all, at least for the default window. I don't see any reason why it shouldn't be called for all the window instances.

I think this is because WidgetRegistry.reconstructWidget() is not called before the failure occurs. I set a breakpoint there and the failure occurs (and the client abends), before it gets invoked.

Ideas?

#13 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

There is another problem though. WindowGuiImpl.initialize() is not called at all, at least for the default window. I don't see any reason why it shouldn't be called for all the window instances.

I think this is because WidgetRegistry.reconstructWidget() is not called before the failure occurs. I set a breakpoint there and the failure occurs (and the client abends), before it gets invoked.

Ideas?

WindowGuiImpl.initialize() is not called at all. Even when the program doesn't abend. Let me see how to resolve it.

#14 Updated by Hynek Cihlar over 8 years ago

A workaround fix for the abend from note 5 checked in to 1811q revision 11035.

#15 Updated by Greg Shah over 8 years ago

Please list the things to be done to get a long-term fix for this.

#16 Updated by Hynek Cihlar over 8 years ago

Greg Shah wrote:

Please list the things to be done to get a long-term fix for this.

The method WindowGuiImpl.truncateWindowHeightQuirk was changed to a no-op until the following items are addressed.
  • AbstractGuiDriver.getDisplayWorkArea() doesn't return correct display size, this seems to be related the fact that the method is called during window init phase.
  • The method must be called only when height is assigned on the server, currently the method is called every time the window config is pushed to the client. There used to be a logic on the client side that checked whether height really changed and only then truncateWindowHeightQuirk() was called, but that code is gone. We need something more explicit and reliable. An option could be to move the quirk to the server, the down side is that we need to know the actual window layout and display work area size which is kept on the client.

#17 Updated by Greg Shah over 8 years ago

  • Status changed from New to Closed

#18 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

The stacktrace was obtained by using a breakpoint in Dispatcher.processInbound:712 and evaluating t.printStackTrace() expression. Otherwise, the exception gets "eaten" and never logged. We should fixed this too.

The code deliberately avoids logging at that point because so many normal use cases involve exception processing (e.g. all the ConditionException cases) that should silently return the exception to the other side.

What do you suggest here?

I would do this: log everything which doesn't have a ConditionException in the cause chain.

#19 Updated by Greg Shah over 8 years ago

What about SilentUnwindException or InterruptedException?

#20 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

What about SilentUnwindException or InterruptedException?

Yes, these too should not be logged, along with UnstoppableExitException, which is thrown for batch mode.

RetryUnwindException and StackUnwindException as I see are not raised by the client-side, and they should not reach the Dispatcher.processInbound.

#21 Updated by Greg Shah over 8 years ago

What about in virtual sessions? I wonder if there are cases where StackUnwindException (and sub-classes) can be sent from one server to another.

#22 Updated by Constantin Asofiei over 8 years ago

Greg Shah wrote:

What about in virtual sessions?

If you mention virtual sessions, when remote persistence is used, PersistenceException may be thrown by the remote side (e.g. IdentityManagerMultiplexer.nextPrimaryKey).

I wonder if there are cases where StackUnwindException (and sub-classes) can be sent from one server to another.

I can't see a use-case where the 4GL-style procedure code would be split across servers... all legacy code should be enclosed and executed within a BlockManager API, which treats these exceptions.

What about this: if the exception class is part of com.goldencode.p2j package, then assume is legit and don't log it; otherwise log it. This should cover all custom exceptions thrown by P2J.

#23 Updated by Greg Shah over 8 years ago

Task branch 1811q revision 11038 adds logging for unexpected throwables in Dispatcher.processInbound(). At this time we only exclude ConditionExceptions, InterruptedException and UnstoppableExitException. SilentUnwindException can occur during abnormal end processing so it would hide some abends.

#24 Updated by Greg Shah over 8 years ago

  • % Done changed from 0 to 100

#25 Updated by Greg Shah over 8 years ago

  • Assignee set to Greg Shah

#26 Updated by Greg Shah over 7 years ago

  • Target version changed from Milestone 12 to GUI Support for a Complex ADM2 App

Also available in: Atom PDF