Re: Clone problem? Difference in behavior between 1.2 and 1.3

2007-07-11 Thread Johan Compagner

this is not really solveable by wicket itself.
We don't know where such a reference is comming from, so this should be
documented i guess
that if you use session data from the session object itself. You should
always use an extra
indiretion to get it
new Model()
{
 getObject() {Session.get().getList()}
}

johan


On 7/10/07, Martijn Dashorst [EMAIL PROTECTED] wrote:


Working on the Book I found a difference between 1.2 and 1.3:

In the following setup if you click on the 'link' a couple of times,
you see that the list in the session grows, and that it is reflected
in each page render.

Now, press the back button and continue clicking on the link. You will
see that the page remains static from that moment on. This was not a
problem in 1.2 because the HttpSessionStore is the only way of storing
the pages for back button behavior. However, in 1.3 the 2nd level
cache is the new way of storing, and this is the consequence of that
store: you get different objects between versions.

Is there anything we can do to prevent this from happening?

public class MySession extends WebSession {
public final ListString list = new ArrayListString();
}

public class FooPage extends WebPage {
public FooPage() {
add(new ListView(foo, MySession.get().list){
protected void populateItem(ListItem item) {
item.add(new Label(text, item.getModelObject()));
}
});
add(new Link(link) {
protected void onClick() {
MySession.get().list.add(foo  + System.currentTimeMillis
());
}
});
}
}

html
body
ul
li wicket:id=foospan wicket:id=text/span/li
/ul
a href=# wicket:id=linkClick me/a
/body
/html


--
Wicket joins the Apache Software Foundation as Apache Wicket
Apache Wicket 1.3.0-beta2 is released
Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3.0-beta2/



Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Al Maw

Martijn Dashorst wrote:

Matej had the brilliant idea of auto discovery of the type parameter
for FormComponents when they use a PropertyModel or
CompoundPropertyModel. In order to remove confusion for noobs, and to
point out that there is a Better Way (tm) I propose the following
options:

For those wondering if it is still possible to set the target type:
yes you can, just use the setType() method on the form component.

I know it is a tad late in the game, but I think the clean up is
something worthwile.

[ ] remove the affected FormComponent constructors with the type parameter
[ ] deprecate the affected FormComponent constructors with the type 
parameter

[ ] leave them


Ugh. We still seem to be changing lots of fundamental stuff, don't we. :-)

I vote:
[x] deprecate them for beta3

We could possibly remove them for rc1, but that makes migration from 
1.2.x harder, doesn't it?


Al
--
Alastair Maw
Wicket-biased blog at http://herebebeasties.com


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Johan Compagner


Ugh. We still seem to be changing lots of fundamental stuff, don't we. :-)

I vote:
[x] deprecate them for beta3

We could possibly remove them for rc1, but that makes migration from
1.2.x harder, doesn't it?




i personally don't care that much about breaking stuff for 1.3.
We really need to streamline the api i think for 1.3 so that we don't have
to break a lot in the further anymore
lets make 1.3 a very solid base..


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Al Maw

Johan Compagner wrote:

this constructor can be deleted yes:

public TextField(final String id, final Class type)
   {
   super(id);
   setType(type);
   }


but i don't know about this one:

   public TextField(final String id, IModel model, Class type)
   {
   super(id, model);
   setType(type);
   }

because if you don't use the propertymodel here then that type is pretty
needed


But you can just call setType() yourself, which is the whole point of 
this thread, I thought? (Note that we can possibly improve this further 
with generic models in the future, as they are effectively like an 
IObjectClassAwareModel.)



And bigger problem here, if you override
public IConverter getConverter(Class type)
and you don't set the type then that converter isn't used.


This sucks. It's totally counter-intuitive.

In my opinion, if you override getConverter() then it should always be 
used, even if that means we have to call it with a null type parameter. 
(Normally when you're overriding it for a particular component you don't 
care about the type parameter anyway).


I did a live demo at the last London Wicket event where I temporarily 
overlooked this and couldn't make it work, which was silly of me. Just 
goes to show it's not obvious, though. ;-)


Regards,

Al

--
Alastair Maw
Wicket-biased blog at http://herebebeasties.com


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Al Maw

