Le plug-in OptimisticCallback permet de personnaliser les opérations de vérification et de comparaison des versions des objets du cache lorsqu'on utilise la stratégie de verrouillage optimiste.
Il est possible de fournir un objet connectable de rappel optimiste qui implémente l'interface com.ibm.websphere.objectgrid.plugins.OptimisticCallback. Pour les mappes d'entités, un plug-in OptimisticCallback hautes performances est automatiquement configuré.
L'interface OptimisticCallback permet de fournir des opérations de comparaison optimiste entre les valeurs d'une mappe. Un plug-in OptimisticCallback est nécessaire lorsqu'on utilise la stratégie de verrouillage optimiste. Le produit fournit une implémentation par défaut d'OptimisticCallback. Mais, en principe, c'est à l'application de connecter sa propre implémentation de cette interface.
public interface Employee
{
// Sequential sequence number used for optimistic versioning.
public long getSequenceNumber();
public void setSequenceNumber(long newSequenceNumber);
// Other get/set methods for other fields of Employee object.
}
Dans cet exemple, le chargeur sait qu'il peut utiliser la méthode getSequenceNumber pour obtenir la version actuelle d'un objet value Employee. Le chargeur incrémente la valeur retournée pour générer un nouveau numéro de version avant d'actualiser le stockage de persistance avec la nouvelle valeur d'Employee. Dans le cas d'un chargeur JDBC (Java Database Connectivity), c'est le numéro actuel de séquence dans la clause WHERE d'une instruction SQL UPDATE surqualifiée qui est utilisé et le chargeur utilise le nouveau numéro de séquence qui est généré pour définir la colonne des numéros de séquence. Autre possibilité : le chargeur recourt à une certaine fonction fournie en dorsal, qui actualise automatiquement une colonne masquée utilisables pour la vérification optimiste des versions.
Dans certains cas, une procédure stockée ou déclencheur peut être utilisée pour aider à maintenir une colonne contenant les informations de version. Si le chargeur utilise l'une de ces techniques pour maintenir des informations optimistes de version, l'application n'aura pas besoin de fournir d'implémentation d'OptimisticCallback. L'implémentation par défaut d'OptimisticCallback est utilisable dans ce scénario car le chargeur peut vérifier les versions de manière optimiste sans l'assistance d'un objet OptimisticCallback.
Les entités sont stockées dans l'ObjectGrid à l'aide d'objets tuple. Le comportement de l'implémentation par défaut d'OptimisticCallback est semblable à celui des mappes de non-entités. Mais la zone version dans l'entité est identifiée à l'aide de l'annotation @Version ou de l'attribut version dans le fichier XML de descripteur d'entités.
L'attribut version peut être de l'un des types suivants : int, Integer, short, Short, long, Long ou java.sql.Timestamp. Une entité ne doit avoir qu'un seul attribut version défini. L'attribut version ne doit être défini que pendant la construction. Une fois l'entité persistante, la valeur de l'attribut version ne doit pas être modifiée.
Si un attribut version n'est pas configuré et que l'on utilise la stratégie de verrouillage optimiste, le tuple tout entier est versionné en utilisant son état tout entier, ce qui est beaucoup plus onéreux.
@Entity
public class Employee {
private long sequence;
// Sequential sequence number used for optimistic versioning.
@Version
public long getSequenceNumber() {
return sequence;
}
public void setSequenceNumber(long newSequenceNumber) {
this.sequence = newSequenceNumber;
}
// Other get/set methods for other fields of Employee object.
}
Un plug-in OptimisticCallback doit implémenter l'interface OptimisticCallback et se conformer aux conventions habituelles des plug-in ObjectGrid. Pour plus d'informations, voir Interface OptimisticCallback.
La liste suivante décrit ou explique chacune des méthodes de l'interface OptimisticCallback :
Cette valeur spéciale est retournée par la méthode getVersionedObjectForValue si l'implémentation d'OptimisticCallback ne requiert pas de vérification des versions. L'implémentation pré-intégrée de la classe com.ibm.websphere.objectgrid.plugins.builtins.NoVersioningOptimisticCallback utilise cette valeur car la vérification des versions est désactivée lorsque c'est cette implémentation qui est spécifiée pour le plug-in.
La méthode getVersionedObjectForValue peut retourner une copie de la valeur ou d'un attribut de la valeur qui peut être utilisée à des fins de vérification des versions. Cette méthode est appelée chaque fois qu'un objet est associé à une transaction. Lorsqu'aucune API Loader n'est connectée à une mappe de sauvegarde, cette dernière utilise cette valeur au moment de la validation afin d'effectuer une comparaison optimiste des versions. La comparaison optimiste des versions est utilisée par la mappe de sauvegarde pour s'assurer que la version n'a pas changé après le premier accès de cette transaction à l'entrée de mappe qui a été modifiée par cette transaction. Si entre-temps une autre transaction a modifié la version de cette entrée de mappe, la comparaison échoue et la mappe de sauvegarde affiche une exception OptimisticCollisionException pour forcer la transaction à s'annuler. Si une API Loader est connectée, la mappe de sauvegarde n'utilise pas les informations de vérification optimiste des versions. Car c'est à l'API Loader d'effectuer cette comparaison optimiste et d'actualiser les informations de version quand c'est nécessaire. Normalement, l'API Loader obtient l'objet de version initial du LogElement transmis à sa méthode batchUpdate, laquelle méthode est appelée lorsqu'une opération de vidage se produit ou lorsqu'une transaction est validée.
public Object getVersionedObjectForValue(Object value)
{
if (value == null)
{
return null;
}
else
{
Employee emp = (Employee) value;
return new Long( emp.getSequenceNumber() );
}
}
Comme le montre l'exemple ci-dessus, l'attribut sequenceNumber est retourné dans un objet java.lang.Long object, attendu par l'API Loader, ce qui implique que la personne qui a écrit l'API soit a écrit l'implémentation EmployeeOptimisticCallbackImpl, soit a collaboré étroitement avec celle qui a implémenté EmployeeOptimisticCallbackImpl, notamment en se mettant d'accord sur la valeur retournée par la méthode getVersionedObjectForValue. Le plug-in OptimisticCallback par défaut retourne la valeur spéciale NULL_OPTIMISTIC_VERSION en tant qu'objet version.
public void updateVersionedObjectForValue(Object value)
{
if ( value != null )
{
Employee emp = (Employee) value;
long next = emp.getSequenceNumber() + 1;
emp.updateSequenceNumber( next );
}
}
Comme le montre l'exemple ci-dessus, l'attribut sequenceNumber s'incrémente de un afin que, lors du prochain appel de la méthode getVersionedObjectForValue, la valeur java.lang.Long qui est retournée soit une valeur de type long, égale à celle du numéro de séquence d'origine. Plus un, par exemple, sera la version suivante de cette instance d'Employee. Il ressort de cet exemple que la personne qui a écrit l'API Loader soit a écrit l'implémentation EmployeeOptimisticCallbackImpl, soit a collaboré étroitement avec celle qui a implémenté EmployeeOptimisticCallbackImpl.
Cette méthode écrit dans le flux spécifié la valeur versionnée. Selon l'implémentation, la valeur versionnée peut être utilisée pour identifier les collisions de mises à jour optimistes. Dans certaines implémentations, la valeur versionnée est une copie de la valeur d'origine. D'autres implémentations peuvent avoir un numéro de séquence ou un autre objet pur indiquer la version de la valeur. Comme l'implémentation effective est inconnue, cette méthode est fournie pour effectuer la sérialisation appropriée. L'implémentation par défaut appelle la méthode writeObject.
Cette méthode prend la version sérialisée de la valeur versionnée et elle retourne l'objet effectif de la valeur versionnée. Selon l'implémentation, la valeur versionnée peut être utilisée pour identifier les collisions de mises à jour optimistes. Dans certaines implémentations, la valeur versionnée est une copie de la valeur d'origine. D'autres implémentations peuvent avoir un numéro de séquence ou un autre objet pur indiquer la version de la valeur. Comme l'implémentation effective est inconnue, cette méthode est fournie pour effectuer la désérialisation appropriée. L'implémentation par défaut appelle la méthode readObject.
Deux approches permettent d'ajouter un plug-in OptimisticCallback dans la configuration BackingMap : la configuration XML et la configuration par programmation.
import com.ibm.websphere.objectgrid.ObjectGridManagerFactory;
import com.ibm.websphere.objectgrid.ObjectGridManager;
import com.ibm.websphere.objectgrid.ObjectGrid;
import com.ibm.websphere.objectgrid.BackingMap;
ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
ObjectGrid og = ogManager.createObjectGrid( "grid1" );
BackingMap bm = dg.defineMap("employees");
EmployeeOptimisticCallbackImpl cb = new EmployeeOptimisticCallbackImpl();
bm.setOptimisticCallback( cb );
<?xml version="1.0" encoding="UTF-8"?>
<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
xmlns="http://ibm.com/ws/objectgrid/config">
<objectGrids>
<objectGrid name="grid1">
<backingMap name="employees" pluginCollectionRef="employees" lockStrategy="OPTIMISTIC" />
</objectGrid>
</objectGrids>
<backingMapPluginCollections>
<backingMapPluginCollection id="employees">
<bean id="OptimisticCallback" className="com.xyz.EmployeeOptimisticCallbackImpl" />
</backingMapPluginCollection>
</backingMapPluginCollections>
</objectGridConfig>