modifying EventList from ListEventListener disallowed?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

modifying EventList from ListEventListener disallowed?

hbrands
Administrator
Hey guys,

just to confirm: is it true, that modifying the source list from an event listener is disallowed?
Consider the following example:
BasicEventList->SortedList->ReadonlyList

The listener on the ReadonlyList listens for an insert event and in turn deletes the first item from
the BasicEventList. While the list is of course modified, no delete event is fired:

    public void testModifyFromListener() throws Exception{
        final BasicEventList<String> unsortedList = new BasicEventList<String>();
        unsortedList.addAll(GlazedListsTests.stringToList("ABCDEFG"));
        unsortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": UNSORTEDLIST=" + listChanges);
            }
        });
        final SortedList<String> sortedList = SortedList.create(unsortedList);
        sortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": SORTEDLIST=" + listChanges);
            }
        });
       
        final EventList<String> readonlyList = GlazedLists.readOnlyList(sortedList);
        readonlyList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": READONLYLIST=" + listChanges);
                while(listChanges.next()) {                       
                    // get the current change info
                    int index = listChanges.getIndex();
                    int changeType = listChanges.getType();

                    // on insert, do a delete
                    if(changeType == ListEvent.INSERT) {
                        listChanges.getSourceList().getReadWriteLock().writeLock().lock();
                        if (listChanges.getSourceList().get(index).equals("H")) {
                            System.err.println("MODIFYING unsortedList");
                            unsortedList.remove(0); //WILL NOT BE BROADCASTED!
                        }
                        listChanges.getSourceList().getReadWriteLock().writeLock().unlock();
                    }
                }
            }
        });
        unsortedList.getReadWriteLock().writeLock().lock();
        unsortedList.add("H");
        unsortedList.getReadWriteLock().writeLock().unlock();
        Thread.sleep(5000L);
        System.err.println("UNSORTEDLIST= " + unsortedList);
    }

Is this behavoiur expected?
I guess so, but would like to confirm it. Perhaps we should document this better?

Please see http://java.net/jira/browse/GLAZEDLISTS-531 for another example.

Thanks,
Holger



Reply | Threaded
Open this post in threaded view
|

Re: modifying EventList from ListEventListener disallowed?

James Lemieux
I'm surprised by that result. I'd have hoped for either an exception when you begin the event or (more likely) for that event to be sent after the first is completely delivered.

It is a common usecase to alter list data in response to other ListEvents, sometimes even from another area of your list pipeline (another branch of the tree). But, to do this correctly, the user needs to become much more aware of what is happening re: firing the *current* ListEvent.

You typically want the entire pipeline to be fully up-to-date before you're willing to construct and fire a new ListEvent in response to the first one. I used to wonder if providing a SECOND callback method (in addition to listChanged(...)) was the best way to handle that.

James

On Sun, Nov 27, 2011 at 7:54 AM, Holger Brands <[hidden email]> wrote:
Hey guys,

just to confirm: is it true, that modifying the source list from an event listener is disallowed?
Consider the following example:
BasicEventList->SortedList->ReadonlyList

The listener on the ReadonlyList listens for an insert event and in turn deletes the first item from
the BasicEventList. While the list is of course modified, no delete event is fired:

    public void testModifyFromListener() throws Exception{
        final BasicEventList<String> unsortedList = new BasicEventList<String>();
        unsortedList.addAll(GlazedListsTests.stringToList("ABCDEFG"));
        unsortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": UNSORTEDLIST=" + listChanges);
            }
        });
        final SortedList<String> sortedList = SortedList.create(unsortedList);
        sortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": SORTEDLIST=" + listChanges);
            }
        });
       
        final EventList<String> readonlyList = GlazedLists.readOnlyList(sortedList);
        readonlyList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": READONLYLIST=" + listChanges);
                while(listChanges.next()) {                       
                    // get the current change info
                    int index = listChanges.getIndex();
                    int changeType = listChanges.getType();

                    // on insert, do a delete
                    if(changeType == ListEvent.INSERT) {
                        listChanges.getSourceList().getReadWriteLock().writeLock().lock();
                        if (listChanges.getSourceList().get(index).equals("H")) {
                            System.err.println("MODIFYING unsortedList");
                            unsortedList.remove(0); //WILL NOT BE BROADCASTED!
                        }
                        listChanges.getSourceList().getReadWriteLock().writeLock().unlock();
                    }
                }
            }
        });
        unsortedList.getReadWriteLock().writeLock().lock();
        unsortedList.add("H");
        unsortedList.getReadWriteLock().writeLock().unlock();
        Thread.sleep(5000L);
        System.err.println("UNSORTEDLIST= " + unsortedList);
    }

