This week's book giveaway is in the Agile and other Processes forum. We're giving away four copies of The Mikado Method and have Ola Ellnestam and Daniel Brolund on-line! See this thread for details.
Hi everybody, I'm clearly new to EJB 3.0, so please be patient with me :-)
I've got some Entity-Beans, which are transferred to a couple of Swing clients. These beans are then existing as POJO's unmanaged on the clients. If one of these clients is removing an entity, a session bean will remove it on the server. The other clients still have the correspondending POJO. If another client will operate on this POJO, e.g. rename its caption, and is then updating it via a session bean (entityManager.merge()), a new entity will be created (standard procedure of merge()).
This is absolutly not, what I want. I'm using optimistic locking, so I expected an Exception, to tell the renaming client, that this entity was removed or updated.
I know, that one have to 'remove' the associated unmanaged POJO's, but I only can think of this on the removing client, not on the others.
I don't want to check every time, when someone is changing a POJO, if this entity was already removed, because I thought, the container would do that for me.
Any ideas? Any help would be highly appreciated. Thans in advance.
yes I'm using @version. The second POJO (what I think you mean is the POJO of the second client) has the same id as the recently removed entity. In this case no entity with the same id as the client POJO is now existing in the database, so, as the merge will occur, a new entity will be inserted (with a completly new id, that's right), but it is inserted (what a pitty).
Any ideas?
Rene
Parameswaran Thangavel
Ranch Hand
Joined: Mar 01, 2005
Posts: 485
posted
0
Hi Rene. I am too new to EJB 3.0 and i want to run some sample applications using 3.0
Can you please clarify me on the below mentioned items.
1) Any idea about which version of Weblogic server will support 3.0 2) Suggest me some reference material.
I'm using JBoss AS 4.0.4, which is already supporting EJB 3.0.
I can recommend this book: Enterprise JavaBeans 3.0, Fifth Edition, ISBN: 059600978X from o'reilly. It explains a huge range of 3.0 aspects, unfortunately, not the question above.
Rene
Mike Keith
author
Ranch Hand
Joined: Jul 14, 2005
Posts: 304
posted
0
There are a few points to make on this issue:
1) The spec does mandate that the version field be checked at merge time, but only discusses it in terms of existing objects.
2) Users are not supposed to set version fields. This means that a provider should be able to detect on the merge call that the object pre-existed even though it was not in the database.
3) There are cases when objects are intended to be resurrected, so the ability to persist new objects with existing version numbers is not a bad thing.
In the end, I think that what you are doing should work and I would say that in order to get 3) one should have to call persist() on the object.
BTW, this is a persistence issue so I would recommend reading "Pro EJB 3: Java Persistence API" for more detailed JPA material.
I don't know, if I get it completly, but am I right, if I recapitulate your answer like this: the container (JBoss 4.0.4) will check, if a pre-existed object, well, pre-existed and would inform the client about this fact?
I'm not setting version fields by myself and I don't want to persist new objects with existing version numbers.
But I can observe, that a new object will be persisted, if a merge on an unmanaged object will be executed, although the managed version of this object is not existing anymore.
What I would expect, is an exception, if a pre-existed unmanaged POJO, will be merged by the container. Is this correct? If so, how is that be implemented?
I think, this observation is the result of my absence of understanding. So please have a look at my testing code, even if this will violate the "how to ask questions the smart way" rule (if so, sorry for that).
@Remote public interface DepotManager { public Depot addDepot(Depot depot); public void removeDepot(Depot depot); public Depot updateDepot(Depot depot); public List getAllDepots(); }
/** * is gui frame, where the user can interact with depot tree, * to demonstrate entity bean access and currency aspects * @author Rene * */ public class Client extends JFrame implements ActionListener {
JTree tree = new JTree(top); tree.setCellRenderer(new TreeCellRenderer()); tree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION);
return tree; }
/** * refreshes the tree with new data from database * */ private void refreshTree() { tree = createTree(); scrollPane.setViewportView(tree); depotName.setText(""); }
/** * sets the action of the buttons */ public void actionPerformed(ActionEvent e) { /* * adds new Depot with name from depotName text field, * sends this depot to application server * and refreshes the depot tree */ if (e.getSource() == addButton) { if (!depotName.equals("")) { Depot depot = new Depot(depotName.getText()); depot = manager.addDepot(depot); refreshTree(); } else { JOptionPane.showMessageDialog(this, "Please insert depot name.", "", JOptionPane.ERROR_MESSAGE); }
/** * removes the selected depot */ } else if (e.getSource() == removeButton) { try { if (tree.getLastSelectedPathComponent() != null) { Depot depot = (Depot) ((DefaultMutableTreeNode) tree .getLastSelectedPathComponent()).getUserObject(); manager.removeDepot(depot); refreshTree(); } } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Depot was updated. Please refresh view.", "", JOptionPane.ERROR_MESSAGE); }
/** * renames the selected depot with content of depotName text field, * updates it on application server */ } else if (e.getSource() == renameButton) { try { if (tree.getLastSelectedPathComponent() != null) { if (!depotName.getText().equals("")) { Depot depot = (Depot) ((DefaultMutableTreeNode) tree .getLastSelectedPathComponent()) .getUserObject(); depot.setName(depotName.getText()); depot = manager.updateDepot(depot); refreshTree(); } else { JOptionPane.showMessageDialog(null, "Please insert depot name.", "", JOptionPane.ERROR_MESSAGE); } } } catch (Exception ex) { JOptionPane.showMessageDialog(this, "Depot was updated. Please refresh view.", "", JOptionPane.ERROR_MESSAGE); } /* * refreshes depot tree */ } else if (e.getSource() == refreshButton) { refreshTree(); } }
/** * sets text of tree node to name of depot */ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (o instanceof Depot) { Depot depot = (Depot) o; this.setText(depot.getName()); }
return this; } } }
Mike Keith
author
Ranch Hand
Joined: Jul 14, 2005
Posts: 304
posted
0
Rene,
I am not generally in the habit of giving Hibernate help (given that I am an Oracle TopLink architect and all) but I will respond in this case as long as you take out the awful "from Depot" half-query and make it a proper standard JPA query :-)
Actually, in this case you are not really doing anything wrong, apart from removing entities and assuming that they are not removed. Looking at your entity and session bean it seems you have configured them correctly and I am surprised that Hibernate does not actually stop the insert from happening, especially given that you are using id generation. I thought that Hibernate actually treated entities with existing generated ids as pre-existing. In any case, though, as I said earlier, Hibernate can't technically be blamed for not following the spec, since the spec doesn't explicitly comment on version checks against non-existent objects. Dies seem like a usability concern, although I don't think it is a very common case.
One of the ways that I have seen this kind of situation solved is by doing logical deletes instead of real ones. In other words, use a column for flagging the entities as deleted and don't actually remove them. It is admitedly a bit of a pain, though, since queries and API need to consider the removed field in a number of places.
-Mike
Parameswaran Thangavel
Ranch Hand
Joined: Mar 01, 2005
Posts: 485
posted
0
Hi rene, i am not able to import javax.persistence.*; it says it cannot resolve the symbol.
i installed j2sdk 1.5 and set it in the java build path. i am using eclipse editor.
is there any other files i need to add to my class path.
Please help me
Rene Curth
Greenhorn
Joined: May 13, 2004
Posts: 11
posted
0
Hi Parameswaran,
you definitely need some othe jars in your classpath. To import javax.persistence.* classes, you have to integrate the ejb3-persistence.jar.
If you are using eclipse with JBoss you can use a plugin from JBoss, called JBoss Eclipse IDE 1.6. There are some wizards, which are integrating the nescessary jars for you.
Good luck :-)
Rene
Rene Curth
Greenhorn
Joined: May 13, 2004
Posts: 11
posted
0
Hi Mike, thanks for touching my soul with your wisdom (I'm so unworthy) ;-) I definitely will change my query, just the old sql habit, you know :-)
No kidding, thanks for analyzing my problem so deeply. I agree with you, that it will be painfull to work around the problem with fake removes, but if hibernate is not willing to do it for me, what choice do I have?
Thanks again.
Rene
p.s. how is it like on top of the oracle pyramid?
Mike Keith
author
Ranch Hand
Joined: Jul 14, 2005
Posts: 304
posted
0
I agree with you, that it will be painfull to work around the problem with fake removes, but if hibernate is not willing to do it for me, what choice do I have?
That is the beauty of the JPA standard. If one provider doesn't do what you want, you can change to another one that does. Of course, you need to be writing portable queries... :-)
I agree. Here's the link: http://ej-technologies/jprofiler - if it wasn't for jprofiler, we would need to
run our stuff on 16 servers instead of 3.