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
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).
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.
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.
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)
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
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.
qa verified
This bug was previously known as http://jira.rhq-project.org/browse/RHQ-1086