Michal, I adopted your idea, but with a variation. It is something like: // Use this instead of WebPage for any base page whose component-tree // construction relies on abstract or overridable methods. // abstract class DelayedConstructionWebPage extends WebPage {
private Boolean componentsAssembled = false; ...(preserve the standard constructors of WebPage)... // This method's implementation will build the component tree. // It may freely call abstract or overridable methods. // abstract protected void assembleComponents(); // If you have any method which accesses a component, // and which might be called before the first rendering, // to ensure that the component exists you should insert // a one-line call to assembleComponentsIfNecessary() // protected assembleComponentsIfNecessary() { if ( !componentsAssembled ) { assembleComponents(); componentsAssembled = true; } } @Override void onBeforeRender() { assembleComponentsIfNecessary(); super.onBeforeRender(); } } I believe this will minimize the boilerplate code in the classes that provide the actual business value. -----Original Message----- From: Michal Kurtak [mailto:michal.kur...@gmail.com] Sent: Monday, November 02, 2009 11:08 AM To: users@wicket.apache.org Subject: Re: Glue for composing panels Yes Frank, model-setting method was just an example how to access a component before onBeforeRender() executes. I've only tried to point out that we set componentsAssembled = true in assembleComponents() method. We call assembleComponents() from get-method (for referenced component) to ensure that referenced component has been created. michal ... > /Frank > > -----Original Message----- > From: Michal Kurtak [mailto:michal.kur...@gmail.com] > Sent: Monday, November 02, 2009 3:39 AM > To: users@wicket.apache.org > Subject: Re: Glue for composing panels > > Hi Frank, > > We use the same approach as you. We have found one disadvantage, which > relates to references to components created by subclasses. > I'll demostrate it (problem and solution) in the following example: > > class BasePage extends Page > { > /** Component created by subclass */ > private Component component; > private boolean componentsAssembled = false; > > /** Let the assemple method to set componentsAssembled flag */ > private void assembleComponents() > { > component = createComponent(); > ... > componentsAssembled = true; > } > > protected abstract Component createComponent(); > > @Override > void onBeforeRender() { > if ( !componentsAssembled ) { > assembleComponents(); > } > super.onBeforeRender(); // Or whatever else is needed > } > > /** Method uses assambelComponents() to ensure, that component is created */ > public Component getComponent() > { > if(component == null) > { > assembleComponents(); > } > return component; > } > > /** public method delegete to referenced component. Uses safe > getComponent() method */ > public void setComponentModel(IModel<?> model) > { > getComponent().setModel(model); > } > > > > michal > > > 2009/10/29 Frank Silbermann <frank.silberm...@fedex.com>: >> >> I was discussing glue for composing reusable panels into web pages on >> the blog of Erik van Oosten >> (http://blog.jteam.nl/2009/09/16/wicket-dos-and-donts/). >> >> I told him that my approach had been to create an abstract base page >> that constructs the common elements while leaving place-holders for >> page-specific panels by defining methods such as: >> >> abstract Panel createUpperLeftPanel (String wicketID); >> abstract Panel createLowerRightPanel(String wicketID); >> >> and having the base page's constructor say things like: >> >> Panel p1 = createUpperLeftPanel("a_wicket_id"); >> add(p1); >> ... >> Add( createUpperRightPanel("another_wicket_id") ); >> >> The child page's contribution would be the implementation of the >> abstract methods. >> >> I explained that I preferred this to mark-up inheritance because I could >> add to the base page in any number places (not just one place), the >> compiler would tell the child-page writer exactly what panels were >> needed, and most importantly, no additional mark-up whatsoever would >> need to be associated with any of the child pages. (Panel classes used >> by the child page would of course have their associated mark-up.) >> >> Eric and others explained what a bad idea it is for constructors to call >> overridable methods -- they execute before the child-page's properties >> have been set. I usually got away with this, but I admit I was burnt a >> few times. Recently, I wondered whether there might be a simple fix for >> the constructor-calls-overridable-method problem, such as: >> >> (a) Move the base page's component tree construction out of the >> constructor, and put it into the method: >> >> private void assembleComponents() { >> ... >> } >> >> (b) Add the property: >> >> private boolean componentsAssembled = false; >> >> (c) Override as follows to construct the component tree after the class >> constructors finish: >> >> �...@override >> void onBeforeRender() { >> if ( !componentsAssembled ) { >> assembleComponents(); >> componentsAssembled = true; >> } >> super.onBeforeRender(); // Or whatever else is needed >> } >> >> Then component construction would wait until the properties in both the >> parent and the subclass had been set. I'd no longer have the problem >> associated with calling abstract methods from the constructor. >> >> Do you see any disadvantages to this approach? Is there a more >> appropriate hook upon which to hang my base page's component-tree >> assembly? >> >> If it _is_ a good approach, is there any reason the Wicket designers >> chose not to create an overrideable method in the Component class that >> is called just once after constructors terminate, and tell developers >> that this is where the component tree should be created? >> >> /Frank --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org For additional commands, e-mail: users-h...@wicket.apache.org