Al Maw wrote:
In my opinion, if you override getConverter() then it should always be 
used, even if that means we have to call it with a null type parameter. 
(Normally when you're overriding it for a particular component you don't 
care about the type parameter anyway).


Looking at this further, it seems logical to me that we should remove 
the convertValue(String[] value) method from FormComponent and push the 
logic in there into a proper converter, which gets registered for null 
types.


Thoughts?

Regards,

Al

--
Alastair Maw
Wicket-biased blog at http://herebebeasties.com


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Johan Compagner

so you always want to call getConverter()
and if typename is not set you get a null param?
and then all the components that now implemements convertValue(String[]
values)
should override getConverted(Class)  and test for null and if it is null
then return a converter which does the same as convertValue does now.

we could do that yes. It cleans up the api and makes it more obvious that
getConverter()
is always called.

johan


On 7/11/07, Al Maw [EMAIL PROTECTED] wrote:


Al Maw wrote:
 In my opinion, if you override getConverter() then it should always be
 used, even if that means we have to call it with a null type parameter.
 (Normally when you're overriding it for a particular component you don't
 care about the type parameter anyway).

Looking at this further, it seems logical to me that we should remove
the convertValue(String[] value) method from FormComponent and push the
logic in there into a proper converter, which gets registered for null
types.

Thoughts?

Regards,

Al

--
Alastair Maw
Wicket-biased blog at http://herebebeasties.com



wicketstuff-push: centralizing requests

2007-07-11 Thread Xavier Hanin

Hi,

I'm currently using wicketstuff-push to push events to a page and it works
pretty well, but not well enough. Before trying to move to a comet based
implementation, I would like to improve the timer based implementation. In
the current implementation you got as many AjaxTimer as you install the push
on components on the same page. So if you have three components requiring
push, you will have three requests each x seconds, to poll for push events
from the three components. This would be much more efficient if I had only
one request polling for all push events sent by all components on the
page...

Hence my first thought was to add the timer behavior to the page instead of
the component, and verify that the same kind of behavior is not already
installed before installing a new one. The problem is that when I install
the behavior the component doesn't know its page. So I have to do something
at this time, and then later when I know the page make sure that only one
behavior is actually rendered.

I see two solutions to this problem:
- Add one timer behavior to each component (as today), and then when
rendering the component use the wasRendered/markRendered methods of
IHeaderResponse to render only one of them (using the isEnabled method to
disable it if another similar one has already been rendered). But then I
will have to update all the non rendered behaviors so that push events sent
to them are actually sent to the only behavior which is rendered.
- Modify the API of the push service and ask to enable push on a page before
actually using push on components on the page. This would actually install a
unique timer behavior on the page. Then when installing push on a component
I could simply add something which could be located by the unique timer on
the page to collect all push events (maybe a disabled behavior)

Now that I expose the two options I think I prefer the first one. But I
would like to gather feedback from experienced wicket developers to see if
I'm not missing something or if you have better ideas about how to implement
what I want.

Thanks,

Xavier
--
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://incubator.apache.org/ivy/
http://www.xoocode.org/


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Gwyn Evans
On Wednesday, July 11, 2007, 9:19:51 AM, Johan [EMAIL PROTECTED] wrote:


 Ugh. We still seem to be changing lots of fundamental stuff, don't we. :-)

 I vote:
 [x] deprecate them for beta3

 We could possibly remove them for rc1, but that makes migration from
 1.2.x harder, doesn't it?

 i personally don't care that much about breaking stuff for 1.3.
 We really need to streamline the api i think for 1.3 so that we don't have
 to break a lot in the further anymore
 lets make 1.3 a very solid base..

I do - that's the reason that we /always/ slip releases, as there's
/always/ just one more let's tidy this up change.

It also means that committers don't feel any big urge to ship
releases, as they're still tweaking as they want, while normal
users are still waiting for a stable release they can use.

/Gwyn



Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Martijn Dashorst

On 7/11/07, Gwyn Evans [EMAIL PROTECTED] wrote:

I do - that's the reason that we /always/ slip releases, as there's
/always/ just one more let's tidy this up change.



It also means that committers don't feel any big urge to ship
releases, as they're still tweaking as they want, while normal
users are still waiting for a stable release they can use.


