Attached is the patch. Changed DataView added OIRModel() helper and a test DataViewOIRModelTest.

With this implementation there is no exception thrown if two objects share an equal IModel. For those ori is silently turned off. Please look at the comments in the code.

I also replace getDataProvider() to return an empty model instead of null.

I think in the current code (from the cvs and my patch) the dataitems are not always rendered in the order as they come from the iterator. I guess for existing DataItems setting the index has no effect. Is this right? If so I think this should be fixed.

Christian


On Fri, 12 Aug 2005 16:30:37 -0700, Igor Vaynberg <[EMAIL PROTECTED]> wrote:

Why don't you implement it and email us the patch. That way we can all take
a look at it and see if it works.

-Igor


-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of
Christian Essl
Sent: Friday, August 12, 2005 1:48 PM
To: [email protected]
Subject: Re: [Wicket-user] [Wicket] DataView and optimized
item removal

On Fri, 12 Aug 2005 12:57:37 -0700, Igor Vaynberg
<[EMAIL PROTECTED]>
wrote:

> Explain the benefits of your approach as opposed to the current
> implementation - I cant think of any off the top of my head.
Because you can use any object not just a string. This means
you can provide optimized item removal (lets call it oir)
also to things like wicket.examples.guestbook.Comment objects
( return new EqualsModel(ob,ob) ). I do not know an easy way
to create a string id for this not db held objects. Or in
case a particular object is contained double in the iterator
you can turn of oir for just this particular item new Model(ob).
new Model(ob) gives you always an indeed unique id.

>
> As far as collections go, performance wise I think you
would be better
> off transforming it to a list first or to an array and writing an
> ArrayAdapter.
> Assuming your collection interface isnt backed by a dynamic source
> this should work ok.
>

Performance wise you are right. The difference is with new
List(colleciton) the Model reflects a snapshot not the actual maybe
changing collection.

Christian


        

        
                
___________________________________________________________
Gesendet von Yahoo! Mail - Jetzt mit 1GB Speicher kostenlos -
Hier anmelden: http://mail.yahoo.de



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development
Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams *
Testing & QA
Security * Process Improvement & Measurement *
http://www.sqe.com/bsce5sf
_______________________________________________
Wicket-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/wicket-user







-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Wicket-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/wicket-user



--
Christian Essl 
Index: DataView.java
===================================================================
RCS file: 
/cvsroot/wicket-stuff/wicket-contrib-dataview/src/wicket/contrib/dataview/DataView.java,v
retrieving revision 1.9
diff -u -r1.9 DataView.java
--- DataView.java       11 Aug 2005 20:54:48 -0000      1.9
+++ DataView.java       13 Aug 2005 10:23:49 -0000
@@ -17,11 +17,16 @@
  */
 package wicket.contrib.dataview;
 
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import wicket.Component;
+import wicket.WicketRuntimeException;
 import wicket.model.IModel;
 import wicket.model.Model;
 
@@ -90,8 +95,12 @@
         */
        protected final IDataProvider getDataProvider()
        {
-               return (IDataProvider)getModelObject();
+               IDataProvider ret = (IDataProvider)getModelObject();
+               if(ret == null)
+                       ret = EmptyDataProvider.SINGLETON;
+               return ret;
        }
