blob: ff68440179ed214954da5aa0a3f2988c5fd12137 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 12/14/2017-3.0 Tomas Kraus
// - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
package org.eclipse.persistence.descriptors;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReferenceArray;
import org.eclipse.persistence.core.descriptors.CoreDescriptorEventManager;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.sessions.SessionProfiler;
/**
* <p><b>Purpose</b>: The event manager allows for a descriptor to specify that
* an object should be notified when a EclipseLink event occurs. It also determines
* how the object will be notified. To specify an event a method name can be
* registered to be called on the object when the event occurs. Events can be
* used to extend the EclipseLink reading and writing behavior.
* <p>
* These events include:
* <ul>
* <li> pre/postWrite - occurs when an object is written (occurs even if no changes to the object).
* <li> pre/postInsert - occurs when an object is inserted.
* <li> pre/postUpdate - occurs when an object is updated (occurs even if no changes to the object).
* <li> pre/postDeleted - occurs when an object is deleted.
* <li> postBuild/postRefresh - occurs after a object has been built/refreshed from its database row.
* <li> aboutTo/Insert/Update - occurs when an object is about to be inserted/update allows for row modification.
* <li> postClone - occurs when an object is registered/cloned in a unit of work.
* <li> postMerge - occurs when an object is merged with its original in a unit of work.
* </ul>
*
* @see ClassDescriptor
*/
public class DescriptorEventManager extends CoreDescriptorEventManager<DescriptorEvent> implements Cloneable, Serializable {
protected ClassDescriptor descriptor;
protected AtomicReferenceArray<String> eventSelectors;
protected transient AtomicReferenceArray<Method> eventMethods;
protected transient List<DescriptorEventListener> eventListeners;
// EJB 3.0 support for event listeners.
protected transient List<DescriptorEventListener> defaultEventListeners;
protected transient List<DescriptorEventListener> entityListenerEventListeners;
protected transient DescriptorEventListener entityEventListener;
/**
* Listeners that are fired after all other listeners are fired
*/
protected transient List<DescriptorEventListener> internalListeners = new ArrayList<>();
// EJB 3.0 support - cache our parent event managers.
protected transient List<DescriptorEventManager> entityEventManagers;
protected transient List<DescriptorEventManager> entityListenerEventManagers;
// EJB 3.0 support for event listener configuration flags.
protected boolean excludeDefaultListeners;
protected boolean excludeSuperclassListeners;
//JPA project caching support. Holds DescriptorEventListener representations for serialization/storage.
protected List<SerializableDescriptorEventHolder> descriptorEventHolders;
/** PERF: Cache if any events listener exist. */
protected boolean hasAnyEventListeners;
public static final int PreWriteEvent = 0;
public static final int PostWriteEvent = 1;
public static final int PreDeleteEvent = 2;
public static final int PostDeleteEvent = 3;
public static final int PreInsertEvent = 4;
public static final int PostInsertEvent = 5;
public static final int PreUpdateEvent = 6;
public static final int PostUpdateEvent = 7;
public static final int PostBuildEvent = 8;
public static final int PostRefreshEvent = 9;
public static final int PostCloneEvent = 10;
public static final int PostMergeEvent = 11;
public static final int AboutToInsertEvent = 12;
public static final int AboutToUpdateEvent = 13;
// CR#2660080 was missing aboutToDelete
public static final int AboutToDeleteEvent = 14;
// EJB 3.0 events
public static final int PrePersistEvent = 15;
public static final int PreRemoveEvent = 16;
public static final int PreUpdateWithChangesEvent = 17;
protected static final int NumberOfEvents = 18;
/**
* INTERNAL:
* Returns a new DescriptorEventManager for the specified ClassDescriptor.
*/
public DescriptorEventManager() {
this.eventSelectors = newAtomicReferenceArray(NumberOfEvents);
this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
this.hasAnyEventListeners = false;
this.excludeDefaultListeners = false;
this.excludeSuperclassListeners = false;
}
/**
* PUBLIC:
* EJB 3.0 support for default listeners.
*/
public void addDefaultEventListener(DescriptorEventListener listener) {
getDefaultEventListeners().add(listener);
}
/**
* PUBLIC:
* EJB 3.0 support for lifecycle callback events defined on an entity
* listener class.
*/
public void addEntityListenerEventListener(DescriptorEventListener listener) {
getEntityListenerEventListeners().add(listener);
}
/**
* PUBLIC:
* Listener objects can be registered with the event manager to be notified
* when an event occurs on any instance of the descriptor's class.
*/
public void addListener(DescriptorEventListener listener) {
getEventListeners().add(listener);
setHasAnyEventListeners(true);
}
/**
* INTERNAL:
*
*/
public void addInternalListener(DescriptorEventListener listener) {
if (internalListeners==null) {
internalListeners = new ArrayList<>();
}
internalListeners.add(listener);
setHasAnyEventListeners(true); // ensure that events are generated
}
/**
* INTERNAL:
*
*/
public void addEntityListenerHolder(SerializableDescriptorEventHolder holder) {
this.getDescriptorEventHolders().add(holder);
}
/**
* INTERNAL:
* Clone the manager and its private parts.
*/
@Override
public Object clone() {
try {
DescriptorEventManager clone = (DescriptorEventManager)super.clone();
clone.setEventSelectors(newAtomicReferenceArray(getEventSelectors()));
clone.setEventMethods(newAtomicReferenceArray(getEventMethods()));
clone.setEventListeners(getEventListeners());
return clone;
} catch (Exception exception) {
throw new AssertionError(exception);
}
}
/**
* INTERNAL:
* This method was added to allow JPA project caching so that DescriptorEventListeners could be
* serialized and re-added to the EventManager using a SerializableDescriptorEventHolder.
*/
public void processDescriptorEventHolders(AbstractSession session, ClassLoader classLoader) {
if (this.descriptorEventHolders != null) {
for (SerializableDescriptorEventHolder holder: descriptorEventHolders) {
holder.addListenerToEventManager(getDescriptor(), session, classLoader);
}
}
}
/**
* INTERNAL:
* EJB 3.0 support. Returns true if this event manager should exclude the
* invocation of the default listeners for this descriptor.
*/
public boolean excludeDefaultListeners() {
return excludeDefaultListeners;
}
/**
* INTERNAL:
* EJB 3.0 support. Returns true is this event manager should exclude the
* invocation of the listeners defined by the entity listener classes for
* the superclasses of this descriptor.
*/
public boolean excludeSuperclassListeners() {
return excludeSuperclassListeners;
}
/**
* INTERNAL:
* Execute the given selector with the event as argument.
* @exception DescriptorException - the method cannot be found or executed
*/
@Override
public void executeEvent(DescriptorEvent event) throws DescriptorException {
try {
event.getSession().startOperationProfile(SessionProfiler.DescriptorEvent);
// CR#3467758, ensure the descriptor is set on the event.
event.setDescriptor(getDescriptor());
notifyListeners(event);
notifyEJB30Listeners(event);
if (event.getSource() instanceof DescriptorEventListener) {
// Allow the object itself to implement the interface.
notifyListener((DescriptorEventListener)event.getSource(), event);
return;
}
Method eventMethod = getEventMethods().get(event.getEventCode());
if (eventMethod == null) {
return;
}
// Now that I have the method, I need to invoke it
try {
Object[] runtimeParameters = new Object[1];
runtimeParameters[0] = event;
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
AccessController.doPrivileged(new PrivilegedMethodInvoker(eventMethod, event.getSource(), runtimeParameters));
} catch (PrivilegedActionException exception) {
Exception throwableException = exception.getException();
if (throwableException instanceof IllegalAccessException) {
throw DescriptorException.illegalAccessWhileEventExecution(eventMethod.getName(), getDescriptor(), throwableException);
} else {
throw DescriptorException.targetInvocationWhileEventExecution(eventMethod.getName(), getDescriptor(), throwableException);
}
}
} else {
PrivilegedAccessHelper.invokeMethod(eventMethod, event.getSource(), runtimeParameters);
}
} catch (IllegalAccessException exception) {
throw DescriptorException.illegalAccessWhileEventExecution(eventMethod.getName(), getDescriptor(), exception);
} catch (IllegalArgumentException exception) {
throw DescriptorException.illegalArgumentWhileObsoleteEventExecute(eventMethod.getName(), getDescriptor(), exception);
} catch (InvocationTargetException exception) {
throw DescriptorException.targetInvocationWhileEventExecution(eventMethod.getName(), getDescriptor(), exception);
}
} finally {
event.getSession().endOperationProfile(SessionProfiler.DescriptorEvent);
}
}
/**
* Find the method corresponding to the event selector. The method MUST take
* DescriptorEvent as argument, Session is also supported as argument for
* backward compatibility.
*/
protected Method findMethod(int selector) throws DescriptorException {
Class[] declarationParameters = new Class[1];
declarationParameters[0] = ClassConstants.DescriptorEvent_Class;
String methodName = getEventSelectors().get(selector);
try {
return Helper.getDeclaredMethod(getDescriptor().getJavaClass(), methodName, declarationParameters);
} catch (NoSuchMethodException exception) {
throw DescriptorException.noSuchMethodOnFindObsoleteMethod(methodName, getDescriptor(), exception);
} catch (SecurityException exception) {
throw DescriptorException.securityOnFindMethod(methodName, getDescriptor(), exception);
}
}
/**
* INTERNAL:
* bug 251180 - Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
*/
public String getAboutToDeleteSelector() {
return getEventSelectors().get(AboutToDeleteEvent);
}
/**
* INTERNAL:
*/
public String getAboutToInsertSelector() {
return getEventSelectors().get(AboutToInsertEvent);
}
/**
* INTERNAL:
*/
public String getAboutToUpdateSelector() {
return getEventSelectors().get(AboutToUpdateEvent);
}
/**
* INTERNAL:
* EJB 3.0 support. Returns the default listeners.
*/
public List<DescriptorEventListener> getDefaultEventListeners() {
if (defaultEventListeners == null) {
defaultEventListeners = new CopyOnWriteArrayList<>();
}
return defaultEventListeners;
}
/**
* INTERNAL:
*/
protected ClassDescriptor getDescriptor() {
return descriptor;
}
/**
* INTERNAL:
* used by JPA project caching to store DescriptorEventListener representations that can build the underlying
* DescriptorEventListener and add it to the EventManager.
*/
public List<SerializableDescriptorEventHolder> getDescriptorEventHolders() {
if (descriptorEventHolders == null) {
descriptorEventHolders = new CopyOnWriteArrayList<>();
}
return descriptorEventHolders;
}
/**
* INTERNAL:
* used by JPA project caching to store DescriptorEventListener representations that can build the underlying
* DescriptorEventListener and add it to the EventManager.
*/
public void setDescriptorEventHolders(List<SerializableDescriptorEventHolder> descriptorEventHolders) {
this.descriptorEventHolders = descriptorEventHolders;
}
/**
* INTERNAL:
* EJB 3.0 support. Returns the entity event listener.
*/
public DescriptorEventListener getEntityEventListener() {
return entityEventListener;
}
/**
* INTERNAL:
* EJB 3.0 support. Returns the entity listener event listeners.
*/
public List<DescriptorEventListener> getEntityListenerEventListeners() {
if (entityListenerEventListeners == null) {
entityListenerEventListeners = new CopyOnWriteArrayList<>();
}
return entityListenerEventListeners;
}
/**
* PUBLIC:
* Returns the Listener objects that have been added.
*
* @see #addListener(DescriptorEventListener)
*/
public List<DescriptorEventListener> getEventListeners() {
// Lazy initialize to avoid unnecessary enumerations.
if (eventListeners == null) {
eventListeners = new CopyOnWriteArrayList<>();
}
return eventListeners;
}
protected AtomicReferenceArray<Method> getEventMethods() {
//Lazy Initialized to prevent Null Pointer exception after serialization
if (this.eventMethods == null) {
this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
}
return eventMethods;
}
protected AtomicReferenceArray<String> getEventSelectors() {
if (this.eventSelectors == null) {
this.eventSelectors = newAtomicReferenceArray(NumberOfEvents);
}
return eventSelectors;
}
/**
* PUBLIC:
* The name of the method called after an object is built
*/
public String getPostBuildSelector() {
return getEventSelectors().get(PostBuildEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is cloned
*/
public String getPostCloneSelector() {
return getEventSelectors().get(PostCloneEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is deleted
*/
public String getPostDeleteSelector() {
return getEventSelectors().get(PostDeleteEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is inserted
*/
public String getPostInsertSelector() {
return getEventSelectors().get(PostInsertEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is merged
*/
public String getPostMergeSelector() {
return getEventSelectors().get(PostMergeEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is refreshed
*/
public String getPostRefreshSelector() {
return getEventSelectors().get(PostRefreshEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is updated
*/
public String getPostUpdateSelector() {
return getEventSelectors().get(PostUpdateEvent);
}
/**
* PUBLIC:
* The name of the method called after an object is written
*/
public String getPostWriteSelector() {
return getEventSelectors().get(PostWriteEvent);
}
/**
* PUBLIC:
* The name of the method called before the create operation is applied to an object
*/
public String getPrePersistSelector() {
return getEventSelectors().get(PrePersistEvent);
}
/**
* PUBLIC:
* The name of the method called before an object is deleted
*/
public String getPreDeleteSelector() {
return getEventSelectors().get(PreDeleteEvent);
}
/**
* PUBLIC:
* The name of the method called before an object is inserted
*/
public String getPreInsertSelector() {
return getEventSelectors().get(PreInsertEvent);
}
/**
* PUBLIC:
* The name of the method called before the remove operation is applied to an object
*/
public String getPreRemoveSelector() {
return getEventSelectors().get(PreRemoveEvent);
}
/**
* PUBLIC:
* The name of the method called before an object is updated
*/
public String getPreUpdateSelector() {
return getEventSelectors().get(PreUpdateEvent);
}
/**
* PUBLIC:
* The name of the method called before an object is written
*/
public String getPreWriteSelector() {
return getEventSelectors().get(PreWriteEvent);
}
/**
* INTERNAL:
* Return if the event manager has any event listeners, or event methods.
* If nothing is listening to event they can be avoided.
*/
@Override
public boolean hasAnyEventListeners() {
// Check listeners in case of collection added to directly as occurs
// for aggregates that have a clone of the event manager but not the
// listeners.
return hasAnyEventListeners || hasAnyListeners();
}
protected boolean hasAnyListeners() {
return (eventListeners != null) && (!eventListeners.isEmpty());
}
/**
* INTERNAL:
* This method will return true, if this event manager has default listeners
* and does not exclude them. Default listeners are always added to every
* event manager to allow users to turn them on a later time if so desired.
*/
public boolean hasDefaultEventListeners() {
return defaultEventListeners != null && ! defaultEventListeners.isEmpty() && ! excludeDefaultListeners;
}
/**
* INTERNAL:
* EJB 3.0 support. Return true if this event manager has any entity event
* listeners.
*/
public boolean hasEntityEventListener() {
return entityEventListener != null;
}
/**
* INTERNAL:
* Internal event support. Return true if this event manager has any internal
* listener event listeners.
*/
public boolean hasInternalEventListeners() {
return internalListeners != null && !internalListeners.isEmpty();
}
/**
* INTERNAL:
* EJB 3.0 support. Return true if this event manager has any entity
* listener event listeners.
*/
public boolean hasEntityListenerEventListeners() {
return entityListenerEventListeners != null && !entityListenerEventListeners.isEmpty();
}
/**
* INTERNAL:
* Configure inherited selectors.
*/
public void initialize(AbstractSession session) {
setHasAnyEventListeners(false);
// Initialize the EJB 3.0 supported listeners.
initializeEJB30EventManagers();
if (hasEntityEventListener() || hasEntityListenerEventListeners() || hasDefaultEventListeners() || hasInternalEventListeners()) {
setHasAnyEventListeners(true);
}
// Initialize if events are required at all.
if (hasAnyListeners() || DescriptorEventListener.class.isAssignableFrom(getDescriptor().getJavaClass())) {
setHasAnyEventListeners(true);
}
final AtomicReferenceArray<String> selectors = getEventSelectors();
for (int index = 0; index < NumberOfEvents; index++) {
if (selectors.get(index) != null) {
setHasAnyEventListeners(true);
getEventMethods().set(index, findMethod(index));
}
}
// Inherit all parent defined event method
// Do NOT inherit the listener as the events are broadcast to the parent.
if (getDescriptor().isChildDescriptor()) {
DescriptorEventManager parentEventManager = getDescriptor().getInheritancePolicy().getParentDescriptor().getEventManager();
if (parentEventManager.hasAnyEventListeners()) {
setHasAnyEventListeners(true);
}
for (int index = 0; index < NumberOfEvents; index++) {
if ((selectors.get(index) == null) && (parentEventManager.getEventSelectors().get(index) != null)) {
setHasAnyEventListeners(true);
selectors.set(index, parentEventManager.getEventSelectors().get(index));
getEventMethods().set(index, parentEventManager.getEventMethods().get(index));
}
}
}
}
/**
* INTERNAL:
* EJB 3.0 support. Builds our chains of descriptor event managers that will
* need to be notified. The chains are cache so we only need to build them
* once.
*/
protected void initializeEJB30EventManagers() {
entityEventManagers = new CopyOnWriteArrayList<>();
entityListenerEventManagers = new CopyOnWriteArrayList<>();
if (hasEntityEventListener()) {
entityEventManagers.add(this);
}
if (hasEntityListenerEventListeners()) {
entityListenerEventManagers.add(this);
}
ClassDescriptor currentDescriptor = getDescriptor();
boolean excludeEntityListeners = excludeSuperclassListeners();
while (currentDescriptor.isChildDescriptor()) {
currentDescriptor = currentDescriptor.getInheritancePolicy().getParentDescriptor();
DescriptorEventManager eventManager = currentDescriptor.getEventManager();
if (eventManager.hasEntityEventListener()) {
entityEventManagers.add(eventManager);
}
if (eventManager.hasEntityListenerEventListeners()) {
if (!excludeEntityListeners) {
entityListenerEventManagers.add(eventManager);
}
}
excludeEntityListeners = eventManager.excludeSuperclassListeners();
}
}
/**
* INTERNAL:
* Notify the EJB 3.0 event listeners.
*/
protected void notifyEJB30Listeners(DescriptorEvent event) {
// Step 1 - notify our default listeners.
if (hasDefaultEventListeners()) {
for (int i = 0; i < getDefaultEventListeners().size(); i++) {
DescriptorEventListener listener = getDefaultEventListeners().get(i);
notifyListener(listener, event);
}
}
// Step 2 - Notify the Entity Listener's first, top -> down.
for (int index = entityListenerEventManagers.size() - 1; index >= 0; index--) {
List entityListenerEventListeners = entityListenerEventManagers.get(index).getEntityListenerEventListeners();
for (int i = 0; i < entityListenerEventListeners.size(); i++) {
DescriptorEventListener listener = (DescriptorEventListener) entityListenerEventListeners.get(i);
notifyListener(listener, event);
}
}
// Step 3 - Notify the Entity event listeners. top -> down, unless
// they are overridden in a subclass.
for (int index = entityEventManagers.size() - 1; index >= 0; index--) {
DescriptorEventListener entityEventListener = entityEventManagers.get(index).getEntityEventListener();
if (! entityEventListener.isOverriddenEvent(event, entityEventManagers)) {
notifyListener(entityEventListener, event);
}
}
// Step 4 - Notify internal listeners.
if (internalListeners != null) { // could be null after serialization
for (DescriptorEventListener listener : internalListeners) {
notifyListener(listener, event);
}
}
}
/**
* INTERNAL:
* Big ugly case statement to notify listeners.
*/
protected void notifyListener(DescriptorEventListener listener, DescriptorEvent event) throws DescriptorException {
switch (event.getEventCode()) {
case PreWriteEvent:
listener.preWrite(event);
break;
case PostWriteEvent:
listener.postWrite(event);
break;
case PreDeleteEvent:
listener.preDelete(event);
break;
case PostDeleteEvent:
listener.postDelete(event);
break;
case PreInsertEvent:
listener.preInsert(event);
break;
case PostInsertEvent:
listener.postInsert(event);
break;
case PreUpdateEvent:
listener.preUpdate(event);
break;
case PostUpdateEvent:
listener.postUpdate(event);
break;
case PostMergeEvent:
listener.postMerge(event);
break;
case PostCloneEvent:
listener.postClone(event);
break;
case PostBuildEvent:
listener.postBuild(event);
break;
case PostRefreshEvent:
listener.postRefresh(event);
break;
case AboutToInsertEvent:
listener.aboutToInsert(event);
break;
case AboutToUpdateEvent:
listener.aboutToUpdate(event);
break;
case AboutToDeleteEvent:
listener.aboutToDelete(event);
break;
case PrePersistEvent:
listener.prePersist(event);
break;
case PreRemoveEvent:
listener.preRemove(event);
break;
case PreUpdateWithChangesEvent:
listener.preUpdateWithChanges(event);
break;
default:
throw DescriptorException.invalidDescriptorEventCode(event, getDescriptor());
}
}
/**
* INTERNAL:
* Notify the event listeners.
*/
public void notifyListeners(DescriptorEvent event) {
if (hasAnyListeners()) {
for (int index = 0; index < getEventListeners().size(); index++) {
DescriptorEventListener listener = getEventListeners().get(index);
notifyListener(listener, event);
}
}
// Also must notify any inherited listeners.
if (getDescriptor().isChildDescriptor()) {
getDescriptor().getInheritancePolicy().getParentDescriptor().getEventManager().notifyListeners(event);
}
}
/**
* INTERNAL:
* Used to initialize a remote DescriptorEventManager.
*/
public void remoteInitialization(AbstractSession session) {
this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
initialize(session);
}
/**
* PUBLIC:
* Remove a event listener.
*/
public void removeListener(DescriptorEventListener listener) {
getEventListeners().remove(listener);
}
/**
* PUBLIC:
* A method can be registered to be called when an object's row it about to
* be inserted. This uses the optional event argument of the DatabaseRow.
* This is different from pre/postInsert because it occurs after the row has
* already been built. This event can be used to modify the row before
* insert, such as adding a user inserted by.
*/
//bug 251180: Missing method org.eclipse.persistence.descriptors.DescriptorEventManager#setAboutToDeleteSelector
public void setAboutToDeleteSelector(String aboutToDeleteSelector) {
getEventSelectors().set(AboutToDeleteEvent, aboutToDeleteSelector);
}
/**
* PUBLIC:
* A method can be registered to be called when an object's row it about to
* be inserted. This uses the optional event argument of the DatabaseRow.
* This is different from pre/postInsert because it occurs after the row has
* already been built. This event can be used to modify the row before
* insert, such as adding a user inserted by.
*/
public void setAboutToInsertSelector(String aboutToInsertSelector) {
getEventSelectors().set(AboutToInsertEvent, aboutToInsertSelector);
}
/**
* PUBLIC:
* A method can be registered to be called when an object's row it about to
* be updated. This uses the optional event argument of the DatabaseRow.
* This is different from pre/postUpdate because it occurs after the row has
* already been built, and it ONLY called if the update is required (changed
* within a unit of work), as the other occur ALWAYS. This event can be used
* to modify the row before insert, such as adding a user inserted by.
*/
public void setAboutToUpdateSelector(String aboutToUpdateSelector) {
getEventSelectors().set(AboutToUpdateEvent, aboutToUpdateSelector);
}
/**
* INTERNAL:
* Set the descriptor.
*/
public void setDescriptor(ClassDescriptor descriptor) {
this.descriptor = descriptor;
}
/**
* PUBLIC:
* EJB 3.0 support for lifecycle callback events defined on an entity class.
*/
public void setEntityEventListener(DescriptorEventListener listener) {
this.entityEventListener = listener;
}
protected void setEventListeners(List<DescriptorEventListener> eventListeners) {
if (eventListeners instanceof CopyOnWriteArrayList) {
this.eventListeners = eventListeners;
} else {
this.eventListeners = new CopyOnWriteArrayList(eventListeners);
}
}
protected void setEventMethods(AtomicReferenceArray<Method> eventMethods) {
this.eventMethods = eventMethods;
}
protected void setEventSelectors(AtomicReferenceArray<String> eventSelectors) {
this.eventSelectors = eventSelectors;
}
/**
* INTERNAL:
* EJB 3.0 support. Default listeners apply to all entities in a persistence
* unit. Set this flag to true to exclude the invocation of the default
* listeners for this descriptor.
*/
public void setExcludeDefaultListeners(boolean excludeDefaultListeners) {
this.excludeDefaultListeners = excludeDefaultListeners;
}
/**
* INTERNAL:
* EJB 3.0 support. If multiple entity classes in an inheritance hierarchy
* define entity listeners, the listeners defined for a superclass are
* invoked before the listeners defined for its subclasses. Set this flag
* to true to exclude the invocation of the listeners defined by the entity
* listener classes for the superclasses of this descriptor.
*/
public void setExcludeSuperclassListeners(boolean excludeSuperclassListeners) {
this.excludeSuperclassListeners = excludeSuperclassListeners;
}
/**
* INTERNAL:
* Set if the event manager has any event listeners, or event methods.
* If nothing is listening to event they can be avoided.
*/
protected void setHasAnyEventListeners(boolean hasAnyEventListeners) {
this.hasAnyEventListeners = hasAnyEventListeners;
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* built from the database. This uses the optional event argument for the
* DatabaseRow. This event can be used to correctly initialize an object's
* non-persistent attributes or to perform complex optimizations or
* mappings. This event is called whenever an object is built.
*/
public void setPostBuildSelector(String postBuildSelector) {
getEventSelectors().set(PostBuildEvent, postBuildSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* cloned into a unit of work. This uses the optional event argument for the
* original object (the source object is the clone). This event can be used
* to correctly initialize an object's non-persistent attributes.
*/
public void setPostCloneSelector(String postCloneSelector) {
getEventSelectors().set(PostCloneEvent, postCloneSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* deleted from the database. This event can notify/remove any dependents
* on the object.
*/
public void setPostDeleteSelector(String postDeleteSelector) {
getEventSelectors().set(PostDeleteEvent, postDeleteSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* inserted into the database. This event can be used to notify any
* dependent on the object, or to update information not accessible until
* the object has been inserted.
*/
public void setPostInsertSelector(String postInsertSelector) {
getEventSelectors().set(PostInsertEvent, postInsertSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* merge from a unit of work. This uses the optional event argument of the
* original object which is the object being merged from, the source object
* is the object being merged into. This event can be used to correctly
* initialize an object's non-persistent attributes.
*/
public void setPostMergeSelector(String postMergeSelector) {
getEventSelectors().set(PostMergeEvent, postMergeSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* refreshed from the database. This uses the optional event argument of
* the DatabaseRow. This event can be used to correctly initialize an
* object's non-persistent attributes or to perform complex optimizations or
* mappings. This event is only called on refreshes of existing objects.
*/
public void setPostRefreshSelector(String postRefreshSelector) {
getEventSelectors().set(PostRefreshEvent, postRefreshSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* updated into the database.
*/
public void setPostUpdateSelector(String postUpdateSelector) {
getEventSelectors().set(PostUpdateEvent, postUpdateSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that has just been
* written to the database. This event is raised on any registered object
* in a unit of work, even if it has not changed, refer to the
* "aboutToUpdate" selector if it is required for the event to be raised
* only when the object has been changed. This will be called on all inserts
* and updates, after the "postInsert/Update" event has been raised. This
* event can be used to notify any dependent on the object.
*/
public void setPostWriteSelector(String postWriteSelector) {
getEventSelectors().set(PostWriteEvent, postWriteSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that is going to be
* deleted from the database. This event can notify/remove any dependents
* on the object.
*/
public void setPreDeleteSelector(String preDeleteSelector) {
getEventSelectors().set(PreDeleteEvent, preDeleteSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that is going to be
* inserted into the database. This event can be used to notify any
* dependent on the object or acquire the object's id through a custom
* mechanism.
*/
public void setPreInsertSelector(String preInsertSelector) {
getEventSelectors().set(PreInsertEvent, preInsertSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object when that object has
* the create operation applied to it.
*/
public void setPrePersistSelector(String prePersistSelector) {
getEventSelectors().set(PrePersistEvent, prePersistSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object when that object has
* the remove operation applied to it.
*/
public void setPreRemoveSelector(String preRemoveSelector) {
getEventSelectors().set(PreRemoveEvent, preRemoveSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that is going to be
* updated into the database. This event is raised on any registered object
* in a unit of work, even if it has not changed, refer to the
* "aboutToUpdate" selector if it is required for the event to be raised
* only when the object has been changed. This event can be used to notify
* any dependent on the object.
*/
public void setPreUpdateSelector(String preUpdateSelector) {
getEventSelectors().set(PreUpdateEvent, preUpdateSelector);
}
/**
* PUBLIC:
* A method can be registered to be called on a object that is going to be
* written to the database. This event is raised on any registered object
* in a unit of work, even if it has not changed, refer to the
* "aboutToUpdate" selector if it is required for the event to be raised
* only when the object has been changed. This will be called on all inserts
* and updates, before the "preInsert/Update" event has been raised. This
* event can be used to notify any dependent on the object.
*/
public void setPreWriteSelector(String preWriteSelector) {
getEventSelectors().set(PreWriteEvent, preWriteSelector);
}
/**
* Create an instance of {@link java.util.concurrent.atomic.AtomicIntegerArray} initialized with {@code NullEvent} values.
*
* @param length length of the array.
* @return initialized instance of {@link java.util.concurrent.atomic.AtomicIntegerArray}
*/
private static <T> AtomicReferenceArray<T> newAtomicReferenceArray(final int length) {
final AtomicReferenceArray array = new AtomicReferenceArray<>(length);
for (int index = 0; index < length; array.set(index++, null));
return array;
}
/**
* Create an instance of {@link java.util.concurrent.atomic.AtomicIntegerArray} initialized with content of provided array.
*
* @param src source array.
* @return initialized instance of {@link java.util.concurrent.atomic.AtomicIntegerArray}
*/
private static <T> AtomicReferenceArray<T> newAtomicReferenceArray(final AtomicReferenceArray<T> src) {
final int length = src.length();
final AtomicReferenceArray array = new AtomicReferenceArray<>(length);
for (int index = 0; index < length; array.set(index, src.get(index++)));
return array;
}
}