Bug 534274 (RHQ-1086) - plugin deployment fails when a new <runs-inside> parent is added to descriptor
Summary: plugin deployment fails when a new <runs-inside> parent is added to descriptor
Keywords:
Status: CLOSED NEXTRELEASE
Alias: RHQ-1086
Product: RHQ Project
Classification: Other
Component: Plugin Container
Version: 1.1
Hardware: All
OS: All
medium
medium
Target Milestone: ---
: ---
Assignee: John Mazzitelli
QA Contact: Corey Welton
URL: http://jira.rhq-project.org/browse/RH...
Whiteboard:
Depends On:
Blocks: RHQ-1093
TreeView+ depends on / blocked
 
Reported: 2008-11-08 07:12 UTC by John Mazzitelli
Modified: 2009-11-10 21:22 UTC (History)
0 users

Fixed In Version: 1.2
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description John Mazzitelli 2008-11-08 07:12:00 UTC
If you have a plugin previously deployed, then add a new <runs-inside> element to it and redeploy it, the server fails to update the metadata. See below for the exception.

This is needed because our Hibernate plugin cannot support managing Hib stats running in standalone J2SE deployments.  I have a J2SE app running with hib stats Mbean.  From a clean database and new hibernate plugin, I was able to import a JMX Server and have it auto-discovery the hibernate statistics service, as expected.  However, for those with hibernate plugin already deployed with the old metadata, they can't do this because the new plugin won't deploy.

To replicate:
1) run the RHQ Server. 
2) I imported a RHQ JBossAS server just so I can get data in the database for a JBossAS Server resource, a JMX Server resource and a Hibernate service resource (I don't know if it really matters, but I did this just to be thorough).
3) Shutdown the RHQ Server
4) Edit the hibernate plugin descriptor and add this to the <runs-inside> element:
    <parent-resource-type name="JMX Server" plugin="JMX"/>
5) Copy the new hibernate plugin in the RHQ Server's rhq-downloads/rhq-plugins directory
6) Restart the RHQ Server

You will get this exception:

02:02:44,953 ERROR [ProductPluginDeployer] Unable to deploy RHQ plugin [/C:/mazz/source/rhq/trunk/dev-container/jbossas/server/default/deploy/rhq.ear/rhq-downloads/rhq-plugins/jopr-hibernate-plugin-2.2.0-SNAPSHOT.jar]
javax.ejb.EJBException: java.lang.RuntimeException: javax.persistence.NonUniqueResultException: result returns 2 elements
        at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:63)
        ...
        at $Proxy313.registerPlugin(Unknown Source)
        at org.rhq.enterprise.server.core.plugin.ProductPluginDeployer.registerPluginJar(ProductPluginDeployer.java:407)
        at org.rhq.enterprise.server.core.plugin.ProductPluginDeployer.access$000(ProductPluginDeployer.java:74)
        at org.rhq.enterprise.server.core.plugin.ProductPluginDeployer$LatchedPluginDeploymentService.executeService(ProductPluginDeployer.java:311)
        at org.rhq.enterprise.server.core.concurrency.LatchedServiceController$LatchedService.run(LatchedServiceController.java:208)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.RuntimeException: javax.persistence.NonUniqueResultException: result returns 2 elements
        at org.rhq.enterprise.server.resource.metadata.ResourceMetadataManagerBean.updateType(ResourceMetadataManagerBean.java:358)
        at org.rhq.enterprise.server.resource.metadata.ResourceMetadataManagerBean.updateType(ResourceMetadataManagerBean.java:296)
        at org.rhq.enterprise.server.resource.metadata.ResourceMetadataManagerBean.updateTypes(ResourceMetadataManagerBean.java:155)
        at org.rhq.enterprise.server.resource.metadata.ResourceMetadataManagerBean.registerPlugin(ResourceMetadataManagerBean.java:134)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...
        at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
        ... 22 more
Caused by: javax.persistence.NonUniqueResultException: result returns 2 elements
        at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:85)
        at org.rhq.enterprise.server.resource.metadata.ResourceMetadataManagerBean.updateType(ResourceMetadataManagerBean.java:234)
        ... 43 more



Comment 1 John Mazzitelli 2008-11-09 06:13:03 UTC
stepping thru code to find out why this happens.

ResourceMetadataManagerBean.updateType

the first for-loop attaches the resourceType  parameter (which may or may already exist in the DB) as a child to the "real" parent entities. The parameter resourceType has id 0 because it is not attached yet. When we do:

realParentType.addChildResourceType(resourceType);

that attached the id=0 type to the real parent.

