I am trying to implement an oracle DCN with eclipselink 2.6 and Oracle 11.2 with the ojdbc6 driver.
Currently, through the setup, i am receiving correctly the table change notifications through my receiver.
I have extended the org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener
in order to fix several problems that i noticed on my project.
First of i have overridden the register method in order to unwrap correctly the connection :
OracleConnection connection = null;
try {
Connection unwrapConnection = databaseSession.getServerPlatform().unwrapConnection(accessor.getConnection());
try {
if (unwrapConnection.isWrapperFor(OracleConnection.class)) {
connection = unwrapConnection.unwrap(OracleConnection.class);
} else {
// recover, not an oracle connection
connection = (OracleConnection) databaseSession.getServerPlatform().unwrapConnection(accessor.getConnection());
}
} catch (SQLException e) {
e.printStackTrace();
throw DatabaseException.sqlException(e, databaseSession.getAccessor(), databaseSession, false);
}
I am also storing each table's object_id (tableNameIdMap) in order to correctly find the table from each notification.
Here is the DatabaseChangeListener method :
public void onDatabaseChangeNotification(final DatabaseChangeEvent changeEvent) {
if (changeEvent.getTableChangeDescription() != null) {
for (TableChangeDescription tableChange : changeEvent.getTableChangeDescription()) {
String tableName = this.tableNameIdMap.get(tableChange.getObjectNumber());
if (tableName != null)
{
ClassDescriptor descriptor = DatabaseChangeNotificationListener.this.descriptorsByTable.get(new DatabaseTable(tableName));
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);
}
}
}
}
}
}
}
}
The problem i am having is that whenever i receive a notification, i cannot get the cacheKey.
The method getIdentityMapManager().getCacheKeyByIndex(...) always returns null
Debugging through, it seems that the identityMaManager should return the cacheKey from an identityMap (a weakHashMap). The corresonding rowId is present but it is not returned.
Here is the line in the IdentityMapManager#getCacheKeyByIndex
CacheKey cacheKey = map.getCacheKey(indexValues, false);
It seems the CacheId's hashMap is based on the values hashcode. But when in look in the map, the value i should receive is indexed by a CacheId that contains a ROWID. Therefore, i cannot see how this should ever work...
I have tried to instantiate the cacheId using instead :
CacheId id = new CacheId(new Object[]{rowChange.getRowid(});
An it still does not work as the hashcode of a ROWID is the object's hashcode or so it seems.
Therefore i am stuck here. I don't understand how this can work elsewhere.
Any help is appreciated.
FYI, here is an extract of my persistence.xml
<property name="eclipselink.target-database" value="Oracle11" />
<property name="eclipselink.jdbc.native-sql" value="true" />
<property name="eclipselink.jdbc.cache-statements" value="true" />
<property name="eclipselink.query-results-cache" value="true" />
<property name="eclipselink.cache.shared.default" value="true"/>
<property name="eclipselink.refresh" value="true" />
<property name="eclipselink.weaving" value="true"/>
<property name="eclipselink.cache.database-event-listener" value="com.isel.persistence.database.DatabaseChangeNotificationListener" />