It was in my hash function. Hibernate works like a charm.
The reduced problem was to persist the following XML tree:
<contenttree name="test">TA
<item name="login" >Login page</item>
<item name="home" >Home page</item>
<item name="services" >Services
<item name="info412" >Info 412</item>
<item name="alice" >Area Clienti Alice</item>
<item name="smart" >Area Clienti Smart</item>
<item name="fbc" >Area Clienti FBC</item>
</item>
<item name="profile" >Profile
<item name="cardinfo" >My Account</item>
<item name="changepwd" >Change Password</item>
</item>
<item name="coverage" >Coverage</item>
<item name="events">Events</item>
<item name="support" >Support
<item name="faq">FAQ</item>
<item name="downloads">Downloads</item>
<item name="contacts">Contacts</item>
</item>
<item name="logout">Logout</item>
<item name="popup" >Popup
<item name="legals">Legal Notes</item>
<item name="help">Help</item>
</item>
<item name="wba">WBA</item>
<item name="wbalogin">WBALOGIN</item>
</contenttree>
by the composite pattern whose mapping file is:
<hibernate-mapping>
<class name="content.TreeItem"
table="CATEGORY">
<id name="id"
column="ID_CATEGORY"
type="long">
<generator class="increment"/>
</id>
<property name="name"/>
<set name="subcategories"
inverse="false"
lazy="true"
cascade="save-update">
<key column="PARENT_ID"/>
<one-to-many class="content.TreeItem"/>
</set>
<many-to-one name="parent"
column="PARENT_ID"
cascade="save-update"
class="content.TreeItem"/>
</class>
</hibernate-mapping>
The code is the following:
public static Node findNode(Node node, String name)
{
if (node == null) throw new IllegalArgumentException("node cannot be null");
if (node.getNodeName().equals(name))
{
return node;
}
if (node.hasChildNodes())
{
NodeList list = node.getChildNodes();
int size = list.getLength();
for (int i = 0; i < size; i++)
{
if (isElementNode(list.item(i)))
{
Node found = findNode(list.item(i), name);
if (found != null)
{
return found;
}
}
}
}
return null;
}
main:
........
Node contentNode = findNode(doc, "contenttree");
persistTreeItem(contentNode);
...............................................
where persistTreeItem(Node node) is:
Transaction tx = session.beginTransaction();
TreeItem tree = iterateXLM(session,topNode);
session.save(tree);
session.flush();
tx.commit();
abd finally:
private TreeItem createTreeItem(Node contentNode) throws DataLayerException
{
if (logger.isInfoEnabled()) logger.info("HibernateDataLayer.createTreeItem");
String name = XML.getAttributeValue(contentNode, "name").trim();
TreeItem cat = new TreeItem();
cat.setName(name);
if (logger.isInfoEnabled()) logger.info("name = " + name);
return cat;
}
private TreeItem iterateXLM(Session session, Node treeNode) throws DataLayerException
{
TreeItem cat = createTreeItem(treeNode);
List children = XML.getImmediateChildren(treeNode);
if (logger.isInfoEnabled()) logger.info("children.size() = " + children.size());
for (int i = 0; i < children.size(); i++)
{
Node child = (Node) children.get(i);
TreeItem childcat = iterateXLM(session,child);
cat.addSubcategories(childcat);
}
return cat;
}
public static List getImmediateChildren(Node node)
{
List children = new ArrayList();
NodeList nl = node.getChildNodes();
for (int i = 0; i < nl.getLength(); i++)
{
Node n = nl.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE)
children.add(n);
}
return children;
}
public static String getAttributeValue(Node result,
String attributeName)
{
String val = "";
if (XML.isElementNode(result))
{
NamedNodeMap atts = result.getAttributes();
for (int i = 0; i < atts.getLength(); i++)
{
Node att = atts.item(i);
if (XML.isAttributeNode(att))
{
// check if the attribute name is the same
if (att.getNodeName().equalsIgnoreCase(attributeName))
{
val = att.getNodeValue();
return val;
}
}
}
}
return val.trim();
}
The class TreeItem is:
public class TreeItem
{
protected static Log logger = LogFactory.getLog(TreeItem.class);
private Long id;
private String name;
private Long parent;
private Set subcategories = new HashSet();
public TreeItem()
{
}
public Long getId()
{
return id;
}
private void setId(Long id)
{
this.id = id;
}
public Set getSubcategories()
{
return subcategories;
}
public void setSubcategories(Set subcategories)
{
this.subcategories = subcategories;
}
public void addSubcategories(TreeItem subcategory)
{
this.subcategories.add(subcategory);
}
public Long getParent()
{
return parent;
}
public void setParent(Long parent)
{
this.parent = parent;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public boolean equals(Object o)
{
if (this == o) return true;
if (!(o instanceof TreeItem)) return false;
final TreeItem treeItem = (TreeItem) o;
if (id != null ? !id.equals(treeItem.id) : treeItem.id != null) return false;
if (name != null ? !name.equals(treeItem.name) : treeItem.name != null) return false;
if (parent != null ? !parent.equals(treeItem.parent) : treeItem.parent != null) return false;
if (subcategories != null ? !subcategories.equals(treeItem.subcategories) : treeItem.subcategories != null) return false;
return true;
}
public int hashCode()
{
int result;
result = (id != null ? id.hashCode() : 0);
result = 29 * result + (name != null ? name.hashCode() : 0);
result = 29 * result + (parent != null ? parent.hashCode() : 0);
result = 29 * result + (subcategories != null ? subcategories.hashCode() : 0);
return result;
}
}
Finally MySQL correctly persists the composite tree as:
ID_CATEGORY name PARENT_ID
----------- --------- ---------
1 test (NULL)
2 login 1
3 events 1
4 popup 1
5 legals 4
6 help 4
7 wba 1
8 home 1
9 services 1
10 info412 9
11 fbc 9
12 alice 9
13 smart 9
14 coverage 1
15 profile 1
16 changepwd 15
17 cardinfo 15
18 wbalogin 1
19 logout 1
20 support 1
21 faq 20
22 contacts 20
23 downloads 20
Pretty cool stuff this hibernate!
|