Hello,
We have problem with serializing webpages - the user session files
growing rapidly (each request about 100KB), we don't know what we have
did wrong - system is based on examples from wicket.apache.org, so it
should work but this large files (10-20MB for some time, after many
request) slows it down.
We have tried to put transient in all fields which we are use as
components on WebPages - it doesn't help.
Maybe I put some code and little explain and you can tell us whay is wrong.
The example will be consider LinkTree with 2000+ categories:
Categories we have as Hibernate Entity cached whole in ehcache in memory:
@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Category implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String description;
@Enumerated(value = EnumType.STRING)
private CategoryStatus categoryStatus;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="parent_id", insertable=false, updatable=false,
nullable=true)
@Cascade(org.hibernate.annotations.CascadeType.ALL)
@Fetch(value=FetchMode.SELECT)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
private Category parent;
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name="parent_id")
@Cascade(org.hibernate.annotations.CascadeType.ALL)
@IndexColumn(name="list_id")
@Fetch(value=FetchMode.SELECT)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
private List<Category> children = new ArrayList<Category> ();
@Index(name = "categoryPathIndex")
private String categoryPath = "";
public Category addChild(Category child) {
child.parent = this;
children.add(child);
return this;
}
//getters setters hashcode equals
}
Next we put the categories on panel as:
public class CategoryTreePanel extends Panel {
private final transient Log LOG =
LogFactory.getLog(CategoryTreePanel.class);
private transient Category activeCategory;
private transient TreeNode treeNode;
private transient LinkTree tree;
public CategoryTreePanel(String id, List<Category> rootCategory) {
this(id, rootCategory, null);
}
public CategoryTreePanel(String id, List<Category> rootCategory,
Category activeCategory) {
super(id);
LOG.info("activeCategory: " + activeCategory);
this.activeCategory = activeCategory;
tree = new CarPartsLinkTree("category_tree",
createTreeModel(rootCategory));
tree.setRootLess(true);
LOG.info("treeNode: " + treeNode);
if(treeNode != null) {
expandAllParentNodes(tree, treeNode);
tree.getTreeState().selectNode(treeNode, true);
} else {
tree.getTreeState().collapseAll();
}
add(tree);
}
class CarPartsLinkTree extends LinkTree {
public CarPartsLinkTree(String id, TreeModel model) {
super(id, model);
}
@Override
protected void onNodeLinkClicked(TreeNode node, BaseTree tree,
AjaxRequestTarget target) {
super.onNodeLinkClicked(node, tree, target);
int catId = ((CategoryTreeNode)
((DefaultMutableTreeNode)
node).getUserObject()).getCategory().getId();
setRedirect(true);
Page page = getPage();
if(page instanceof AdvertismentsList || page instanceof
AddAdvertisement) {
setResponsePage(getPage().getClass(), new
PageParameters("category=" + catId));
} else {
setResponsePage(AdvertismentsList.class, new
PageParameters("category=" + catId));
}
}
@Override
protected ResourceReference getCSS() {
return null;
}
protected Component newNodeComponent(String id, IModel model) {
return new LinkIconPanel(id, model,
CarPartsLinkTree.this) {
private static final long serialVersionUID = 1L;
protected void onNodeLinkClicked(TreeNode node,
BaseTree tree,
AjaxRequestTarget target)
{
super.onNodeLinkClicked(node, tree,
target);
CarPartsLinkTree.this.onNodeLinkClicked(node, tree, target);
}
protected Component newContentComponent(String
componentId,
BaseTree tree, IModel model)
{
return new Label(componentId,
getNodeTextModel(model));
}
@Override
protected ResourceReference
getResourceFolderOpen(TreeNode node) {
return new
ResourceReference(CategoryTreePanel.class,
"res/folder-open.gif");
}
@Override
protected ResourceReference
getResourceFolderClosed(TreeNode node) {
return new
ResourceReference(CategoryTreePanel.class,
"res/folder-closed.gif");
}
@Override
protected ResourceReference
getResourceItemLeaf(TreeNode node) {
return new
ResourceReference(CategoryTreePanel.class, "res/item.gif");
}
};
}
}
private void expandAllParentNodes(AbstractTree tree, TreeNode treeNode) {
tree.getTreeState().expandNode(treeNode);
if(treeNode.getParent() != null) {
expandAllParentNodes(tree, treeNode.getParent());
}
}
private TreeModel createTreeModel(List<Category> rootCategories) {
TreeModel model = null;
DefaultMutableTreeNode rootNode = new
DefaultMutableTreeNode("rootCategory");
add(rootNode, rootCategories);
model = new DefaultTreeModel(rootNode);
return model;
}
private class CategoryTreeNode {
private Category category;
public CategoryTreeNode(Category category) {
super();
this.category = category;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String toString() {
return category.getName();
}
}
private void add(DefaultMutableTreeNode parent, List<Category> sub) {
for (Iterator<Category> i = sub.iterator(); i.hasNext();) {
Category category = i.next();
DefaultMutableTreeNode child = new
DefaultMutableTreeNode(new CategoryTreeNode(category));
parent.add(child);
if(category.equals(activeCategory)) {
treeNode = child;
}
if(category.getChildren().size() > 0) {
add(child, category.getChildren());
}
}
}
}
Next we put panel on the page:
public abstract class CommonWebPage extends WebPage {
@SpringBean
private transient SessionService sessionService;
@SpringBean
private transient CategoryDAO categoryDAO;
//some reusabale elements
public static final String ID_PARAMETER = "id";
private static final String CATEGORY_PARAMETER = "category";
public static final String EMPTY_STRING = "";
public static final String EQUALS = "=";
protected static final char DOT_SEPERATOR = '.';
protected static final String[] ALLOWED_PICTURES_TYPES = new String[]
{"jpg", "gif", "jpeg", "png"};
public static final String ONCHANGE_BEHAVIOR = "onchange";
public static final String ONCLICK_BEHAVIOR = "onclick";
//wicket:ids
private static final String CATEGORIES = "categories";
private static final String MAIN_MENU = "main_menu";
protected static final String SEARCH_PANEL = "search_panel";
static {
Arrays.sort(ALLOWED_PICTURES_TYPES);
}
protected transient Category category;
private transient Label categoryTreePanel;
private transient Menu menu;
public CommonWebPage(PageParameters pageParameters) {
super();
loginUserIfRemembered();
if(pageParameters.get(CATEGORY_PARAMETER) != null) {
category =
categoryDAO.getCategoryById(Integer.parseInt((String)
pageParameters.get(CATEGORY_PARAMETER)));
}
menu = new Menu(MAIN_MENU, category, isUserLogin());
add(menu);
categoryTreePanel = new CategoryTreePanel(CATEGORIES,
categoryDAO.getRootCategories(), category);
add(categoryTreePanel);
}
....
}
This is first problem large data is kept in session which is same for
all users (TreeModel), what can be done? What is wrong?
Second problem is with serializing some objects which we don't want
and use LoadebaleDeatachableModel for them:
public class CarPartDataProvider implements IDataProvider{
private transient CarPartService carPartService;
private transient Category category;
public CarPartDataProvider(CarPartService carPartService) {
super();
this.carPartService = carPartService;
}
public CarPartDataProvider(CarPartService carPartService, Category
category) {
super();
this.carPartService = carPartService;
this.category = category;
}
@SuppressWarnings("unchecked")
@Override
public Iterator iterator(int first, int count) {
return carPartService.getCarParts(category, first,
count).iterator();
}
@Override
public IModel model(Object carPart) {
return new CarPartDetachableModel((CarPart) carPart);
}
class CarPartDetachableModel extends LoadableDetachableModel {
private Integer carPartId;
public CarPartDetachableModel(CarPart carPart) {
this.carPartId = carPart.getId();
}
@Override
protected Object load() {
return carPartService.getCarPartById(this.carPartId);
}
}
@Override
public int size() {
return carPartService.getCarPartsSize(category);
}
@Override
public void detach() {
}
public CarPartService getCarPartService() {
return carPartService;
}
public void setCarPartService(CarPartService carPartService) {
this.carPartService = carPartService;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
I have see CarPart objects in serialized form in sesion which is
really unwanted for us - we cache all the objects in Hibernate so we
can get them really fast, serialization is not we want. Also we have
problem witch web spiders - spiders do not use session so for each
request is generated new session :(
I think it's problem by our side, so we ask for little help with optimizing.
Best regards,
Adr
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]