/*
 * Copyright (c) 1998, 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:
//     05/28/2008-1.0M8 Andrei Ilitchev
//        - New file introduced for bug 224964: Provide support for Proxy Authentication through JPA.
package org.eclipse.persistence.internal.databaseaccess;

import org.eclipse.persistence.sessions.Session;

/**
 * PUBLIC:
 * The base class for connection customization.
 *
 * The extending class must not alter the attributes defined in this class.
 *
 * Consider implementing equals method on the extending class so that
 * the two instances are consider equal if they apply exactly the same customizations.
 * This allows to skip unnecessary work when overriding customizer defined by
 * ServerSession by the one defined by ClientSession: in case the two customizers are
 * equal the old (ServerSession's) customizer is kept.
 * That may save considerable effort in internal connection pooling case:
 * if both ServerSession and ClientSession have exactly the same proxy properties
 * (that happens if ClientSession doesn't have any proxy properties at all and
 * just "inherits" all the properties from its parent ServerSession)
 * then without correct customizer equality check the proxy session opened
 * by ServerSession would have been closed, only to be re-opened again by ClientSession
 * customizer using exactly the same proxy properties (and then the same happens again
 * when ClientSession releases connection).
 */
public abstract class ConnectionCustomizer implements Cloneable {
    protected Accessor accessor;
    protected Session session;
    private ConnectionCustomizer prevCustomizer;

    /**
     * INTERNAL:
     * Constructor accepts the accessor to which the customizer will be applied and the session that used for customization.
     * The accessor and the session couldn't be altered during the connector's lifetime,
     * the only exception is of the new accessor by DatasourceAccessor.clone method.
     */
    public ConnectionCustomizer(Accessor accessor, Session session) {
        this.accessor = accessor;
        this.session = session;
    }

    /**
     * INTERNAL:
     * Used only by DatasourceAccessor.clone method.
     */
    void setAccessor(Accessor accessor) {
        this.accessor = accessor;
    }

    /**
     * INTERNAL:
     */
    public Accessor getAccessor() {
        return accessor;
    }

    /**
     * INTERNAL:
     */
    public Session getSession() {
        return session;
    }

    /**
     * INTERNAL:
     */
    public ConnectionCustomizer getPrevCustomizer() {
        return prevCustomizer;
    }

    /**
     * INTERNAL:
     */
    public void setPrevCustomizer(ConnectionCustomizer prevCustomizer) {
        this.prevCustomizer = prevCustomizer;
    }

    /**
     * INTERNAL:
     * Empty customizer that does nothing.
     * Used when ServerSession defines customizer and ClientSession
     * explicitly demands no customization.
     * Example: ServerSession has proxy properties, ClientSession
     * has PersistenceUnitProperties.ORACLE_PROXY_TYPE property with an empty String value.
     * Using Empty customizer allows to avoid customization as well as
     * cache the previous (ServerSession - created) customizer,
     * which is brought back after ClientSession releases the accessor.
     */
    static class Empty extends ConnectionCustomizer {
        public Empty(Accessor accessor, Session session) {
            super(accessor, session);
        }
        public void customize() {
        }
        public boolean isActive() {
            return false;
        }
        public void clear() {
        }
        public boolean equals(Object obj) {
            return (obj instanceof Empty);
        }
    }
    public static ConnectionCustomizer createEmptyCustomizer(Session session) {
        return new Empty(null, session);
    }

    /**
     * INTERNAL:
     * Applies customization to connection.
     * Called only if connection is not already customized (isActive()==false).
     * The method may throw SQLException wrapped into DatabaseException.
     * isActive method called after this method should return true only in case
     * the connection was actually customized.
     */
    public abstract void customize();

    /**
     * INTERNAL:
     * Indicated whether the connection is currently customized.
     */
    public abstract boolean isActive();

    /**
     * INTERNAL:
     * Clears customization from connection.
     * Called only if connection is customized (isActive()==true).
     * If the method fails due to SQLException it should "eat" it
     * (just like DatasourceAccessor.closeConnection method).
     * isActive method called after this method should always return false.
     */
    public abstract void clear();
}