I agree, but do have a slightly different pov: I discovered this while
revising a chapter for the Book, and not having to explain the type
parameter in this chapter saved about 1 1/2 page. I can now delay that
until later in the book.

In that light, I found the parameter to be superfluous and not needed.
I don't mind it being shot down though: like I said, it is late in the
game.

Martijn

--
Wicket joins the Apache Software Foundation as Apache Wicket
Apache Wicket 1.3.0-beta2 is released
Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3.0-beta2/


Re: wicketstuff-push: centralizing requests

2007-07-11 Thread Vincent Demay

Xavier Hanin wrote:

Hi,

I'm currently using wicketstuff-push to push events to a page and it 
works

pretty well, but not well enough. Before trying to move to a comet based
implementation, I would like to improve the timer based 
implementation. In
the current implementation you got as many AjaxTimer as you install 
the push

on components on the same page. So if you have three components requiring
push, you will have three requests each x seconds, to poll for push 
events
from the three components. This would be much more efficient if I had 
only

one request polling for all push events sent by all components on the
page...

Hence my first thought was to add the timer behavior to the page 
instead of

the component, and verify that the same kind of behavior is not already
installed before installing a new one. The problem is that when I install
the behavior the component doesn't know its page. So I have to do 
something

at this time, and then later when I know the page make sure that only one
behavior is actually rendered.

I see two solutions to this problem:
- Add one timer behavior to each component (as today), and then when
rendering the component use the wasRendered/markRendered methods of
IHeaderResponse to render only one of them (using the isEnabled method to
disable it if another similar one has already been rendered). But then I
will have to update all the non rendered behaviors so that push events 
sent

to them are actually sent to the only behavior which is rendered.
- Modify the API of the push service and ask to enable push on a page 
before
actually using push on components on the page. This would actually 
install a
unique timer behavior on the page. Then when installing push on a 
component
I could simply add something which could be located by the unique 
timer on

the page to collect all push events (maybe a disabled behavior)

Now that I expose the two options I think I prefer the first one. But I
would like to gather feedback from experienced wicket developers to 
see if
I'm not missing something or if you have better ideas about how to 
implement

what I want.


Hy Xavier,

I've got an idea but I don't know if it will be convenient:
TimerPushBehavior should not extends AjaxTimerBehavior. 
TimerPushBehavior could now do :
- Adding a javascript(jsMain) in the header (using a static id - render 
once). This javascript can manage ajax timer on a specific callback url.
- Each TimerPushBehavior registers its component id on the previous 
added javascript(jsMain)

- When a callback is received by the first added behavior:
   * get all id registered in jsMain (sent to the behavior as 
parameters of the callbackUrl)

   * look for each child(server side) by they component id (IVisitor)
   * look for TimerPushBehavior on each child
   * call onTimer method on each TimerPushBehavior of each Child

it is may be a little bit hacked but it can be a solution.
WDYT?

--
Vincent


Thanks,

Xavier




Re: wicketstuff-push: centralizing requests

2007-07-11 Thread Xavier Hanin

On 7/11/07, Vincent Demay [EMAIL PROTECTED] wrote:


Xavier Hanin wrote:
 Hi,

 I'm currently using wicketstuff-push to push events to a page and it
 works
 pretty well, but not well enough. Before trying to move to a comet based
 implementation, I would like to improve the timer based
 implementation. In
 the current implementation you got as many AjaxTimer as you install
 the push
 on components on the same page. So if you have three components
requiring
 push, you will have three requests each x seconds, to poll for push
 events
 from the three components. This would be much more efficient if I had
 only
 one request polling for all push events sent by all components on the
 page...

 Hence my first thought was to add the timer behavior to the page
 instead of
 the component, and verify that the same kind of behavior is not already
 installed before installing a new one. The problem is that when I
install
 the behavior the component doesn't know its page. So I have to do
 something
 at this time, and then later when I know the page make sure that only
one
 behavior is actually rendered.

 I see two solutions to this problem:
 - Add one timer behavior to each component (as today), and then when
 rendering the component use the wasRendered/markRendered methods of
 IHeaderResponse to render only one of them (using the isEnabled method
to
 disable it if another similar one has already been rendered). But then I
 will have to update all the non rendered behaviors so that push events
 sent
 to them are actually sent to the only behavior which is rendered.
 - Modify the API of the push service and ask to enable push on a page
 before
 actually using push on components on the page. This would actually
 install a
 unique timer behavior on the page. Then when installing push on a
 component
 I could simply add something which could be located by the unique
 timer on
 the page to collect all push events (maybe a disabled behavior)

 Now that I expose the two options I think I prefer the first one. But I
 would like to gather feedback from experienced wicket developers to
 see if
 I'm not missing something or if you have better ideas about how to
 implement
 what I want.

Hy Xavier,

I've got an idea but I don't know if it will be convenient:
TimerPushBehavior should not extends AjaxTimerBehavior.
TimerPushBehavior could now do :
- Adding a javascript(jsMain) in the header (using a static id - render
once). This javascript can manage ajax timer on a specific callback url.
- Each TimerPushBehavior registers its component id on the previous
added javascript(jsMain)
- When a callback is received by the first added behavior:
* get all id registered in jsMain (sent to the behavior as
parameters of the callbackUrl)
* look for each child(server side) by they component id (IVisitor)
* look for TimerPushBehavior on each child
* call onTimer method on each TimerPushBehavior of each Child

it is may be a little bit hacked but it can be a solution.
WDYT?


Salut Vincent,

The idea to use a specific javascript to handle the timer is interesting.
Though ATM I've started implementing the first solution I suggested above,
and it now works pretty well like this. So I think I'll stick with that for
the moment, unless someone tell me there is a serious flaw in the approach I
used. You will also be able to review what I've done when I'll commit it on
wicketstuff-push, and revert or use another approach if there is a problem.

BTW I'm having an issue with the timer, but I think it's a bug in the
AbstractAjaxTimerBehavior implementation (I'll send another e-mail about
this).

Xavier

--

Vincent

 Thanks,

 Xavier





--
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://incubator.apache.org/ivy/
http://www.xoocode.org/


bug in AbstractAjaxTimerBehavior?

2007-07-11 Thread Xavier Hanin

Hi,

I think I've found a bug in AbstractAjaxTimerBehavior... The problem happens
when a component to which an AbstractAjaxTimerBehavior is attached is
rendered by an AjaxRequestTarget which is not due to the timer, but to
another Ajax call. In this case it seems that the renderHead method called
on AbstractAjaxTimerBehavior adds another setTimeout() javascript call than
the one originally rendered, which makes the timer call happen twice as
frequently as it should. I haven't isolated the problem in a simple example,
so my analysis may be wrong (I'm experiencing this issue when working on
wicketstuff-push, so the source can be something else).

Do you think my analysis make sense? Should I open an issue in JIRA?

Xavier
--
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://incubator.apache.org/ivy/
http://www.xoocode.org/


Re: Escaping quotes in attributes

2007-07-11 Thread Eelco Hillenius

  1. Automatically insert an attribute value that's the same as the name
 (which I think it always should be), for things like disabled.

  2. Prevent people adding null values to the map in the first place. To
 do this, we'd need to wrap the IValueMap in XmlTag with some magic
 on the put method to check for null values. Or we could add a
 boolean flag to IValueMap to say whether it accepts them, or
 similar.

Obviously #1 is nice and simple.

What do people think?


#1 sounds good to me.

Eelco


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Igor Vaynberg

On 7/11/07, Martijn Dashorst [EMAIL PROTECTED] wrote:


On 7/11/07, Gwyn Evans [EMAIL PROTECTED] wrote:
 I did want to respond to Johan's comment, but it's /not/ a -1 vote,
 especially in view of your reasons above - 0 if anything.

I didn't want to imply as such, but I would not hold a grudge if you
would -1 it. It is late in the game, so ...



the thing about removing convertValue(String[])

if we are going to do it it needs to be now, or it wont make it into
1.3.xperiod. so we need to decide if this is important enough to get
into
1.3 branch.

one tricky part about it is that the converter will have to be installed for
String[]? or do we call it repeatedly if there is more then one element?

-igor


Martijn


--
Wicket joins the Apache Software Foundation as Apache Wicket
Apache Wicket 1.3.0-beta2 is released
Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3.0-beta2/



Wicket and VMBuild

2007-07-11 Thread Brett Porter

Hi,

I'm not on this list, so please reply directly - thanks.

