[ 
https://issues.apache.org/jira/browse/WICKET-2384?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Tsutomu YANO updated WICKET-2384:
---------------------------------

    Attachment: wickettestapp.tar.gz

sample application to reproduce this problem.

> OutOfMemoryError occur for memory leak on FeedbackPanel & FeedbackMessages
> --------------------------------------------------------------------------
>
>                 Key: WICKET-2384
>                 URL: https://issues.apache.org/jira/browse/WICKET-2384
>             Project: Wicket
>          Issue Type: Bug
>          Components: wicket
>    Affects Versions: 1.3.6, 1.4-RC7
>         Environment: reproduceable on wicket-1.4-rc7(current newest) and 
> wicket-1.3.6(current newest release of 1.3 series). tested on Windows XP and 
> Mac OS X
>            Reporter: Tsutomu YANO
>            Priority: Critical
>         Attachments: wickettestapp.tar.gz
>
>
> When I uses component.info() method to display a message, my program stopped 
> by OutOfMemoryError or StackOverflowError. 
> on both of wicket 1.4-rc7 and wicket 1.3.6.
> I create a sample application to show this problem. Open attached tar.gz 
> file(including a maven project) and run. 
> check 'submit continuously' checkbox and click 'register' button. 
> The program will display current session size continuously on console. the 
> size will be increased, and finally program will be 
> stopped with OutOfMemoryError or StackOverflowError. 
> But if you changes only one line, this program will not be stopped. 
> ---original code--- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             info("message"); 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> --------------------- 
> ---changed---------- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             Session.get().info("message");  //CHANGED!!! 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> -------------------- 
>    so component's info() method is the reason of this problem. If you 
> commented out 'info()' line, this program never crashed.
>    We found out the reason of this problem in a static inner class 
> 'MessageListView' in FeedbackPanel.
>   MessageListView uses annonimous inner class of Model (named ad 
> 'replacementModel'), and it imports a FeedbackMessage object from 
> enclosing instance. FeedbackPanel holds this annonimous inner class and the 
> annonimous inner class holds a FeedbackMessage.
>   When we use component's info() method, the component is assigned into 
> FeedbackMessage object as a 'reporter' object. so, all of 
> FeedbackMessage objects have a component instance inside of himself as 
> 'reporter' (only one exception: if you use Session.get().info() 
> method instead of component's info() method, 'reporter' object become null).
>   All already-displayed FeedbackMessages will be purged at 'detach' time from 
> Session object. But FeedbackPanel holds FeedbackMessages. 
> So when page is serialized, all FeedbackMessages, all 'reporter' components 
> is serialized. This is the reason of this problem.
>   We can solve this problem if we do not hold FeedbackMessage instance in the 
> annnonimous inner class.
> change the code of FeedbackPanel as bellow (this code is based on 
> FeedbackPanel class of wicket 1.4-rc7, line 70):
> ---- original code -----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>       final FeedbackMessage message = listItem.getModelObject();
>       message.markRendered();
>       final IModel<String> replacementModel = new Model<String>()
>       {
>               private static final long serialVersionUID = 1L;
>               /**
>                * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>                * as the class of the li / span elements.
>                * 
>                * @see org.apache.wicket.model.IModel#getObject()
>                */
>               @Override
>               public String getObject()
>               {
>                       return getCSSClass(message);
>               }
>       };
>       final Component label = newMessageDisplayComponent("message", message);
>       final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>       label.add(levelModifier);
>       listItem.add(levelModifier);
>       listItem.add(label);
> }
> --------------------
> ---- fixed code ----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>       //FIXED message must not be 'final'. It must not be used in inner class.
>       //If message could be used in inner class, the instance could be hold by
>       //inner class tacitly and never cleared at detach time and will be 
> serialized.
>       FeedbackMessage message = listItem.getModelObject();
>       message.markRendered();
>       final IModel<String> replacementModel = new Model<String>()
>       {
>               private static final long serialVersionUID = 1L;
>               /**
>                * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>                * as the class of the li / span elements.
>                * 
>                * @see org.apache.wicket.model.IModel#getObject()
>                */
>               @Override
>               public String getObject()
>               {
>                       //FIXED -- retrieve a FeedbackMessage object from 
> ListView's Model.
>                       //         never hold it.
>                       @SuppressWarnings("unchecked")
>                       List<FeedbackMessage> list = (List<FeedbackMessage>) 
> MessageListView.this.getDefaultModelObject();
>                       FeedbackMessage feedbackMessage = null;
>                       int index = listItem.getIndex();
>                       if(index < list.size()) {
>                               feedbackMessage = list.get(index);
>                       }
>                       if(feedbackMessage == null) return "";
>                       return getCSSClass(feedbackMessage);
>                       //UNTIL HERE
>               }
>       };
>       final Component label = newMessageDisplayComponent("message", message);
>       final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>       label.add(levelModifier);
>       listItem.add(levelModifier);
>       listItem.add(label);
> }
> --------------------

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to