...
Children Display | ||||||
---|---|---|---|---|---|---|
|
Best Practices
Html Template Declaration
...
Why - because A) we don't want to risk serialize an object, models are fine though - lightweight and ok. And we want to let the component take care of the detach when the request is done B) With an direct-entity we would set an nondynamic value to our label. With a model, the label will update the value from the entity it's using.
...
May collide with wicket code, make sure you know your JS-library well
Do make sure you understand the repeaters for high performance sites
...
The remedy is to split of parts of the screen to separate components (e.g. Panels) and manage the complexity there.
...
Don't try to do authorization from a servlet filter
Do take your time to override key Wicket features
Wicket Filter Mapping
Wicket 1.4.x and upwards
On these versions, you should prefer to use WicketFilter instead of WicketServlet. If you want, it's possible to map /*
instead of /app/*
. But remember to configure the ignorePaths
parameter to ignore static resources and leave them to be handled by the container.
Ignoring paths
If you want to leave static resources to be handled by the container, configure the ignorePaths
init parameter as follows:
It just won't work. Wicket is full of generated URLs (yes, even if you mount every page) so authorization based on the URL is a fruitless exercise. You are better off by writing an IAuthorizationStrategy and configuring this in your Wicket application. Study the code of wicket-auth-roles to see how this can work. In addition you'll get component based authorization, not just page based! (By the way, you'll have no problems with filter based authentication.)
Do take your time to override key Wicket features
Wicket can be tweaked in all kinds of expected and unexpected ways. For example you can substitute your own resource messages provider, filter and change the markup as it is read from disk or completely override the request cycle handling. However, some of these extension points are not for the faint hearted and not likely to be right immediately
onInitialize for adding components.
If you need to , and for components that are not a Page, you can override the new onInitialize callback to add components, which is only called once after construction, when the component has been added to the page (so that component.getPage() doesn't return null).
Another option is to use addOrReplace() instead of add.
Wicket Filter Mapping
Wicket 1.4.x and upwards
On these versions, you should prefer to use WicketFilter instead of WicketServlet. If you want, it's possible to map /*
instead of /app/*
. But remember to configure the ignorePaths
parameter to ignore static resources and leave them to be handled by the container.
Ignoring paths
If you want to leave static resources to be handled by the container, configure the ignorePaths
init parameter as follows:
Code Block |
---|
<filter>
<filter-name>wicket.app</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>com.myproject.MyApplication</param-value>
</init-param>
<init-param>
<param-name>filterMappingUrlPattern</param-name>
|
Code Block |
<filter>
<filter-name>wicket.app</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>com.myproject.MyApplication</param-value>
</init-param>
<init-param>
<param-name>filterMappingUrlPattern</param-name>
<param-value>/*</param-value>
</init-param>
<init-param>
<param-name>ignorePaths</param-name>
<param-value>/css,/js,/images,/icons</param-value>
</init-param>
</filter>
|
Otherwise, there's a risk the wicketservlet will handle the job to serve static resources, instead of the container.
For example,let's say you have /myapp/images/foo.gif
and you map your wicket servlet to /*
and dpn't have set ignorePaths.
Antipatterns
Anti-Pattern #1.
Code Block |
---|
public FooPanel(String id,IModel<User> userMdl) {
super(id,userMdl);
final User user = getModelObject();
IModel<List<User>> model = new LoadableDetachableModel<List<User>>() {
private static final long serialVersionUID = 1L;
@Override
protected List<User> load() {
// A Stale User entity is now serialized with each page view
// This can consume lots of session space if the user entity is large.
return getWebSession().getUserService().getUserFriends(user);
}
};
}
|
Here
...
is
...
the
...
correct
...
way
...
to
...
do
...
this
Code Block |
---|
//IModel needs to be a LoadableDetachableModel! public FooPanel(String id,IModel<User> userMdl) { super(id,userMdl); final User user = getModelObject(); IModel<List<User>> model = new LoadableDetachableModel<List<User>>() { private static final long serialVersionUID = 1L; @Override protected List<User> load() { User uuser = FooPanel.this.getModelObject(); return getWebSession().getUserService().getUserFriends(uuser); } }; } |
The
...
entity
...
is
...
fetched
...
each
...
page
...
view,
...
and
...
NOT
...
serialized
...
with
...
the
...
page.
...
The
...
only
...
thing
...
that
...
gets
...
serialized
...
is
...
the
...
fetching
...
model.
...
Anti-Pattern #2.
Code Block |
---|
public FooPanel(String id,IModel<User> userMdl) { super(id.userMdl); User user = getModelObject(); // Doh! user is not serialized with each page view, since the PropertyModel holds a reference! add(new Label("name",new PropertyModel(user,"screenName"))); } |
Here
...
is
...
the
...
correct
...
way
...
to
...
do
...
this:
Code Block |
---|
public FooPanel(String id,IModel<User> userMdl) {
super(id.userMdl);
add(new Label("name",new PropertyModel(userMdl,"screenName")));
}
|
The
...
PropertyModel
...
holds
...
a
...
reference
...
to
...
the
...
Model
...
which
...
fetches
...
the
...
User
...
on
...
each
...
page
...
view.
...
That
...
way
...
the
...
User
...
object
...
is
...
always
...
fresh
...
and
...
is
...
not
...
serialized
...
with
...
the
...
page.
...
Anti-Pattern #3.
Code Block |
---|
public FooPanel(String id,User user) {
// The stale User object will be in your session
// for the life span of the stateful page.
super(id.new Model(user));
}
|
Here
...
is
...
the
...
correct
...
way
...
to
...
do
...
this,
...
though
...
not
...
very
...
elegant.
Code Block |
---|
public FooPanel(String id,User user) { super(id); final int id = user.getId(); setModel(new LoadableDetachableModel<List<User>>() { @Override protected List<User> load() { return getUserDao().findById(id); } |
antipattern 1-3 from blog letsgetdugg, thanks
Anti-pattern #4. - Anonymous Inner classes
Don't do this:
Code Block |
---|
class MyPage extends WebPage { private MyVeryLargeObject subject; // .... public MyPage() { // get my very large object from database subject = MyVeryLargeObjectDao.get(); // ... form.add(new TextField("name", new PropertyModel(MyPage.this, "some.very.large.navigational.structure.name")); } } |
The 'subject' instance of the MyVeryLargeObjectDao class will be serialized into the session with each page version. This can get out of hand, because with some business object models, the attached object can become very large. For this we introduced DetachableModels, which will retrieve the data from the database when needed, and will clean up when the data is not needed (at the end of the request for instance).
The other thing to avoid is be careful about are anonymous or nested instances subclasses of IModel. Usually you shouldn't share an instance of a model between two page instances. If But if you create an anonymous or nested instance of IModel, then you automatically get a 'this' reference to the class that surrounds it. This will usually be the page, but can also be the form or a listview. Anyway, because the reference is /final/, you will copy that reference to the old page, with the model to the new page, thus duplicating the component tree (it gets versioned etc.). This will eventually lead to OutOfMemoryError.
...
PBEWithMD5AndDES not found
_\[For the [For the moment, I'll leave this, but I'm not convinced this actually belongs here at all -_ _[Gwyn|User__Gwynevans]_ _13:56, 23 Aug 2006 (BST)\]_ Wiki Markup
Not entirely clear what causes this.
...
- download http://www.bouncycastle.org/download/bcprov-jdk15-133.jar
- put it in jre\lib\ext
- in java.security (jre\lib\security), add this security provider:
Code Block security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
...
\[Comments on the mailing list suggest this has been seen _twice_ only, and may be due to misconfigured/corrupted JDK - Suggest reinstalling the JDK before adding BouncyCastle... [Gwyn|User__Gwynevans] 13:56, 23 Aug 2006 (BST)\]
I've only seen this under the SysDeo Tomcat plug-in for Eclipse, when the boot classpath wasn't configured properly to include jce.jar, etc. – Al Maw
...
This is due to a hard to fix issue. As long as that issue is open, people should avoid setting id attributes on tags that are coupled to components that use rely on the markup id (setOutputMarkupId true). See ). See http://issues.apache.org/jira/browse/WICKET-694 – Eelco
Avoid using empty elements (i.e. <textarea />)
Wicket will not automatically expand an empty element (i.e., an element that is expressed as a single tag ending in "/>") during the rendering phase. You should always include both an open tag and a close tag in your markup when you want Wicket to include content in the tag body.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<textarea wicket:id="mytext" />
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<textarea wicket:id="mytext">Content to be replaced by Wicket</textarea>
|
Links with stuff not yet integrated:
http://www.devproof.org/wicket_best_practice - Devproof best practices
http://blog.worldturner.com/worldturner/entry/wicket_best_practices_components_vs blog worldtuner
http://issueswww.apachesmall-improvements.org/jira/browse/WICKET-694 – Eelco
Avoid using empty elements (i.e. <textarea />)
Wicket will not automatically expand an empty element (i.e., an element that is expressed as a single tag ending in "/>") during the rendering phase. You should always include both an open tag and a close tag in your markup when you want Wicket to include content in the tag body.
...
<textarea wicket:id="mytext" />
...
<textarea wicket:id="mytext">Content to be replaced by Wicket</textarea>
--Jaycom/10-things-about-apache-wicket-i-love/wicket:pageMapName/wicket-0 - 10 things to know..
http://stronglytypedblog.blogspot.se/2009/04/wicket-patterns-and-pitfalls-5.html Wicket pitfalls 5 articles
http://wicketinaction.com/ in action - lots of good stuff if searching here