+       
 
        /**
         * Returns the total number of items available through the DataProvider
@@ -199,32 +208,110 @@
                return this;
        }
 
-       /**
-        * @see wicket.MarkupContainer#internalOnBeginRequest()
-        */
        protected void internalOnBeginRequest()
        {
-               final IDataProvider dataProvider = getDataProvider();
-               
-               // Get number of items to be displayed
                final int size = getViewSize();
-
-               if (size > 0)
-               {
-
-                       IUniqueIdProvider idProvider=null;
+               if(size > 0){
+                       final IDataProvider dataProvider = getDataProvider();
                        if (dataProvider instanceof IUniqueIdProvider) {
-                               idProvider=(IUniqueIdProvider)dataProvider;
-                       } else {
-                               removeAll();
-                               idProvider=new IUniqueIdProvider() {
-                                       public String uniqueId(Object object)
-                                       {
-                                               return 
String.valueOf(DataView.this.generateChildId());
+                               IUniqueIdProvider udp = 
(IUniqueIdProvider)dataProvider;
+                               internalOnBeginRequestUniqueId(dataProvider, 
udp,size);
+                       }else{
+                               internalOnBeginRequestModel(dataProvider,size);
+                       }
+               }else{
+                       removeAll();
+               }
+       }
+    
+       private static final Object EXISTING_BEFORE_MARKER = new Object();
+       private void internalOnBeginRequestModel(final IDataProvider 
dataProvider, final int size)
+       {
+                       Iterator it = null;
+
+                       
+                       final Map existingModels = new HashMap(size());
+                       List removeItems = null;
+                       it = iterator();
+                       while (it.hasNext())
+                       {
+                               final DataItem child = (DataItem)it.next();
+                               final IModel oldModel = child.getModel();
+                               //?: There are different possibilities what to 
do when IDataProvider.model() returns equal
+                               //Models 
+                               //1.) throw an Excpetion immidiatley: do the 
check when the model is gotten from the dataProvider
+                               //    this is the same as with 
IUniqueIdProviders
+                               //2.) throw an Exception in the second turn: 
this would be at this place and would be 
+                               //    I guess more efficient
+                               //3.) silently turn off optimized item removal: 
for all DataItems sharing the same model
+                               //4.) silently keep oir for (abitraraly) one 
DataItem and turn off for others
+                               //I for now choose 3 I guess that comes closer 
to what you would expect.
+                               
+                               final Object edi = existingModels.get(oldModel);
+                               if(edi == null){
+                                       existingModels.put(oldModel, child);
+                               }else{
+                                       it.remove();
+                                       if(edi != EXISTING_BEFORE_MARKER){
+                                               if(removeItems == null)
+                                                       removeItems = new 
LinkedList();
+                                               DataItem di = (DataItem) edi;
+                                               removeItems.add(di); //remember 
for later removal
+                                               existingModels.put(oldModel, 
EXISTING_BEFORE_MARKER);
                                        }
-                               };
+                               }
                        }
                        
+                       //remove the items which have identical models
+                       if(removeItems != null){
+                               for (Iterator iter = removeItems.iterator(); 
iter.hasNext(); ) {
+                                       DataItem di = (DataItem) iter.next();
+                                       remove(di.getId());
+                               }
+                       }
+                       
+
+                       it = dataProvider.iterator(firstIndex, size);
+
+                       // render all items not already present
+                       int index = 0;
+                       while (it.hasNext()&&index<size)
+                       {
+                               final Object object = it.next();
+                               final String id = super.generateChildId();
+                               final IModel model = dataProvider.model(object);
+
+                               final Object ob = existingModels.get(model);
+                               if(ob == null || ob == EXISTING_BEFORE_MARKER){
+                                       DataItem newItem = newItem(id, index, 
model);
+                                       add(newItem);
+                                       populateItem(newItem);
+                               }else{
+                                       DataItem oldItem = (DataItem) ob;
+                                       oldItem.setIndex(index);
+                                       existingModels.remove(model);
+                               }
+                               index++;
+                       }
+
+                       // remove dataitems no longer present in the view
+                       it = existingModels.values().iterator();
+                       while (it.hasNext())
+                       {
+                               Object ob = it.next();
+                               if(ob != EXISTING_BEFORE_MARKER){
+                                       DataItem di = (DataItem)ob;
+                                       remove(di.getId());
+                               }
+                       }
+       }
+
+       /**
+        * @see wicket.MarkupContainer#internalOnBeginRequest()
+        */
+       private void internalOnBeginRequestUniqueId(final IDataProvider 
dataProvider,final IUniqueIdProvider idProvider,final int size)
+       {
+               
                        Iterator it = null;
 
                        Set existingIds = new HashSet(size());
@@ -266,11 +353,6 @@
                        {
                                remove((String)it.next());
                        }
-               }
-               else
-               {
-                       removeAll();
-               }
        }
 
        /**
@@ -320,4 +402,46 @@
         *            The item to populate
         */
        protected abstract void populateItem(final DataItem item);
+       
+       /**
+        * used internally for when there is no IDataProvider set as model.
+        * @author Igor Vaynberg ( ivaynberg )
+        *
+        */
+       private static final class EmptyDataProvider implements IDataProvider{
+
+               final static EmptyDataProvider SINGLETON = new 
EmptyDataProvider();
+               public Iterator iterator(int first, int count)
+               {
+                       return new Iterator(){
+
+                               public boolean hasNext()
+                               {
+                                       return false;
+                               }
+
+                               public Object next()
+                               {
+                                       throw new IndexOutOfBoundsException();
+                               }
+
+                               public void remove()
+                               {
+                                       throw new 
UnsupportedOperationException();
+                               }
+                               
+                       };
+               }
+
+               public int size()
+               {
+                       return 0;
+               }
+
+               public IModel model(Object object)
+               {
+                       throw new WicketRuntimeException("object is not 
supplied by this IDataProvider");
+               }
+       }
+       
 }
Index: DataViewOIRModelTest.java
===================================================================
RCS file: DataViewOIRModelTest.java
diff -N DataViewOIRModelTest.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ DataViewOIRModelTest.java   1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,316 @@
+package wicket.contrib.dataview;
+
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import wicket.MarkupContainer;
+import wicket.model.IModel;
+import wicket.model.Model;
+
+import junit.framework.TestCase;
+
+public class DataViewOIRModelTest extends TestCase
+{
+       
+       private List _data;
+       private static int DATASIZE = 5;
+       
+       
+       protected void setUp() throws Exception
+       {
+               super.setUp();
+               _data = new ArrayList();
+               for(int i=0;i< DATASIZE;i++){
+                       _data.add(new DataBean((long)i,"Some text "+i));
+               }
+                       
+       }
+       
+       public void testOIRModel(){
+               OIRModel model = new OIRModel("some","some");
+               OIRModel model2 = new OIRModel("other","some");
+               OIRModel model3 = new OIRModel("some", new Long(3));
+               OIRModel model4 = new OIRModel("other", new Long(3));
+               OIRModel model5 = new OIRModel("some",null);
+               OIRModel model6 = new OIRModel("other",null);
+               
+               assertEquals(model,model2);
+               assertEquals(model, model);
+               assertEquals(model3,model4);
+               assertEquals(model5, model5);
+               
+               assertFalse(model5.equals(model6));
+               assertFalse(model.equals(model6));
+               assertFalse(model.equals(model3));
+               assertFalse(model3.equals(model6));
+               assertFalse(model3.equals(model));
+               
+       }
+
+       public void testNoOIR(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new Model((Serializable)object);
+                       }
+               });
+
+               assertEquals(0,dv.size());
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.size());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE,oldDataItems.size());
+               
+               //make sure all dataItems are new 
+               //(i can use collections for identity check as long as DataItem 
does not implement equals itself)
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.getItemCount());
+               Collection col = new ContainerCollection(dv);
+               assertEquals(DATASIZE, col.size());
+               oldDataItems.retainAll(col);
+               assertEquals(0,oldDataItems.size());
+       }
+       
+       public void testAllOIR(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new OIRModel((Serializable)object,new 
Long(((DataBean)object)._id));
+                       }});
+               
+               assertEquals(0,dv.size());
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.size());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE, oldDataItems.size());
+               
+               //now all DataItems must be retained
+               dv.doBeginRequest();
+               Collection col = new ContainerCollection(dv);
+               assertEquals(DATASIZE,col.size());
+               oldDataItems.retainAll(col);
+               assertEquals(DATASIZE,oldDataItems.size());
+               
+       }
+       
+       public void testRemove(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new OIRModel((Serializable)object,new 
Long(((DataBean)object)._id));
+                       }});
+               
+               assertEquals(0,dv.size());
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.size());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE, oldDataItems.size());
+
+               //add one and remove one
+               _data.remove(2);
+               dv.doBeginRequest();
+               assertEquals(DATASIZE-1,dv.size());
+
+               //now one item must be more not identity in the oldDataItems
+               Collection col = new ContainerCollection(dv);
+               assertEquals(DATASIZE-1,col.size());
+               oldDataItems.removeAll(col);
+               assertEquals(1,oldDataItems.size());
+               DataBean dI = 
(DataBean)((DataItem)oldDataItems.get(0)).getModelObject();
+               assertEquals(2,dI._id);
+       }
+       
+       public void testAdd(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new OIRModel((Serializable)object,new 
Long(((DataBean)object)._id));
+                       }});
+               
+               assertEquals(0,dv.size());
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.size());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE, oldDataItems.size());
+
+               //add one and remove one
+               _data.add(new DataBean(DATASIZE+1,""));
+               dv.doBeginRequest();
+               assertEquals(DATASIZE+1,dv.size());
+
+               //now one item must be more not identity in the oldDataItems
+               List col = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE+1,col.size());
+               col.removeAll(oldDataItems);
+               assertEquals(1,col.size());
+               DataBean dI = (DataBean)((DataItem)col.get(0)).getModelObject();
+               assertEquals(DATASIZE+1,dI._id);
+               
+       }
+       
+       public void testRemoveAdd(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new OIRModel((Serializable)object,new 
Long(((DataBean)object)._id));
+                       }});
+
+               assertEquals(0,dv.size());
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.getItemCount());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE, oldDataItems.size());
+
+               //add one and remove one
+               _data.remove(2);
+               _data.add(new DataBean(DATASIZE+1,""));
+               dv.doBeginRequest();
+               assertEquals(DATASIZE,dv.size());
+               
+               //now DATASIZE -2 dataItems must be equal
+               Collection col = new ContainerCollection(dv);
+               assertEquals(DATASIZE,col.size());
+               col.removeAll(oldDataItems);
+               assertEquals(1,col.size());
+       }
+       
+       public void testDoubleIModel(){
+               TDataView dv = new TDataView("dv",new TDataProvider(){
+                       public IModel model(Object object)
+                       {
+                               return new OIRModel((Serializable)object,new 
Long(((DataBean)object)._id));
+                       }});
+
+               assertEquals(0,dv.size());
+               
+               //add some the bean 0 again
+               _data.add(_data.get(0));
+               _data.add(_data.get(0));
+               
+               //build
+               dv.doBeginRequest();
+               assertEquals(DATASIZE+2,dv.getItemCount());
+               
+               List oldDataItems = new ArrayList(new ContainerCollection(dv));
+               assertEquals(DATASIZE+2, oldDataItems.size());
+
+               //when rerendering all dataitems for bean0 must be recreated. 
This is index 0, DATASIZE-1 and DATASIZE
+               dv.doBeginRequest();
+               List col = new ArrayList(new ContainerCollection(dv));
+               
+               assertEquals(DATASIZE+2,col.size());
+//             assertNotSame(col.get(0), oldDataItems.get(0));
+//             assertNotSame(col.get(DATASIZE -1), 
oldDataItems.get(DATASIZE-1));
+//             assertNotSame(col.get(DATASIZE), oldDataItems.get(DATASIZE));
+               
+               col.removeAll(oldDataItems);
+               assertEquals(3,col.size());
+               
assertSame(_data.get(0),((DataItem)col.get(0)).getModelObject());
+               
assertSame(_data.get(0),((DataItem)col.get(1)).getModelObject());
+               
assertSame(_data.get(0),((DataItem)col.get(2)).getModelObject());
+               
+       }
+       
+       
+       
+       private static class TDataView extends DataView{
+
+               public TDataView(String id, IDataProvider dataProvider)
+               {
+                       super(id, dataProvider);
+               }
+               
+               public void doBeginRequest()
+               {
+                       super.internalOnBeginRequest();
+                       //make sure the cached item count is cleared
+                       super.internalOnEndRequest();
+               }
+               
+               protected void internalOnBeginRequest()
+               {
+                       throw new UnsupportedOperationException();
+               }
+               
+               protected DataItem newItem(String id, int index, IModel model)
+               {
+                       return new TDataItem(id, index, model);
+               }
+
+               protected void populateItem(DataItem item)
+               {
+                       assertTrue(item.getModelObject() instanceof DataBean);
+               }
+               
+               //need this to always make sure to have always an identity 
check in the collections
+               private static class TDataItem extends DataItem{
+
+                       public TDataItem(String id, int index, IModel model)
+                       {
+                               super(id, index, model);
+                       }
+                       
+                       public int hashCode()
+                       {
+                               return System.identityHashCode(this);
+                       }
+                       
+                       public boolean equals(Object obj)
+                       {
+                               return this == obj;
+                       }
+                       
+               }
+               
+       }
+       
+       private static class DataBean implements Serializable{
+               final public String _text;
+               final public long _id;
+               DataBean(long id, String text){
+                       _text = text;
+                       _id = id;
+               }
+       }
+       
+       abstract private class TDataProvider implements IDataProvider{
+
+               public Iterator iterator(int first, int count)
+               {
+                       return _data.listIterator(first);
+               }
+
+               public int size()
+               {
+                       return _data.size();
+               }
+       }
+       
+       private static class ContainerCollection extends AbstractCollection{
+
+               private final MarkupContainer _container;
+               
+               public ContainerCollection(MarkupContainer cont){
+                       _container = cont;
+               }
+               public Iterator iterator()
+               {
+                       return _container.iterator();
+               }
+
+               public int size()
+               {
+                       return _container.size();
+               }
+               
+       }
+}
Index: OIRModel.java
===================================================================
RCS file: OIRModel.java
diff -N OIRModel.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ OIRModel.java       1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,36 @@
+package wicket.contrib.dataview;
+
+import java.io.Serializable;
+
+import wicket.model.Model;
+
+public class OIRModel extends Model
+{
+
+       private Serializable _differentiator;
+       
+       public OIRModel(Serializable object, Serializable differentiator)
+       {
+               super(object);
+               _differentiator = differentiator;
+       }
+       
+       public boolean equals(Object obj)
+       {
+               if(_differentiator == null)
+                       return super.equals(obj);
+               if (obj instanceof OIRModel) {
+                       OIRModel mod = (OIRModel)obj;
+                       return _differentiator.equals(mod._differentiator);
+               }
+               return false;
+       }
+       
+       public int hashCode()
+       {
+               if(_differentiator == null)
+                       return super.hashCode();
+               return _differentiator.hashCode();
+       }
+
+}

Reply via email to