0

This is not a real problem but more a question to JCA experts to make me see the light wrt one aspect of the JCA spec. I am trying to understand why JCA mandates that a resource adapter bean and managed connection factories must implement equals() and hashCode().

IMO a resource adapter or a managed connection factory are objects managed by an application server, at least in the managed environment. So they are not so far away from EJBs, Servlets, CDI managed beans where the application server is in charge of managing instances. And the number of instances for a resource adapter class or a managed connection factory class is directly defined by its deployment.

So why does anyone need equals() and hashCode() on these classes? I have never made any other implementation than calling the super implementations, which works quite fine until now. But certainly sonar does not really appreciate this.

Robert Panzer
  • 1,419
  • 12
  • 14

2 Answers2

1

To quote from the JCA specification (version 1.0, but 1.5 has the same text and I assume newer versions have it as well):

A resource adapter is required to provide an implementation of the ManagedConnectionFactory interface.
It is required that the ManagedConnectionFactory implementation class extend the implementation of the hashCode and equals methods defined in the java.lang.Object class. These two methods are used by an application server to structure its connection pool in an implementation-specific way. The equals and hashCode method implementation should be based on a complete set of configuration properties that makes a ManagedConnectionFactory instance unique and specific to an EIS instance.

and

An application server may use additional parameters for its search and matching criteria used in its connection pool management. These parameters may be EIS or application server specific. The equals and hashCode methods defined on both ManagedConnectionFactory and ConnectionRequestInfo facilitate the connection pool management and structuring by an application server.

The specification says nothing more about this (except specifying the same requirement for some of the other interfaces).

As the general idea is that managed connection implementations are provided by vendors (for example database vendors), and that the application server can pool the resources (eg ManagedConnection instances), and the sentence "These two methods are used by an application server to structure its connection pool in an implementation-specific way" I can only assume this was done to simplify things for implementations, eg for use in a HashMap or HashSet etc. For example creating two ManagedConnectionFactory instances with identical properties will have the same result for equals and hashCode and therefore could use the same pool.

This seems to be supported by the following quote from the same spec:

An application server may partition its pool on a per ManagedConnectionFactory instance (and thereby on a per EIS instance) basis. An application server may choose to guarantee (in an implementation specific way) that it will always partition connection pools with at least per ManagedConnectionFactory instance granularity.

The JCA specification seems to imply that the connections to a single system should be handled by a single managed connection factory (although I believe it doesn't say it explicitly). This would require a way to find the one single ManagedConnectionFactory based on its properties.

As an example, the core of Jaybird (the Firebird JDBC driver I maintain) is a JCA implementation (which btw can be a real pain). The initial implementation of Jaybird was by David Jencks who also wrote the JCA implementation of JBoss. In the driver the equals and hashCode are used in several ways:

  1. The ManagedConnectionfactory keeps a static WeakHashMap pointing an instance to itself. This is used to canonicalize an instance (if an instance already exists with the same equals and hashCode, that instance is returned).
  2. The java.sql.Driver implementation org.firebirdsql.jdbc.FBDriver keeps a WeakHashMap from ManagedConnectionfactory to a (non-pooling) javax.sql.DataSource implementation. When a new connection is created, this data source is retrieved (or otherwise created) to create the actual connection.
  3. When a ManagedConnectionFactory is deserialized, a readResolve method will return the canonicalized version (see 1) if it was already in the map.

As a side note: thanks for bringing this up; it looks like the current implementation in Jaybird has a bug here as both maps are keeping a direct and indirect strong reference to the managed connection factory, which makes the use of a weak hash map rather useless.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • Thanks for giving insight into a real implementation. Do you think that it is possible that an app server creates multiple instances of one MCF deployment? Or even worse, creates multiple instances of a RA deployment and calls start() only on one instance? Or even on all instances? (I cannot tell which way would give me more headaches;-) ) – Robert Panzer Oct 20 '14 at 20:41
  • @RobertPanzer To be honest, I am not familiar with all requirements of JCA (I inherited the current implementation when I took over the project, and I haven't had to dive too deep into it yet). As far as I understand a resource adapter is loaded only once; my best guess is that this might also be used for the case were two RAs point to the same resource; and as indicated above for looking up the pool associated with the RA. – Mark Rotteveel Oct 20 '14 at 20:49
0

If you have a look at the spec you will find the reason: https://jcp.org/aboutJava/communityprocess/mrel/jsr322/index.html

6.5.3.2 Requirements A resource adapter must provide an implementation of the ManagedConnectionFactory interface. It is required that the ManagedConnectionFactory implementation class extend the implementation of the hashCode and equals methods defined in java.lang.Object. These two methods are used by an application server to structure its connection pool in an implementation-specific way. The equals and hashCode method implementation should be based on a complete set of configuration properties that make a ManagedConnectionFactory instance unique and specific to an EIS instance.

Simon Martinelli
  • 34,053
  • 5
  • 48
  • 82
  • Hi Simon, thanks for your response! I already found this paragraph in the spec as most app servers indicate the section no in error messages;-) My question was more about why the spec demands that? I can see no reason for having these methods on a RA that would not be equally valid for EJBs, CDI managed beans etc. – Robert Panzer Oct 20 '14 at 19:18
  • A resource adapter is something completely different fro EJB or CDIs. As the JCA components are pooled in the App Server. So equals and hashCode are used if the App server keeps the Factory in a collection. – Simon Martinelli Oct 20 '14 at 19:27
  • Hmm... IMO opinion EJBs are rather pooled in contrast to RAs. I directly define the number of instances of my RA or my MCF via my deployment, at least in the managed env. I expect that only one RA is created and started per deployment, and not several each using the same properties. Maybe this makes more sense in the non-managed env. – Robert Panzer Oct 20 '14 at 19:35
  • 1
    You should definitely read the spec: 6.5.3.3 Connection Pool Implementation and 9.1.8.2 Contract for Resource Adapter – Simon Martinelli Oct 20 '14 at 19:51
  • I don't agree on 6.5.3.3 because it talks about managed connection factory instances. But you got me with 9.1.8.2, it states clearly that MCF.equals will be called. Though I still wonder if somebody has ever written an implementation that does not call the super implementations. – Robert Panzer Oct 20 '14 at 20:00
  • @RobertPanzer Well, Jaybird (see my answer) implements them. – Mark Rotteveel Oct 20 '14 at 20:20
  • Great ;-) I'm always happy to talk with someone who uses JCA. JCA is not very well known. – Simon Martinelli Oct 20 '14 at 20:20
  • @simas_ch In my case it is more something I inherited with Jaybird, I still haven't read the entire JCA specification and I try to avoid that part of Jaybird for the time being; although the day draws near that I have to touch it in order to rip out and replace some parts of the actual database connection and transaction implementation – Mark Rotteveel Oct 20 '14 at 20:42