org.eclipse.persistence.descriptors.DescriptorEventManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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.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.sessions.AbstractSession;
import org.eclipse.persistence.sessions.SessionProfiler;
/**
* Purpose: 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.
*
* These events include:
*
* - pre/postWrite - occurs when an object is written (occurs even if no changes to the object).
*
- pre/postInsert - occurs when an object is inserted.
*
- pre/postUpdate - occurs when an object is updated (occurs even if no changes to the object).
*
- pre/postDeleted - occurs when an object is deleted.
*
- postBuild/postRefresh - occurs after a object has been built/refreshed from its database row.
*
- aboutTo/Insert/Update - occurs when an object is about to be inserted/update allows for row modification.
*
- postClone - occurs when an object is registered/cloned in a unit of work.
*
- postMerge - occurs when an object is merged with its original in a unit of work.
*
*
* @see ClassDescriptor
*/
public class DescriptorEventManager extends CoreDescriptorEventManager implements Cloneable, Serializable {
protected ClassDescriptor descriptor;
protected AtomicReferenceArray eventSelectors;
protected transient AtomicReferenceArray eventMethods;
protected transient List eventListeners;
// EJB 3.0 support for event listeners.
protected transient List defaultEventListeners;
protected transient List entityListenerEventListeners;
protected transient DescriptorEventListener entityEventListener;
/**
* Listeners that are fired after all other listeners are fired
*/
protected transient List internalListeners = new ArrayList<>();
// EJB 3.0 support - cache our parent event managers.
protected transient List entityEventManagers;
protected transient List 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 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
Object[] runtimeParameters = new Object[1];
runtimeParameters[0] = event;
PrivilegedAccessHelper.callDoPrivilegedWithException(
() -> PrivilegedAccessHelper.invokeMethod(eventMethod, event.getSource(), runtimeParameters),
(ex) -> {
if (ex instanceof IllegalAccessException) {
return DescriptorException.illegalAccessWhileEventExecution(eventMethod.getName(), getDescriptor(), ex);
}
if (ex instanceof IllegalArgumentException) {
return DescriptorException.illegalArgumentWhileObsoleteEventExecute(eventMethod.getName(), getDescriptor(), ex);
}
if (ex instanceof InvocationTargetException) {
return DescriptorException.targetInvocationWhileEventExecution(eventMethod.getName(), getDescriptor(), ex);
}
return new RuntimeException(String.format("Invocation of %s method failed", eventMethod.getName()), ex);
}
);
} 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 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 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 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 getEntityListenerEventListeners() {
if (entityListenerEventListeners == null) {
entityListenerEventListeners = new CopyOnWriteArrayList<>();
}
return entityListenerEventListeners;
}
/**
* PUBLIC:
* Returns the Listener objects that have been added.
*
* @see #addListener(DescriptorEventListener)
*/
public List getEventListeners() {
// Lazy initialize to avoid unnecessary enumerations.
if (eventListeners == null) {
eventListeners = new CopyOnWriteArrayList<>();
}
return eventListeners;
}
protected AtomicReferenceArray getEventMethods() {
//Lazy Initialized to prevent Null Pointer exception after serialization
if (this.eventMethods == null) {
this.eventMethods = newAtomicReferenceArray(NumberOfEvents);
}
return eventMethods;
}
protected AtomicReferenceArray 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 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 = 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 eventListeners) {
if (eventListeners instanceof CopyOnWriteArrayList) {
this.eventListeners = eventListeners;
} else {
this.eventListeners = new CopyOnWriteArrayList(eventListeners);
}
}
protected void setEventMethods(AtomicReferenceArray eventMethods) {
this.eventMethods = eventMethods;
}
protected void setEventSelectors(AtomicReferenceArray 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 AtomicReferenceArray 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 AtomicReferenceArray newAtomicReferenceArray(final AtomicReferenceArray 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;
}
}