Is this behavoiur expected?
I guess so, but would like to confirm it. Perhaps we should document this better?

Please see http://java.net/jira/browse/GLAZEDLISTS-531 for another example.

Thanks,
Holger




Reply | Threaded
Open this post in threaded view
|

Re: modifying EventList from ListEventListener disallowed?

hbrands
Administrator
Hi James,

2011/11/28 James Lemieux <[hidden email]>
I'm surprised by that result. I'd have hoped for either an exception when you begin the event or (more likely) for that event to be sent after the first is completely delivered.


Dito, exactly what I thought ;-)
I think I'll have to debug this a little more to better understand what's going on.
But I found the following in the javadoc for ListEventListener#listChanged:
"...It is an error to write to the source list while processing an event."

So it seems to be forbidden, but I had hoped that Jesse could clarify the intended behaviour.
 
It is a common usecase to alter list data in response to other ListEvents, sometimes even from another area of your list pipeline (another branch of the tree). But, to do this correctly, the user needs to become much more aware of what is happening re: firing the *current* ListEvent.

You typically want the entire pipeline to be fully up-to-date before you're willing to construct and fire a new ListEvent in response to the first one. I used to wonder if providing a SECOND callback method (in addition to listChanged(...)) was the best way to handle that.

Perhaps that would be an option in the future...

Holger
 
James


On Sun, Nov 27, 2011 at 7:54 AM, Holger Brands <[hidden email]> wrote:
Hey guys,

just to confirm: is it true, that modifying the source list from an event listener is disallowed?
Consider the following example:
BasicEventList->SortedList->ReadonlyList

The listener on the ReadonlyList listens for an insert event and in turn deletes the first item from
the BasicEventList. While the list is of course modified, no delete event is fired:

    public void testModifyFromListener() throws Exception{
        final BasicEventList<String> unsortedList = new BasicEventList<String>();
        unsortedList.addAll(GlazedListsTests.stringToList("ABCDEFG"));
        unsortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": UNSORTEDLIST=" + listChanges);
            }
        });
        final SortedList<String> sortedList = SortedList.create(unsortedList);
        sortedList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": SORTEDLIST=" + listChanges);
            }
        });
       
        final EventList<String> readonlyList = GlazedLists.readOnlyList(sortedList);
        readonlyList.addListEventListener(new ListEventListener<String>() {
            public void listChanged(ListEvent<String> listChanges) {
                System.err.println(Thread.currentThread() + ": READONLYLIST=" + listChanges);
                while(listChanges.next()) {                       
                    // get the current change info
                    int index = listChanges.getIndex();
                    int changeType = listChanges.getType();

                    // on insert, do a delete
                    if(changeType == ListEvent.INSERT) {
                        listChanges.getSourceList().getReadWriteLock().writeLock().lock();
                        if (listChanges.getSourceList().get(index).equals("H")) {
                            System.err.println("MODIFYING unsortedList");
                            unsortedList.remove(0); //WILL NOT BE BROADCASTED!
                        }
                        listChanges.getSourceList().getReadWriteLock().writeLock().unlock();
                    }
                }
            }
        });
        unsortedList.getReadWriteLock().writeLock().lock();
        unsortedList.add("H");
        unsortedList.getReadWriteLock().writeLock().unlock();
        Thread.sleep(5000L);
        System.err.println("UNSORTEDLIST= " + unsortedList);
    }

Is this behavoiur expected?
I guess so, but would like to confirm it. Perhaps we should document this better?

Please see http://java.net/jira/browse/GLAZEDLISTS-531 for another example.

Thanks,
Holger