title: JPA Eclipselink Database Change Notification does not invalidate cache entry
body: <p>I have two Java 1.7 applications using Eclipselink 2.4.2 for persistence.  One application is a JEE application running in Glassfish 3.1.2.2 and the other is a Java SE application.  These applications read and write the same data, so there is the possibility of stale JPA cache entries.  I am attempting to use <a href="http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/DatabaseEvents" rel="nofollow">Oracle DCN</a> to solve the stale cache problem.</p>
  
  <p>I have configured my persistence.xml as described in the link above:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;persistence xmlns="http://java.sun.com/xml/ns/persistence"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
               http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
               version="2.0"&gt;
    &lt;persistence-unit name="drms-persistence-unit" transaction-type="JTA"&gt;
      &lt;provider&gt;org.eclipse.persistence.jpa.PersistenceProvider&lt;/provider&gt;
      &lt;jta-data-source&gt;jdbc/DRMS&lt;/jta-data-source&gt;
      &lt;properties&gt;
        &lt;property name="eclipselink.cache.database-event-listener"
                  value="org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener"/&gt;
        &lt;property name="eclipselink.target-server" value="SunAS9"/&gt;
        &lt;property name="eclipselink.target-database" value="Oracle"/&gt;
        &lt;property name="eclipselink.logging.level" value="INFO"/&gt;
        &lt;property name="eclipselink.logging.parameters" value="true"/&gt;
        &lt;property name="eclipselink.jdbc.native-sql" value="true"/&gt;
        &lt;property name="eclipselink.jdbc.batch-writing" value="Oracle-JDBC"/&gt;
        &lt;property name="eclipselink.jdbc.cache-statements" value="true"/&gt;
        &lt;property name="eclipselink.jdbc.cache-statements.size" value="200"/&gt;
      &lt;/properties&gt;
    &lt;/persistence-unit&gt;
  &lt;/persistence&gt;
  </code></pre>
  
  <p>And yet, I still get stale cache entries.  If one application commits a change to the database, the second application still sees its old stale cache entry, rather than the new change.  Using a debugger, I have confirmed that the OracleChangeNotificationListener is receiving database events, but it never seems to actually invalidate anything in the cache. </p>
  
  <p>The Eclipselink OracleChangeNotificationListener registers the following listener to receive Oracle database change events:</p>
  
  <pre><code>public void onDatabaseChangeNotification(DatabaseChangeEvent changeEvent) {
      databaseSession.log(SessionLog.FINEST, SessionLog.CONNECTION, "dcn_change_event", changeEvent);
      if (changeEvent.getTableChangeDescription() != null) {
          for (TableChangeDescription tableChange : changeEvent.getTableChangeDescription()) {
              ClassDescriptor descriptor = OracleChangeNotificationListener.this.descriptorsByTable.get(new DatabaseTable(tableChange.getTableName()));
              if (descriptor != null) {
                  CacheIndex index = descriptor.getCachePolicy().getCacheIndex(fields);                                
                  for (RowChangeDescription rowChange : tableChange.getRowChangeDescription()) {
                      CacheId id = new CacheId(new Object[]{rowChange.getRowid().stringValue()});
                      CacheKey key = databaseSession.getIdentityMapAccessorInstance().getIdentityMapManager().getCacheKeyByIndex(
                              index, id, true, descriptor);
                      if (key != null) {
                          if ((key.getTransactionId() == null) || !key.getTransactionId().equals(changeEvent.getTransactionId(true))) {
                              databaseSession.log(SessionLog.FINEST, SessionLog.CONNECTION, "dcn_invalidate", key.getKey(), descriptor.getJavaClass().getName());
                              key.setInvalidationState(CacheKey.CACHE_KEY_INVALID);
                          }
                      }
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>This listener does get invoked anytime we make a change to the database.  However, the CacheKey value that gets looked up is always null, and so the invalidation code never runs.  </p>
  
  <p>If I inspect the IdentityMapManager object in the debugger, I can see that the expected entity is in the cache.  And yet the look up by CacheId fails every time (returns null).</p>
  
  <p>Any help is appreciated.   </p>