/******************************************************************************* | |
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.descriptors; | |
import java.lang.reflect.*; | |
import java.security.AccessController; | |
import java.security.PrivilegedActionException; | |
import java.util.*; | |
import java.io.*; | |
import org.eclipse.persistence.internal.helper.*; | |
import org.eclipse.persistence.core.descriptors.CoreDescriptorEventManager; | |
import org.eclipse.persistence.exceptions.*; | |
import org.eclipse.persistence.sessions.SessionProfiler; | |
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; | |
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker; | |
import org.eclipse.persistence.internal.sessions.AbstractSession; | |
/** | |
* <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 Vector eventSelectors; | |
protected transient Vector eventMethods; | |
protected transient Vector eventListeners; | |
// EJB 3.0 support for event listeners. | |
protected transient Vector defaultEventListeners; | |
protected transient Vector entityListenerEventListeners; | |
protected transient DescriptorEventListener entityEventListener; | |
/** | |
* Listeners that are fired after all other listeners are fired | |
*/ | |
protected transient List<DescriptorEventListener> internalListeners = new ArrayList<DescriptorEventListener>(); | |
// EJB 3.0 support - cache our parent event managers. | |
protected transient Vector entityEventManagers; | |
protected transient Vector 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 java.util.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 = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents); | |
this.eventMethods = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents); | |
this.hasAnyEventListeners = false; | |
this.excludeDefaultListeners = false; | |
this.excludeSuperclassListeners = false; | |
for (int index = 0; index < NumberOfEvents; index++) { | |
this.eventSelectors.addElement(null); | |
this.eventMethods.addElement(null); | |
} | |
} | |
/** | |
* PUBLIC: | |
* EJB 3.0 support for default listeners. | |
*/ | |
public void addDefaultEventListener(DescriptorEventListener listener) { | |
getDefaultEventListeners().addElement(listener); | |
} | |
/** | |
* PUBLIC: | |
* EJB 3.0 support for lifecycle callback events defined on an entity | |
* listener class. | |
*/ | |
public void addEntityListenerEventListener(DescriptorEventListener listener) { | |
getEntityListenerEventListeners().addElement(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().addElement(listener); | |
setHasAnyEventListeners(true); | |
} | |
/** | |
* INTERNAL: | |
* | |
*/ | |
public void addInternalListener(DescriptorEventListener listener) { | |
if (internalListeners==null) { | |
internalListeners = new ArrayList<DescriptorEventListener>(); | |
} | |
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. | |
*/ | |
public Object clone() { | |
DescriptorEventManager clone = null; | |
try { | |
clone = (DescriptorEventManager)super.clone(); | |
clone.setEventSelectors((Vector)getEventSelectors().clone()); | |
clone.setEventMethods((Vector)getEventMethods().clone()); | |
clone.setEventListeners(getEventListeners()); | |
} catch (Exception exception) { | |
; | |
} | |
return clone; | |
} | |
/** | |
* 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. | |
* @param classLoader | |
*/ | |
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 | |
*/ | |
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 = (Method)getEventMethods().elementAt(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 = (String)getEventSelectors().elementAt(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 (String)getEventSelectors().elementAt(AboutToDeleteEvent); | |
} | |
/** | |
* INTERNAL: | |
*/ | |
public String getAboutToInsertSelector() { | |
return (String)getEventSelectors().elementAt(AboutToInsertEvent); | |
} | |
/** | |
* INTERNAL: | |
*/ | |
public String getAboutToUpdateSelector() { | |
return (String)getEventSelectors().elementAt(AboutToUpdateEvent); | |
} | |
/** | |
* INTERNAL: | |
* EJB 3.0 support. Returns the default listeners. | |
*/ | |
public Vector getDefaultEventListeners() { | |
if (defaultEventListeners == null) { | |
defaultEventListeners = new NonSynchronizedVector(); | |
} | |
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 java.util.List<SerializableDescriptorEventHolder> getDescriptorEventHolders() { | |
if (descriptorEventHolders == null) { | |
descriptorEventHolders = new java.util.ArrayList(); | |
} | |
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(java.util.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 Vector getEntityListenerEventListeners() { | |
if (entityListenerEventListeners == null) { | |
entityListenerEventListeners = new Vector(); | |
} | |
return entityListenerEventListeners; | |
} | |
/** | |
* PUBLIC: | |
* Returns the Listener objects that have been added. | |
* | |
* @see #addListener(DescriptorEventListener) | |
*/ | |
public Vector getEventListeners() { | |
// Lazy initialize to avoid unnecessary enumerations. | |
if (eventListeners == null) { | |
eventListeners = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1); | |
} | |
return eventListeners; | |
} | |
protected Vector getEventMethods() { | |
//Lazy Initialized to prevent Null Pointer exception after serialization | |
if (this.eventMethods == null) { | |
this.eventMethods = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents); | |
for (int index = 0; index < NumberOfEvents; ++index) { | |
this.eventMethods.addElement(null); | |
} | |
} | |
return eventMethods; | |
} | |
protected Vector getEventSelectors() { | |
if (this.eventSelectors == null) { | |
this.eventSelectors = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(NumberOfEvents); | |
for (int index = 0; index < NumberOfEvents; ++index) { | |
this.eventSelectors.addElement(null); | |
} | |
} | |
return eventSelectors; | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is built | |
*/ | |
public String getPostBuildSelector() { | |
return (String)getEventSelectors().elementAt(PostBuildEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is cloned | |
*/ | |
public String getPostCloneSelector() { | |
return (String)getEventSelectors().elementAt(PostCloneEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is deleted | |
*/ | |
public String getPostDeleteSelector() { | |
return (String)getEventSelectors().elementAt(PostDeleteEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is inserted | |
*/ | |
public String getPostInsertSelector() { | |
return (String)getEventSelectors().elementAt(PostInsertEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is merged | |
*/ | |
public String getPostMergeSelector() { | |
return (String)getEventSelectors().elementAt(PostMergeEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is refreshed | |
*/ | |
public String getPostRefreshSelector() { | |
return (String)getEventSelectors().elementAt(PostRefreshEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is updated | |
*/ | |
public String getPostUpdateSelector() { | |
return (String)getEventSelectors().elementAt(PostUpdateEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called after an object is written | |
*/ | |
public String getPostWriteSelector() { | |
return (String)getEventSelectors().elementAt(PostWriteEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before the create operation is applied to an object | |
*/ | |
public String getPrePersistSelector() { | |
return (String)getEventSelectors().elementAt(PrePersistEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before an object is deleted | |
*/ | |
public String getPreDeleteSelector() { | |
return (String)getEventSelectors().elementAt(PreDeleteEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before an object is inserted | |
*/ | |
public String getPreInsertSelector() { | |
return (String)getEventSelectors().elementAt(PreInsertEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before the remove operation is applied to an object | |
*/ | |
public String getPreRemoveSelector() { | |
return (String)getEventSelectors().elementAt(PreRemoveEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before an object is updated | |
*/ | |
public String getPreUpdateSelector() { | |
return (String)getEventSelectors().elementAt(PreUpdateEvent); | |
} | |
/** | |
* PUBLIC: | |
* The name of the method called before an object is written | |
*/ | |
public String getPreWriteSelector() { | |
return (String)getEventSelectors().elementAt(PreWriteEvent); | |
} | |
/** | |
* INTERNAL: | |
* Return if the event manager has any event listeners, or event methods. | |
* If nothing is listening to event they can be avoided. | |
*/ | |
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.size() > 0; | |
} | |
/** | |
* INTERNAL: | |
* EJB 3.0 support. Return true if this event manager has any entity | |
* listener event listeners. | |
*/ | |
public boolean hasEntityListenerEventListeners() { | |
return entityListenerEventListeners != null && entityListenerEventListeners.size() > 0; | |
} | |
/** | |
* 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); | |
} | |
for (int index = 0; index < NumberOfEvents; index++) { | |
if (getEventSelectors().elementAt(index) != null) { | |
setHasAnyEventListeners(true); | |
getEventMethods().setElementAt(findMethod(index), 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 ((getEventSelectors().get(index) == null) && (parentEventManager.getEventSelectors().get(index) != null)) { | |
setHasAnyEventListeners(true); | |
getEventSelectors().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 NonSynchronizedVector(); | |
entityListenerEventManagers = new NonSynchronizedVector(); | |
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 = (DescriptorEventListener) 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--) { | |
Vector entityListenerEventListeners = ((DescriptorEventManager) 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 = ((DescriptorEventManager) 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 = (DescriptorEventListener)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 = new Vector(NumberOfEvents); | |
for (int index = 0; index < NumberOfEvents; index++) { | |
this.eventMethods.addElement(null); | |
} | |
initialize(session); | |
} | |
/** | |
* PUBLIC: | |
* Remove a event listener. | |
*/ | |
public void removeListener(DescriptorEventListener listener) { | |
getEventListeners().removeElement(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().setElementAt(aboutToDeleteSelector, AboutToDeleteEvent); | |
} | |
/** | |
* 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().setElementAt(aboutToInsertSelector, AboutToInsertEvent); | |
} | |
/** | |
* 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().setElementAt(aboutToUpdateSelector, AboutToUpdateEvent); | |
} | |
/** | |
* 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(Vector eventListeners) { | |
this.eventListeners = eventListeners; | |
} | |
protected void setEventMethods(Vector eventMethods) { | |
this.eventMethods = eventMethods; | |
} | |
protected void setEventSelectors(Vector 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().setElementAt(postBuildSelector, PostBuildEvent); | |
} | |
/** | |
* 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().setElementAt(postCloneSelector, PostCloneEvent); | |
} | |
/** | |
* 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().setElementAt(postDeleteSelector, PostDeleteEvent); | |
} | |
/** | |
* 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().setElementAt(postInsertSelector, PostInsertEvent); | |
} | |
/** | |
* 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().setElementAt(postMergeSelector, PostMergeEvent); | |
} | |
/** | |
* 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().setElementAt(postRefreshSelector, PostRefreshEvent); | |
} | |
/** | |
* 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().setElementAt(postUpdateSelector, PostUpdateEvent); | |
} | |
/** | |
* 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().setElementAt(postWriteSelector, PostWriteEvent); | |
} | |
/** | |
* 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().setElementAt(preDeleteSelector, PreDeleteEvent); | |
} | |
/** | |
* 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().setElementAt(preInsertSelector, PreInsertEvent); | |
} | |
/** | |
* 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().setElementAt(prePersistSelector, PrePersistEvent); | |
} | |
/** | |
* 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().setElementAt(preRemoveSelector, PreRemoveEvent); | |
} | |
/** | |
* 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().setElementAt(preUpdateSelector, PreUpdateEvent); | |
} | |
/** | |
* 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().setElementAt(preWriteSelector, PreWriteEvent); | |
} | |
} |