blob: 898c0b6d43bf1717cafe5372e49c66e3cfe7cd59 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
<<<<<<< Updated upstream
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
=======
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
>>>>>>> Stashed changes
* limitations under the License.
*/
package org.apache.jdo.tck.api.instancecallbacks;
import java.util.ArrayList;
import java.util.List;
import javax.jdo.JDOHelper;
import javax.jdo.listener.AttachLifecycleListener;
import javax.jdo.listener.ClearLifecycleListener;
import javax.jdo.listener.CreateLifecycleListener;
import javax.jdo.listener.DeleteLifecycleListener;
import javax.jdo.listener.DetachLifecycleListener;
import javax.jdo.listener.DirtyLifecycleListener;
import javax.jdo.listener.InstanceLifecycleEvent;
import javax.jdo.listener.LoadLifecycleListener;
import javax.jdo.listener.StoreLifecycleListener;
import org.apache.jdo.tck.JDO_Test;
/**
* <B>Title:</B> Abstract test AbstractInstanceLifecycleListener <br>
* <B>Keywords:</B> LifeCycleListener lifecycle listener callback <br>
* <B>Assertion IDs:</B> A12.15-1, A12.15-2, A12.15-3, A12.15-4, A12.15-5, A12.15-6, A12.15-7,
* A12.15-8, A12.15-9, A12.15-10, A12.15-11, A12.15-12, A12.15-13, A12.15-14, <br>
* <B>Assertion Description: </B> A12.15-1 void postCreate(InstanceLifecycleEvent event); This
* method is called whenever a persistent instance is created, during makePersistent. It is called
* after the instance transitions to persistent-new. A12.15-2 void postLoad(InstanceLifecycleEvent
* event); This method is called whenever a persistent instance is loaded. It is called after the
* jdoPostLoad method is invoked on the instance. A12.15-3 void preStore(InstanceLifecycleEvent
* event); This method is called whenever a persistent instance is stored, for example during flush
* or commit. It is called before the jdoPreStore method is invoked on the instance. A12.15-4 void
* postStore(InstanceLifecycleEvent event); This method is called whenever a persistent instance is
* stored, for example during flush or commit. It is called after the jdoPreStore method is invoked
* on the instance. An object identity for a per?sistent-new instance must have been assigned to the
* instance when this callback is invoked. A12.15-5 void preClear(InstanceLifecycleEvent event);
* This method is called whenever a persistent instance is cleared, for example during
* afterCompletion. It is called before the jdoPreClear method is invoked on the instance. A12.15-6
* void postClear(InstanceLifecycleEvent event); This method is called whenever a persistent
* instance is cleared, for example during afterCom?pletion. It is called after the jdoPreClear
* method is invoked on the instance and the fields have been cleared by the JDO implementation.
* A12.15-7 void preDelete(InstanceLifecycleEvent event); This method is called whenever a
* persistent instance is deleted, during deletePersistent. It is called before the state transition
* and before the jdoPreDelete method is invoked on the instance. A12.15-8 void
* postDelete(InstanceLifecycleEvent event); This method is called whenever a persistent instance is
* deleted, during deletePersistent. It is called after the jdoPreDelete method is invoked on the
* instance and after the state transition. A12.15-9 void preDirty(InstanceLifecycleEvent event);
* This method is called whenever a persistent clean instance is first made dirty, during an
* operation that modifies the value of a persistent or transactional field. It is called before the
* field value is changed. A12.15-10 void postDirty(InstanceLifecycleEvent event); This method is
* called whenever a persistent clean instance is first made dirty, during an operation that
* modifies the value of a persistent or transactional field. It is called after the field value was
* changed. A12.15-11 void preDetach(InstanceLifecycleEvent event); This method is called before a
* persistent instance is copied for detachment. A12.15-12 void postDetach(InstanceLifecycleEvent
* event); This method is called whenever a persistent instance is copied for detachment. The source
* instance is the detached copy; the target instance is the persistent instance. A12.15-13 void
* preAttach(InstanceLifecycleEvent event); This method is called before a detached instance is
* attached. The source instance is the detached instance]. A12.15-14 void
* postAttach(InstanceLifecycleEvent event); This method is called after a detached instance is
* attached. The source instance is the corresponding persistent instance in the cache; the target
* instance is the detached instance.
*
* <p>This is the abstract base class for the lifecycle listener test classes. It contains
* constants, variables, and methods used by each listener test class. This class implements the
* setup and teardown methods used by each concrete test class.
*
* <p>This class also includes the listener base class that is extended by each specific listener.
*
* <p>The strategy of each test case is the same. A specific listener is implemented that responds
* only to events for that specific test; a specific persistence-capable class is also implemented,
* that responds only to callbacks for the specific test. A sequence of operations that stimulates
* the callbacks is executed. During these operations, listener events and callbacks are collected
* by the listener instance. Finally, the actual events and callbacks that were collected are
* analyzed and differences are reported.
*/
public abstract class AbstractInstanceLifecycleListener extends JDO_Test {
/** */
protected static final String ASSERTION1_FAILED =
"Assertion A12.15-1 (TestInstanceLifecycleListenerCreate) failed: ";
protected static final String ASSERTION2_FAILED =
"Assertion A12.15-2 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION3_FAILED =
"Assertion A12.15-3 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION4_FAILED =
"Assertion A12.15-4 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION5_FAILED =
"Assertion A12.15-5 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION6_FAILED =
"Assertion A12.15-6 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION7_FAILED =
"Assertion A12.15-7 (TestInstanceLifecycleListenerDelete) failed: ";
protected static final String ASSERTION8_FAILED =
"Assertion A12.15-8 (TestInstanceLifecycleListenerDelete) failed: ";
protected static final String ASSERTION9_FAILED =
"Assertion A12.15-9 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION10_FAILED =
"Assertion A12.15-10 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION11_FAILED =
"Assertion A12.15-11 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION12_FAILED =
"Assertion A12.15-12 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION13_FAILED =
"Assertion A12.15-13 (TestInstanceLifecycleListener) failed: ";
protected static final String ASSERTION14_FAILED =
"Assertion A12.15-14 (TestInstanceLifecycleListener) failed: ";
/**
* The listener to be used for the test. This method is implemented by the subclasses to use the
* proper listener.
*
* @return listener
*/
protected abstract InstanceLifecycleListenerImpl getListener();
/**
* The classes to be used for the test. This method is implemented by the subclasses to use the
* proper classes. The classes returned by this method are used for two purposes: they are used to
* register listeners; and they are used as the teardown classes whose instances are removed from
* the datastore at the end of the test.
*
* @return classes
*/
protected abstract Class<?>[] getPersistentClasses();
/** Register a new InstanceLifecycleListenerImpl with the PersistenceManager. */
protected void addListener() {
getPM();
pm.addInstanceLifecycleListener(getListener(), getPersistentClasses());
}
/** Unregister the InstanceLifecycleListenerImpl with the PersistenceManager. */
protected void removeListener() {
getPM();
pm.removeInstanceLifecycleListener(getListener());
}
/** Set up for lifecycle tests: Register the LifecycleListener; add PCPoint to tearDownClasses. */
@Override
protected void localSetUp() {
addListener();
addTearDownClass(getPersistentClasses());
}
/** Clean up after lifecycle tests: Unregister the LifecycleListener. */
@Override
protected void localTearDown() {
removeListener(); // no callbacks for teardown
super.localTearDown();
}
/**
* The LifeCycleListener to be registered with the PersistenceManager. This is the base class that
* is extended by each test.
*/
protected abstract static class InstanceLifecycleListenerImpl
implements AttachLifecycleListener,
ClearLifecycleListener,
CreateLifecycleListener,
DeleteLifecycleListener,
DetachLifecycleListener,
DirtyLifecycleListener,
LoadLifecycleListener,
StoreLifecycleListener {
protected InstanceLifecycleListenerImpl() {}
protected Object expectedSource = null;
protected Object expectedTarget = null;
public void setExpectedSource(Object source) {
expectedSource = source;
}
public void setExpectedTarget(Object target) {
expectedTarget = target;
}
/**
* This is the list names of locations for listener events and callbacks. Each instance of an
* event or callback has a specific name that is associated with the value. The values are used
* during collection of events and both names and values are used for reporting results.
*/
private static final List<String> locations = new ArrayList<>();
/**
* These are indexes into the sequence array. Each index represents the position in the sequence
* array for the corresponding callback or listener event.
*/
public static final int PRE_ATTACH_CALLBACK;
public static final int POST_ATTACH_CALLBACK;
public static final int PRE_ATTACH_LISTENER;
public static final int POST_ATTACH_LISTENER;
public static final int PRE_CLEAR_CALLBACK;
public static final int PRE_CLEAR_LISTENER;
public static final int POST_CLEAR_LISTENER;
public static final int POST_CREATE_LISTENER;
public static final int PRE_DELETE_CALLBACK;
public static final int PRE_DELETE_LISTENER;
public static final int POST_DELETE_LISTENER;
public static final int PRE_DETACH_CALLBACK;
public static final int POST_DETACH_CALLBACK;
public static final int PRE_DETACH_LISTENER;
public static final int POST_DETACH_LISTENER;
public static final int PRE_DIRTY_LISTENER;
public static final int POST_DIRTY_LISTENER;
public static final int POST_LOAD_CALLBACK;
public static final int POST_LOAD_LISTENER;
public static final int PRE_STORE_CALLBACK;
public static final int PRE_STORE_LISTENER;
public static final int POST_STORE_LISTENER;
/*
* Initialize the list of names and the associated values. For each
* listener event and callback, add the name and then assign the value.
*/
static {
int index = 0;
locations.add("PRE_ATTACH_LISTENER");
PRE_ATTACH_LISTENER = index++;
locations.add("PRE_ATTACH_CALLBACK");
PRE_ATTACH_CALLBACK = index++;
locations.add("POST_ATTACH_CALLBACK");
POST_ATTACH_CALLBACK = index++;
locations.add("POST_ATTACH_LISTENER");
POST_ATTACH_LISTENER = index++;
locations.add("PRE_CLEAR_LISTENER");
PRE_CLEAR_LISTENER = index++;
locations.add("PRE_CLEAR_CALLBACK");
PRE_CLEAR_CALLBACK = index++;
locations.add("POST_CLEAR_LISTENER");
POST_CLEAR_LISTENER = index++;
locations.add("POST_CREATE_LISTENER");
POST_CREATE_LISTENER = index++;
locations.add("PRE_DELETE_LISTENER");
PRE_DELETE_LISTENER = index++;
locations.add("PRE_DELETE_CALLBACK");
PRE_DELETE_CALLBACK = index++;
locations.add("POST_DELETE_LISTENER");
POST_DELETE_LISTENER = index++;
locations.add("POST_DETACH_CALLBACK");
POST_DETACH_CALLBACK = index++;
locations.add("PRE_DETACH_LISTENER");
PRE_DETACH_LISTENER = index++;
locations.add("PRE_DETACH_CALLBACK");
PRE_DETACH_CALLBACK = index++;
locations.add("POST_DETACH_LISTENER");
POST_DETACH_LISTENER = index++;
locations.add("PRE_DIRTY_LISTENER");
PRE_DIRTY_LISTENER = index++;
locations.add("POST_DIRTY_LISTENER");
POST_DIRTY_LISTENER = index++;
locations.add("POST_LOAD_CALLBACK");
POST_LOAD_CALLBACK = index++;
locations.add("POST_LOAD_LISTENER");
POST_LOAD_LISTENER = index++;
locations.add("PRE_STORE_LISTENER");
PRE_STORE_LISTENER = index++;
locations.add("PRE_STORE_CALLBACK");
PRE_STORE_CALLBACK = index++;
locations.add("POST_STORE_LISTENER");
POST_STORE_LISTENER = index++;
}
private final int[] actual = new int[locations.size()];
/** Track the current sequence of callbacks. */
private int current = 0;
public void notifyEvent(int event) {
actual[event] = ++current;
}
/**
* Initialize the expected ordering of callbacks and listeners. Each entry in the sequence is
* one of the PRE_ or POST_XXX_LISTENER or _CALLBACK above. The order in the sequence is the
* expected calling order.
*/
private static int[] newExpected(int[] sequence) {
int order = 0;
int[] result = new int[locations.size()];
for (int j : sequence) {
result[j] = ++order;
}
return result;
}
/** The error message buffer to report exceptions. */
protected final StringBuffer messages = new StringBuffer();
protected void checkEventType(String where, int expected, int actual) {
if (expected != actual) {
messages.append(
where
+ "wrong event type: "
+ "expected <"
+ expected
+ ">, actual <"
+ actual
+ ">\n");
}
}
protected void checkEventSource(String where, Object eventSource) {
if (expectedSource != eventSource) {
messages.append(
where
+ "wrong event source: "
+ "expected <"
+ expectedSource
+ ">, actual <"
+ eventSource
+ ">\n");
}
}
protected void checkEventTarget(String where, Object eventTarget) {
if (expectedTarget != eventTarget) {
messages.append(
where
+ "wrong event target: "
+ "expected <"
+ expectedTarget
+ ">, actual <"
+ eventTarget
+ ">\n");
}
}
protected void checkTrue(String where, boolean condition) {
if (!condition) {
messages.append(where + "was not true.\n");
}
}
protected void checkSame(String where, Object expected, Object actual) {
if (expected != actual) {
messages.append(where + "expected <" + expected + ">, actual <" + actual + ">\n");
}
}
protected void checkPersistent(String where, Object obj) {
if (!JDOHelper.isPersistent(obj)) {
messages.append(where + "object should be persistent.\n");
}
}
protected void checkNotPersistent(String where, Object obj) {
if (JDOHelper.isPersistent(obj)) {
messages.append(where + "object should not be persistent.\n");
}
}
protected void checkDirty(String where, Object obj) {
if (!JDOHelper.isDirty(obj)) {
messages.append(where + "object should be dirty.\n");
}
}
protected void checkNotDirty(String where, Object obj) {
if (JDOHelper.isDirty(obj)) {
messages.append(where + "object should not be dirty.\n");
}
}
protected void checkNew(String where, Object obj) {
if (!JDOHelper.isNew(obj)) {
messages.append(where + "object should be new.\n");
}
}
protected void checkNotNew(String where, Object obj) {
if (JDOHelper.isNew(obj)) {
messages.append(where + "object should not be new.\n");
}
}
protected void checkDeleted(String where, Object obj) {
if (!JDOHelper.isDeleted(obj)) {
messages.append(where + "object should be deleted.\n");
}
}
protected void checkNotDeleted(String where, Object obj) {
if (JDOHelper.isDeleted(obj)) {
messages.append(where + "object should not be deleted.\n");
}
}
/**
* Verify the actual sequence of callbacks and listeners against the expected. Each of the
* expected and actual are int arrays in which each listener and callback have one position in
* the array and the value of the array at that position is the order, starting with 1, of the
* callback. If the callback or listener was never invoked, the value is 0.
*
* @param where where
* @param expected expected
*/
public void verifyCallbacks(String where, int[] expected) {
int[] expectedSequence = newExpected(expected);
for (int index = 0; index < locations.size(); ++index) {
if (expectedSequence[index] != actual[index]) {
messages.append(
"\nSequence verification failed for "
+ locations.get(index)
+ "; expected: <"
+ expectedSequence[index]
+ "> actual: <"
+ actual[index]
+ ">\n");
}
}
if (messages.length() > 0) {
fail(where + "\n" + messages);
}
}
public void postAttach(InstanceLifecycleEvent event) {}
public void postClear(InstanceLifecycleEvent event) {}
public void postCreate(InstanceLifecycleEvent event) {}
public void postDelete(InstanceLifecycleEvent event) {}
public void postDetach(InstanceLifecycleEvent event) {}
public void postDirty(InstanceLifecycleEvent event) {}
public void postLoad(InstanceLifecycleEvent event) {}
public void postStore(InstanceLifecycleEvent event) {}
public void preAttach(InstanceLifecycleEvent event) {}
public void preClear(InstanceLifecycleEvent event) {}
public void preDelete(InstanceLifecycleEvent event) {}
public void preDetach(InstanceLifecycleEvent event) {}
public void preDirty(InstanceLifecycleEvent event) {}
public void preStore(InstanceLifecycleEvent event) {}
}
}