Wicket currently have a build set up in vmbuild.apache.org. It's been  
down for little bit, but is now back up.


vmbuild is scheduled to be moved to a faster machine, and I intend to  
install a more recent build of Continuum (that supports grouping  
projects and is generally faster, more managable and more stable).  
I'm able to help get it set up as effectively as possible.


There are a lot of failing builds on the machine right now (probably  
unused by the corresponding projects), so I'm cleaning house before  
the move.


Please let me know if:
[ ] you would like the project set up on the new machine with a clean  
slate
[ ] you would like the project (and it's build history if possible)  
moved over
[ ] you are no longer interested in using vmbuild for CI/nightlies/ 
whatever


Thanks!
- Brett


Re: bug in AbstractAjaxTimerBehavior?

2007-07-11 Thread Xavier Hanin

On 7/11/07, Johan Compagner [EMAIL PROTECTED] wrote:


please make a jira issue for this yes, i guess we need some check on
an id so that we dont add it twice



Done:
https://issues.apache.org/jira/browse/WICKET-745

Xavier

On 7/11/07, Xavier Hanin [EMAIL PROTECTED] wrote:

 Hi,

 I think I've found a bug in AbstractAjaxTimerBehavior... The problem
happens
 when a component to which an AbstractAjaxTimerBehavior is attached is
 rendered by an AjaxRequestTarget which is not due to the timer, but to
 another Ajax call. In this case it seems that the renderHead method
called
 on AbstractAjaxTimerBehavior adds another setTimeout() javascript call
than
 the one originally rendered, which makes the timer call happen twice as
 frequently as it should. I haven't isolated the problem in a simple
example,
 so my analysis may be wrong (I'm experiencing this issue when working on
 wicketstuff-push, so the source can be something else).

 Do you think my analysis make sense? Should I open an issue in JIRA?

 Xavier
 --
 Xavier Hanin - Independent Java Consultant
 http://xhab.blogspot.com/
 http://incubator.apache.org/ivy/
 http://www.xoocode.org/






--
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://incubator.apache.org/ivy/
http://www.xoocode.org/


Re: Clone problem? Difference in behavior between 1.2 and 1.3

2007-07-11 Thread Eelco Hillenius

this is not really solveable by wicket itself.
We don't know where such a reference is comming from, so this should be
documented i guess
that if you use session data from the session object itself. You should
always use an extra
indiretion to get it
new Model()
{
  getObject() {Session.get().getList()}
}


I don't see a generic solution either, but in this case I though you
should use custom serialization of either your custom session or a
model you use for the extra indirection.

Eelco


Thread synchronization problems in FilePageStore

2007-07-11 Thread Jan Vermeulen

As a consequence of 'random' errors in a single-page application using
Wicket, that always occurred after restoring a page from the FilePageStore,
I have been debugging the FilePageStore extensively.

I have extended the FilePageStoreTest with a method to simulate the errors
(see code included at the end of this post).

When does the error occur ?
I suppose the error is unlikely to occur in an application in which
navigation is between pages. But in a 'single-page' application, or an
application that allows for state changes within the same page, it is likely
to  occur. The error occurs when someone generates a new version of a page,
requests a previous version of that same page, and repeats that 'forward and
backward' movement. Since the page id remains the same, and the
versionNumber gets incremented and decremented, there is a case in which he
ends up with an incorrect restored page, i.e. a page that corresponds to a
previous 'forward and backward' movement: it has the same page id and
versionNumber, but not necessarily the same state.

What's really going wrong here ? 
Finally I found 2 'holes' in the thread synchronization between the
different threads that operate in the process of page storage. (1) is more
likely to happen than (2).

(1) The thread that saves the pages in a file, sleeps during 1 second
(before 2, in which the error occurred  more easily). Then it gets an
iterator on the 'pagesToBeSaved' map. For being a ConcurrentHashMap, that
iterator takes a snapshot of the contents of the map, and works on that
snapshot. For performance reasons, this process is does not lock the
'pagesToBeSaved' map. So someone can come in an store a new entry in the map
while the iterator is busy saving pages. If the entry happens to have the
same key as one that is already present, it simply replaces that entry.
Problem is now that the saving thread saves the cached (now obsolete) entry,
and finally removes the (updated) entry. So the last added entry never gets 
saved, and on the next retrieval, the wrong page will be returned, because
that's what's in the file.  

(2) The thread that serializes the pages correctly locks access to the list
of pages to be serialized for a given session, but when it has serialized a
page, it first removes that entry from the 'pagesToBeSerialized' list, and
only after that (without locking) adds that entry to the 'pagesToBeSaved'.
That leaves a small hole where the given entry is in neither of the 2 maps.
With some bad luck (it actually occurred in realtime), the thread that looks
for a page to restore it, might not find it in either of the two lists, and
thus decide to restore it from file. And since there was already some file
with that key, it ends up restoring the wrong page. This is a less likely
scenario to occur, but it can be easily provoked by adding a sleep() between
removal from one list and addition to the other to exagerate the hole.

Solutions to the problem 
With the following changes in FilePageStore, the holes can be tapped:

(1) change PageSavingThread to iterate the keys, and lookup actual the value
for each iteration. That way, we reduce the change of saving an obsolete
page if the 'pagesToBeSaved' map has been updated after the iterator has
been created. Advantage: no locking for the whole iteration process is
needed.

Iterator it = pagesToBeSaved.keySet().iterator();
while (it.hasNext())
{
synchronized (pagesToBeSaved) {
SessionPageKey key = 
(SessionPageKey)pagesToBeSaved.get(it.next());
if (key.data instanceof byte[])
{
savePage(key, (byte[])key.data);
}
pagesToBeSaved.remove(key);
}
}

(2) add a synchronize lock on the 'pagesToBeSaved' map for each single
iteration, to prevent that another thread can update an entry while it is
being saved and removed. The updates on 'pagesToBeSaved' must also lock
access to the map. This prevents the update of an entry in the map while the
saving thread is saving and removing the entry.

synchronized (pagesToBeSaved) {
pagesToBeSaved.put(key, key);
}

(3) change the order in which the PageSerializingThread removes entries from
the 'pagesToBeSerialized' map and adds entries to the 'pagesToBeSaved' map:
if the entry is added to the 'pagesToBeSaved' before being removed from the
'pagesToBeSerialized', there can be no case in which it is neither of the
two lists. The fact that it might appear in both lists at a single moment,
does not affect the correct restore of pages in any way.

synchronized (sessionList)
{
key.setObject(pageBytes);
synchronized (pagesToBeSaved) {
pagesToBeSaved.put(key, key);
}
sessionList.remove(key);
sessionList.notifyAll();
}


Re: [vote] remove type parameter from TextField constructor

2007-07-11 Thread Johan Compagner

it must handle string[] because sometimes for a multiselect it returns
a collection. I guess that is tricky thing to put into the converter
interface :(

On 7/11/07, Igor Vaynberg [EMAIL PROTECTED] wrote:

On 7/11/07, Martijn Dashorst [EMAIL PROTECTED] wrote:

 On 7/11/07, Gwyn Evans [EMAIL PROTECTED] wrote:
  I did want to respond to Johan's comment, but it's /not/ a -1 vote,
  especially in view of your reasons above - 0 if anything.

 I didn't want to imply as such, but I would not hold a grudge if you
 would -1 it. It is late in the game, so ...


the thing about removing convertValue(String[])

if we are going to do it it needs to be now, or it wont make it into
1.3.xperiod. so we need to decide if this is important enough to get
into
1.3 branch.

one tricky part about it is that the converter will have to be installed for
String[]? or do we call it repeatedly if there is more then one element?

-igor


Martijn

 --
 Wicket joins the Apache Software Foundation as Apache Wicket
 Apache Wicket 1.3.0-beta2 is released
 Get it now: http://www.apache.org/dyn/closer.cgi/wicket/1.3.0-beta2/




Re: Clone problem? Difference in behavior between 1.2 and 1.3

2007-07-11 Thread Johan Compagner

the problem with session data is just tricky, if you have a shopping
basket that is stored in the session object, and you add some to it,
the remove a few, then use the back button. what you now see on the
screen is the full shopping basket again, but on the serverside a
previos page is restored, so the view shows everything but the data
not, if you then remove one you have very funny behavior which you
really have to program for.

On 7/11/07, Eelco Hillenius [EMAIL PROTECTED] wrote:

 this is not really solveable by wicket itself.
 We don't know where such a reference is comming from, so this should be
 documented i guess
 that if you use session data from the session object itself. You should
 always use an extra
 indiretion to get it
 new Model()
 {
   getObject() {Session.get().getList()}
 }

I don't see a generic solution either, but in this case I though you
should use custom serialization of either your custom session or a
model you use for the extra indirection.

Eelco



Re: Thread synchronization problems in FilePageStore

2007-07-11 Thread Eelco Hillenius

I opened an issue here http://issues.apache.org/jira/browse/WICKET-746

Eelco


Re: Thread synchronization problems in FilePageStore

2007-07-11 Thread Matej Knopp

Btw, I've tried the test you provided with both FilePageStore and
DiskPageStore. It failed with FilePageStore but passed with
DiskPageStore.

-Matej

On 7/11/07, Jan Vermeulen [EMAIL PROTECTED] wrote:


As a consequence of 'random' errors in a single-page application using
Wicket, that always occurred after restoring a page from the FilePageStore,
I have been debugging the FilePageStore extensively.

I have extended the FilePageStoreTest with a method to simulate the errors
(see code included at the end of this post).

When does the error occur ?
I suppose the error is unlikely to occur in an application in which
navigation is between pages. But in a 'single-page' application, or an
application that allows for state changes within the same page, it is likely
to  occur. The error occurs when someone generates a new version of a page,
requests a previous version of that same page, and repeats that 'forward and
backward' movement. Since the page id remains the same, and the
versionNumber gets incremented and decremented, there is a case in which he
ends up with an incorrect restored page, i.e. a page that corresponds to a
previous 'forward and backward' movement: it has the same page id and
versionNumber, but not necessarily the same state.

What's really going wrong here ?
Finally I found 2 'holes' in the thread synchronization between the
different threads that operate in the process of page storage. (1) is more
likely to happen than (2).

(1) The thread that saves the pages in a file, sleeps during 1 second
(before 2, in which the error occurred  more easily). Then it gets an
iterator on the 'pagesToBeSaved' map. For being a ConcurrentHashMap, that
iterator takes a snapshot of the contents of the map, and works on that
snapshot. For performance reasons, this process is does not lock the
'pagesToBeSaved' map. So someone can come in an store a new entry in the map
while the iterator is busy saving pages. If the entry happens to have the
same key as one that is already present, it simply replaces that entry.
Problem is now that the saving thread saves the cached (now obsolete) entry,
and finally removes the (updated) entry. So the last added entry never gets
saved, and on the next retrieval, the wrong page will be returned, because
that's what's in the file.

(2) The thread that serializes the pages correctly locks access to the list
of pages to be serialized for a given session, but when it has serialized a
page, it first removes that entry from the 'pagesToBeSerialized' list, and
only after that (without locking) adds that entry to the 'pagesToBeSaved'.
That leaves a small hole where the given entry is in neither of the 2 maps.
With some bad luck (it actually occurred in realtime), the thread that looks
for a page to restore it, might not find it in either of the two lists, and
thus decide to restore it from file. And since there was already some file
with that key, it ends up restoring the wrong page. This is a less likely
scenario to occur, but it can be easily provoked by adding a sleep() between
removal from one list and addition to the other to exagerate the hole.

Solutions to the problem
With the following changes in FilePageStore, the holes can be tapped:

(1) change PageSavingThread to iterate the keys, and lookup actual the value
for each iteration. That way, we reduce the change of saving an obsolete
page if the 'pagesToBeSaved' map has been updated after the iterator has
been created. Advantage: no locking for the whole iteration process is
needed.

Iterator it = pagesToBeSaved.keySet().iterator();
while (it.hasNext())
{
synchronized (pagesToBeSaved) {
SessionPageKey key = 
(SessionPageKey)pagesToBeSaved.get(it.next());
if (key.data instanceof byte[])
{
savePage(key, (byte[])key.data);
}
pagesToBeSaved.remove(key);
}
}

(2) add a synchronize lock on the 'pagesToBeSaved' map for each single
iteration, to prevent that another thread can update an entry while it is
being saved and removed. The updates on 'pagesToBeSaved' must also lock
access to the map. This prevents the update of an entry in the map while the
saving thread is saving and removing the entry.

synchronized (pagesToBeSaved) {
pagesToBeSaved.put(key, key);
}

(3) change the order in which the PageSerializingThread removes entries from
the 'pagesToBeSerialized' map and adds entries to the 'pagesToBeSaved' map:
if the entry is added to the 'pagesToBeSaved' before being removed from the
'pagesToBeSerialized', there can be no case in which it is neither of the
two lists. The fact that it might appear in both lists at a single moment,
does not affect the correct restore of pages in any way.

synchronized (sessionList)
{
key.setObject(pageBytes);

Re: Nonsensical default validation messages

2007-07-11 Thread Ryan Holmes
As long as you're fixing those messages, I think they have a couple  
of other problems (I'm using 1.2, but it looks like 1.3 has the same  
issues).


First, both messages are off by one . When you create a  
MaximumValidator with a value of 3, the value is inclusive so 3 is a  
valid input. But the message says '5 must be *smaller than* 3', which  
doesn't include 3 itself. It should read 5 must not be greater than  
3 or something along those lines.


The second point is minor, but greater and smaller are kind of  
lopsided antonyms. Bigger/smaller or greater/less would be more  
in sync. Something like this:


NumberValidator.minimum='${label}' must not be less than ${minimum}.
NumberValidator.maximum='${label}' must not be greater than ${maximum}.

Thanks,
-Ryan

On Jul 6, 2007, at 11:42 AM, Al Maw wrote:



The current default validation messages in Application.properties  
make no logical sense.


At the moment, if you put in a value that is larger than a  
NumberValidator maximum it says:


5 must be smaller than 3

Which it can't be, not even for very small values of 5.

To fix this, we need to do one of the following two things:

1. Change ${input} to ${label}, in which case they would all make  
sense.


2. Change the text so it actually makes sense in the context of $ 
{input}

   as in the attached patch. e.g. 5 is larger than 3., which would
   at least tell you what's currently wrong with it.

I appreciate the argument that people don't call setLabel() when  
they should do, but the current set-up isn't nice.


Thoughts?

Regards,

Al

--
Alastair Maw
Wicket-biased blog at http://herebebeasties.com
Index: /home/almaw/svn/wicket/wicket-1.x/jdk-1.4/wicket/src/main/ 
java/org/apache/wicket/Application.properties

===
--- /home/almaw/svn/wicket/wicket-1.x/jdk-1.4/wicket/src/main/java/ 
org/apache/wicket/Application.properties	(revision 553981)
+++ /home/almaw/svn/wicket/wicket-1.x/jdk-1.4/wicket/src/main/java/ 
org/apache/wicket/Application.properties	(working copy)

@@ -15,18 +15,18 @@
 Required=Field '${label}' is required.
 IConverter='${input}' is not a valid ${type}.

-NumberValidator.range=${input} must be between ${minimum} and $ 
{maximum}.

-NumberValidator.minimum='${input}' must be greater than ${minimum}.
-NumberValidator.maximum='${input}' must be smaller than ${maximum}.
+NumberValidator.range=${input} is not between ${minimum} and $ 
{maximum}.

+NumberValidator.minimum='${input}' is smaller than ${minimum}.
+NumberValidator.maximum='${input}' is larger than ${maximum}.

-StringValidator.range='${input}' must be between ${minimum} and $ 
{maximum} characters.
-StringValidator.minimum='${input}' must be at least ${minimum}  
characters.
-StringValidator.maximum='${input}' must be at most ${maximum}  
characters.

-StringValidator.exact='${input}' must be ${exact} characters long.
+StringValidator.range='${input}' is not between ${minimum} and $ 
{maximum} characters.
+StringValidator.minimum='${input}' is less than ${minimum}  
characters.
+StringValidator.maximum='${input}' is more than ${maximum}  
characters.
+StringValidator.exact='${input}' is not exactly ${exact}  
characters long.


-DateValidator.range='${input}' must be between ${minimum} and $ 
{maximum}.

-DateValidator.minimum='${input}' must be greater than ${minimum}.
-DateValidator.maximum='${input}' must be smaller than ${maximum}.
+DateValidator.range='${input}' is not between ${minimum} and $ 
{maximum}.

+DateValidator.minimum='${input}' is less than ${minimum}.
+DateValidator.maximum='${input}' is larger than ${maximum}.