After this for loop completes, within the debugger, I execute "entityManager.flush()" and I see resourceType.id go from 0 to a non-zero value - the entity manager persisted the type (cascade?).  But one already exists under this name (the name/plugin columns on resource type do not have a unique index on them. So I now have two resource types with the same name/plugin in the DB but they are different (one has the old parent set, the other has the new parent set with the new <runs-inside> parent).

I think we need to get the resourceType's ID (if it already exists) and set it before calling realParentType.addChildResource(resourceType).

Comment 2 John Mazzitelli 2008-11-09 07:20:06 UTC
From a previous JIRA (jbnadm 1514), this thread between hrupp and ghinkle occurred and is relevent for this issue. it discusses the code that this RHQ jira refers to and is where the bug is located. note where greg says, "Let's make sure we add the constraint." - we do not have this constraint, as per my earlier comment in this jira where I say, "(the name/plugin columns on resource type do not have a unique index on them.".

---

hrupp:
 The query about exising types around line 198 does a .getSingleResult() call. This can fail if a plugin is redeployed and e.g. an existing service is moved from below a service X next to this service X. Testcase: PluginHandlingTest.testUpdatePlugin2

Greg Hinkle - 10/Jul/07 10:44 AM
This can't ever return more than one. In fact, there should be a constraint here to avoid it. You can't duplicate a plugin and type-name... they're considered together to be a resource-type's natural key.

Heiko W. Rupp - 10/Jul/07 10:53 AM
Do I understand it correctly that the following is then not ok:
platform
   service name="foo"
         service name="memory consumption"
   service name="bar"
         service name="memory consumption"
   serivce name="baz"
         service name="memory consumption"

Heiko W. Rupp - 10/Jul/07 11:04 AM
ResourceType currently has no unique constraint on (plugin, type-name). And after more thinking, the scenario I just described in the previous comment should be valid from the userfriendlyness point of view.

Greg Hinkle - 10/Jul/07 11:17 AM
Yea, this is something that we do not allow for with the current design. There are some nasty implications of having to deal with a natural key that is entirely dependent on its place in a hierarchy. To avoid this with the type system, I made the decision to have an arbitrary restriction of unique type names in a plugin. I think its a fairly minor inconvenience. (name the types "foo memory consuption", "bar memory consuption" etc. We also haven't run into anything like this yet as types don't usually get this granular.

Let's make sure we add the constraint.

Heiko W. Rupp - 10/Jul/07 03:29 PM
r5711 handles the movement of ResourceTypes. (r5711 refers to an old svn repository, not rhq)

Heiko W. Rupp - 11/Jul/07 06:24 AM
r5711 only handled half of it unfortunatley. Still working on it.


Comment 3 John Mazzitelli 2008-11-09 07:24:49 UTC
I don't see how this code in updateTypes can work as intended:

                // two results - see if one is us, then the other must be the existing type that we are looking for
                Iterator<ResourceType> iter = results.iterator();
                ResourceType rt1 = iter.next();
                ResourceType rt2 = iter.next();
                if (rt1.equals(resourceType)) {
                    existingType = rt2;
                } else if (rt2.equals(resourceType)) {
                    existingType = rt1;
                } else {
                    throw new IllegalArgumentException("Houston we have a problem: our type is not there");
                }

Resource type equality is only on name/plugin - it knows nothing about parent hierarchy. So, even if we had two resource types with the same name/plugin, but each in a different place in the parent-child hierarchy, those two resource types will always be equal because name/plugin are the same and that's all that equals() tests. Therefore, that if() check will always be true and the else clause is irrelevent. I don't think this block of code is valid - but i need someone else to look at this closely and confirm what I think I see.

Comment 4 John Mazzitelli 2008-11-09 08:31:54 UTC
fixed the code, but there is still some hack code in here that I am not sure works or is needed.  but I left that as-is as much as I could.  I smoke tested this fix and it works on my box (see RHQ-1093)

Comment 5 John Mazzitelli 2009-02-18 03:57:49 UTC
To test:

1) deploy plugins normally
2) take a plugin and add a <runs-inside> element to its descriptor
3) re-deploy that plugin
4) confirm that a) no error occurs and b) that new resource type parent-child hierachy is created

Comment 6 John Mazzitelli 2009-02-18 16:38:37 UTC
test complete and passed. I put the hibernate server inside the RHQ Agent server resource. Redeployed the hibernate plugin (I hot-deployed it too! that works also) and I saw the RHQ Agent server resource type now have the hibernate service as a child type. No errors in logs.

Comment 7 Corey Welton 2009-02-18 17:37:48 UTC
qa verified

Comment 8 Red Hat Bugzilla 2009-11-10 20:23:35 UTC
This bug was previously known as http://jira.rhq-project.org/browse/RHQ-1086



Note You need to log in before you can comment on or make changes to this bug.