aspose file tools*
The moose likes EJB and other Java EE Technologies and the fly likes EJB 3.0 remove Entity Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » EJB and other Java EE Technologies
Bookmark "EJB 3.0 remove Entity" Watch "EJB 3.0 remove Entity" New topic
Author

EJB 3.0 remove Entity

Rene Curth
Greenhorn

Joined: May 13, 2004
Posts: 11
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.

Rene
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17250
    
    6

Are you using versioning? Wouldn't the second POJO already have an ID, and therefore EJB 3.0 wouldn't try an insert?

Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
Rene Curth
Greenhorn

Joined: May 13, 2004
Posts: 11
Hi Mark,
thanks for answering,

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
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.
Rene Curth
Greenhorn

Joined: May 13, 2004
Posts: 11
Hi Parameswaran,
You can now download a test preview on bea: http://commerce.bea.com/showproduct.jsp?family=WLS&major=EJB30Tech&minor=-1&www_WLS-EJB30Tech_Body
which will be integrated in a future version.

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
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.

-Mike


-Mike
Pro JPA 2: Mastering the Java Persistence API
Rene Curth
Greenhorn

Joined: May 13, 2004
Posts: 11
Hi Mike,
thanks a lot for answering.

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).


Thanks in advance.

Rene

p.s. I surely will have a look on your book ;-)



package ejbtest;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;

/**
* represents an entity POJO for demonstrating EJB 3.0 persistance matters
* @author Rene
*
*/
@Entity
public class Depot implements Serializable {

private int id;
private long version;
private String name;

public Depot() {
}

public Depot(String name) {
this.name = name;
}

@Id
@GeneratedValue
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

@Version
protected long getVersion() {
return version;
}

protected void setVersion(long version) {
this.version = version;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


package ejbtest;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import ejbtest.DepotManager;

public @Stateless class DepotManagerBean implements DepotManager {

@PersistenceContext(unitName = "ejbTest")
private EntityManager manager;

public Depot addDepot(Depot depot) {
manager.persist(depot);
return depot;
}

public void removeDepot(Depot depot) {
manager.remove(depot);
}

public Depot updateDepot(Depot depot) {
return manager.merge(depot);
}

public List getAllDepots() {
Query query = manager.createQuery("from Depot");
return query.getResultList();
}

}


package ejbtest;

import java.util.List;

import javax.ejb.Remote;

@Remote
public interface DepotManager {
public Depot addDepot(Depot depot);
public void removeDepot(Depot depot);
public Depot updateDepot(Depot depot);
public List getAllDepots();
}


package ejbtest;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.List;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeSelectionModel;

/**
* 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 {

private JPanel buttonPanel;
private JTextField depotName;
private JTree tree;
private JButton addButton, removeButton, renameButton, refreshButton;
private JScrollPane scrollPane;

private Context jndiContext;
private DepotManager manager;

/**
* Client constructor
*
*/
public Client() {
try {
initManager();
initLayout();
} catch (NamingException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
Client client = new Client();
}

/**
* initialyzes JNDI-Context and references DepotManager
* @throws NamingException
*/
public void initManager() throws NamingException {
jndiContext = getInitialContext();
Object managerBean = jndiContext.lookup("DepotManagerBean/remote");
manager = (DepotManager) managerBean;
}

/**
* initialyzes the GUI-component
*
*/
private void initLayout() {
buttonPanel = new JPanel();
depotName = new JTextField(10);

addButton = createButton("add");
removeButton = createButton("remove");
renameButton = createButton("rename");
refreshButton = createButton("refresh");

buttonPanel.add(depotName);
buttonPanel.add(addButton);
buttonPanel.add(removeButton);
buttonPanel.add(renameButton);
buttonPanel.add(refreshButton);

tree = createTree();
scrollPane = new JScrollPane(tree);

getContentPane().add(scrollPane, BorderLayout.CENTER);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

pack();
setVisible(true);
}

/**
* creates Button
* @param title sets text of button
* @return
*/
private JButton createButton(String title) {
JButton button = new JButton(title);
button.addActionListener(this);

return button;
}

/**
* creates tree of depots
* @return the tree
*/
private JTree createTree() {
List depots = manager.getAllDepots();

DefaultMutableTreeNode top = new DefaultMutableTreeNode("Depots");
Iterator it = depots.iterator();

while (it.hasNext()) {
Depot depot = (Depot) it.next();
DefaultMutableTreeNode node = new DefaultMutableTreeNode(depot);
top.add(node);
}

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();
}
}

/**
* gets initial context
* @return context
* @throws javax.naming.NamingException
*/
public Context getInitialContext() throws javax.naming.NamingException {
return new javax.naming.InitialContext();
}

/**
* CellRenderer of depot tree
* @author Rene
*
*/
public class TreeCellRenderer extends DefaultTreeCellRenderer {

/**
* 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) {

super.getTreeCellRendererComponent(tree, value, sel, expanded,
leaf, row, hasFocus);

Object o = ((DefaultMutableTreeNode) value).getUserObject();

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
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
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
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
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
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://aspose.com/file-tools
 
subject: EJB 3.0 remove Entity