| /* |
| * 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<DescriptorEventListener> 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<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<T> 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<T> array = new AtomicReferenceArray<>(length); |
| for (int index = 0; index < length; array.set(index, src.get(index++))); |
| return array; |
| } |
| |
| } |