All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.jpa.metadata.listeners.JPAEntityListenerHolder Maven / Gradle / Ivy

/*
 * Copyright (c) 2012, 2018 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
//     08/01/2012-2.5 Chris Delahunt
//       - 371950: Metadata caching
//     12/14/2017-3.0 Tomas Kraus
//       - 291546: Performance degradation due to usage of Vector in DescriptorEventManager
package org.eclipse.persistence.internal.jpa.metadata.listeners;

import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorEventListener;
import org.eclipse.persistence.descriptors.SerializableDescriptorEventHolder;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.sessions.AbstractSession;

public class JPAEntityListenerHolder implements SerializableDescriptorEventHolder, Cloneable {
    public String listenerClassName;

    public Boolean isDefaultListener;

    public transient DescriptorEventListener listener;

    public Map> serializableMethods;

    public void setIsDefaultListener(Boolean isDefaultListener) {
        this.isDefaultListener = isDefaultListener;
    }

    @Override
    public void addListenerToEventManager(ClassDescriptor descriptor, AbstractSession session, ClassLoader loader) {

        if (listener == null) {
            if (listenerClassName !=null) {
                Class listenerClass = getListenerClass(loader);

                if (DescriptorEventListener.class.isAssignableFrom(listenerClass)){
                    listener = (DescriptorEventListener)constructListenerInstance(listenerClass);
                } else {
                    EntityListener entityListener = new EntityListener(listenerClass, descriptor.getJavaClass());
                    entityListener.setOwningSession(session);
                    if (!(serializableMethods == null)) {
                        //The user class is not a DescriptorEventListener, so wrap it in a JPA EntityListener instance
                        entityListener.setAllEventMethods(this.convertToMethods(loader));

                    }
                    listener = entityListener;
                }

            } else {
              //it must be an EntityClassListener
                EntityListener entityListener = new EntityClassListener(descriptor.getJavaClass());
                entityListener.setAllEventMethods(this.convertToMethods(loader));
                listener = entityListener;
            }
        }
        //need to also check if this is a EntityClassListener and call
        if (listenerClassName!=null) {
            if (isDefaultListener) {
                descriptor.getEventManager().addDefaultEventListener(listener);
            } else {
                descriptor.getEventManager().addEntityListenerEventListener(listener);
            }
        } else {
            descriptor.getEventManager().setEntityEventListener(listener);
        }

    }

    protected Object constructListenerInstance(Class listenerClass){
        Object entityListenerClassInstance = null;
        try {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    entityListenerClassInstance = AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(listenerClass));
                } catch (PrivilegedActionException exception) {
                    throw ValidationException.errorInstantiatingClass(listenerClass, exception.getException());
                }
            } else {
                entityListenerClassInstance = PrivilegedAccessHelper.newInstanceFromClass(listenerClass);
            }
        } catch (IllegalAccessException exception) {
            throw ValidationException.errorInstantiatingClass(listenerClass, exception);
        } catch (InstantiationException exception) {
            throw ValidationException.errorInstantiatingClass(listenerClass, exception);
        }
        return entityListenerClassInstance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public void convertToSerializableMethods(Map> methods) {
        this.serializableMethods = new ConcurrentHashMap<>();
        for (String event: methods.keySet()){
            java.util.List methodList = methods.get(event);
            java.util.List newMethodList = new java.util.ArrayList();
            for (Method method: methodList) {
                MethodSerialImpl serializableMethod = new MethodSerialImpl(method);
                newMethodList.add(serializableMethod);
            }
            this.serializableMethods.put(event, newMethodList);
        }
    }

    /**
     * INTERNAL:
     * used to return an instance of the listenerClassName
     * @return an instance of listenerClassName
     */
    private Class getListenerClass(ClassLoader loader){
        Class entityListenerClass = null;
        try {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    entityListenerClass = AccessController.doPrivileged(new PrivilegedClassForName(listenerClassName, true, loader));
                } catch (PrivilegedActionException exception) {
                    throw ValidationException.unableToLoadClass(listenerClassName, exception.getException());
                }

            } else {
                entityListenerClass =  PrivilegedAccessHelper.getClassForName(listenerClassName, true, loader);
            }
        } catch (ClassNotFoundException exception) {
            throw ValidationException.unableToLoadClass(listenerClassName, exception);
        }
        return entityListenerClass;
    }

    /**
     * INTERNAL:
     * You can have multiple event methods for the same event, however, only
     * one event method per class is permitted.
     */
    public void addEventMethod(String event, Method method) {
        if (!getMethods().containsKey(event)) {
            List methodsList = new ArrayList();
            methodsList.add(method);
            serializableMethods.put(event, methodsList);
        }

        MethodSerialImpl convertedMethod = new MethodSerialImpl(method);
        serializableMethods.get(event).add(convertedMethod);
    }

    /**
     * INTERNAL:
     * This returns a hashtable of methods which are used in a JPA EntityListener instance, built from
     * the MethodSerialImpl representation since Methods are not serializable
     * @param loader
     * @return
     */
    public Map> convertToMethods(ClassLoader loader) {
        Map> table = new ConcurrentHashMap<>();
        for (String event: serializableMethods.keySet()){
            java.util.List methodList = serializableMethods.get(event);
            java.util.List newMethodList = new java.util.ArrayList();
            for (MethodSerialImpl serializedMethod: methodList) {
                try {
                    Method method = serializedMethod.convertToMethod(loader);
                    newMethodList.add(method);
                } catch (Exception e) {
                    throw new javax.persistence.PersistenceException(e);
                }
            }
            table.put(event, newMethodList);
        }
        return table;
    }

    public Map> getMethods() {
        if (serializableMethods == null) {
            serializableMethods = new ConcurrentHashMap>();
        }
        return serializableMethods;
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy