/*
 * 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
package org.eclipse.persistence.testing.tests.interfaces;

import org.eclipse.persistence.testing.framework.*;

import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.indirection.*;
import org.eclipse.persistence.testing.models.interfaces.*;

/**
 * VariableOneToOneMapping doesn't work with proxyIndirection,
 * throws a nullPointerException when building the object reference.
 * Scenario: 2 classes (A and B) and an interface C, where A implements C.
 * Set up the mapping from B to A as VariableOneToOneMapping();
 * Then read in a B object that references an A object.  It will throw
 * the following exception :
 * java.lang.NullPointerException
 *       at TOPLink.Private.Indirection.ProxyIndirectionPolicy.valueFromQuery(
 *       ProxyIndirectionPolicy.java:123)
 *
 * Class created on Mar 22/2002; CR#3838 in StarTeam; Predrag
 */

public class QueryAccrossV11ProxyIndirectionTest extends AutoVerifyTestCase {
    protected Exception caughtException;
    protected ClassDescriptor descriptor;
    protected IndirectionPolicy indirectionPolicy = null;

    public QueryAccrossV11ProxyIndirectionTest() {
        super();
        setDescription("Test that VariableOneToOneMapping mapping with ProxyIndirection" + "  works correctly");
    }

    public ClassDescriptor getDescriptorV11ProxyIndirection() {
        return descriptor;
    }

    public void setDescriptorV11ProxyIndirection(Class<?> cls, String attributeName, Class<?> proxyIndirectClass) {
        // instruct descriptor to use proxy indirection since
        // VariableOneToOneMapping maping for attribute "program"
        // in InterfaceWithoutTablesProject.java, did not set it;
        ClassDescriptor descriptorToReturn = null;
        descriptorToReturn = getSession().getClassDescriptor(cls);
        ObjectReferenceMapping mappingForAttribute =
            (ObjectReferenceMapping)descriptorToReturn.getMappingForAttributeName(attributeName);
        indirectionPolicy = mappingForAttribute.getIndirectionPolicy();
        mappingForAttribute.useProxyIndirection(proxyIndirectClass);
        this.descriptor = descriptorToReturn;
    } // end of setDescriptorNamedQuery

    public void resetDescriptorV11ProxyIndirection(String attributeName) {
        ObjectReferenceMapping mappingForAttribute =
            (ObjectReferenceMapping)descriptor.getMappingForAttributeName(attributeName);
        mappingForAttribute.setIndirectionPolicy(indirectionPolicy);
    }

    @Override
    public void setup() {
        setDescriptorV11ProxyIndirection(Actor.class, "program", ProgramInt.class);
        getSession().getIdentityMapAccessor().initializeIdentityMaps();
    } // end of setup()

    @Override
    public void test() {
        try {
            java.util.Vector actors = getSession().readAllObjects(Actor.class);
            for (int x = 0; x < actors.size(); x++) {
                Actor actor = (Actor)actors.elementAt(x);
                //trigger indirection
                String name = actor.program.getName();
            }
        } catch (NullPointerException e) {
            caughtException = e;
        }
    } // end of test()

    @Override
    public void reset() {
        // do not want to keep proxy indirection on maping for
        // attribute "program" - VariableOneToOneMapping
        resetDescriptorV11ProxyIndirection("program");
        getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
    } // end of reset()

    @Override
    public void verify() {
        if (caughtException != null) {
            throw new org.eclipse.persistence.testing.framework.TestErrorException("Test that VariableOneToOneMapping mapping with" +
                                                                              " ProxyIndirection works correctly.\n" +
                                                                              "This exception thrown while testing test case.\n" +
                                                                              "----- QueryAccrossV11ProxyIndirectionTest() -----\n" +
                                                                              caughtException.getMessage());
        }

    }
}   // end of class QueryAccrossV11ProxyIndirectionTest
