<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.proxy2.stub;

import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;

import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.proxy2.Interceptor;
import org.apache.commons.proxy2.Invocation;
import org.apache.commons.proxy2.ObjectProvider;
import org.apache.commons.proxy2.ProxyUtils;
import org.apache.commons.proxy2.invoker.RecordedInvocation;

/**
 * StubInterceptor collects, then replays on demand, the stubbing information.
 *
 * @author <NAME>
 */
/*
 * Handling with an interceptor means we get the parent ProxyFactory's implementation of an Invocation
 */
abstract class StubInterceptor implements Interceptor {
    /** Serialization version */
    private static final long serialVersionUID = 1L;

    private interface InvocationMatcher {
        boolean matches(Invocation invocation);
    }

    private static abstract class Result {
        InvocationMatcher invocationMatcher;

        Result(InvocationMatcher invocationMatcher) {
            super();
            this.invocationMatcher = invocationMatcher;
        }

        abstract Object getResult() throws Throwable;
    }

    private static class Answer extends Result {
        private Object answer;

        Answer(InvocationMatcher invocationMatcher, Object answer) {
            super(invocationMatcher);
            this.answer = answer;
        }

        /**
         * Get the answer.
         * @return Object
         */
        public Object getResult() throws Throwable {
            return answer instanceof ObjectProvider<?> ? ((ObjectProvider<?>) answer)
                    .getObject()
                    : answer;
        }
    }

    private static class Throw extends Result {
        private ObjectProvider<? extends Throwable> throwableProvider;

        /**
         * Create a new Throw instance.
         * @param invocationMatcher
         */
        Throw(InvocationMatcher invocationMatcher,
                ObjectProvider<? extends Throwable> throwableProvider) {
            super(invocationMatcher);
            this.throwableProvider = throwableProvider;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        Object getResult() throws Throwable {
            throw throwableProvider.getObject();
        }
    }

    private boolean complete;
    private RecordedInvocation currentInvocation;
    private Deque<Result> resultStack = new ArrayDeque<Result>();

    /**
     * Create a new StubInterceptor instance.
     */
    StubInterceptor() {
        super();
    }

    /**
     * {@inheritDoc}
     */
    public Object intercept(Invocation invocation) throws Throwable {
        if (complete) {
            for (Result result : resultStack) {
                if (result.invocationMatcher.matches(invocation)) {
                    return result.getResult();
                }
            }
            return interceptFallback(invocation);
        }
        RecordedInvocation incoming = new RecordedInvocation(invocation
                .getMethod(), invocation.getArguments());
        synchronized (this) {
            if (currentInvocation == null) {
                currentInvocation = incoming;
            } else {
                throw new IllegalStateException("Called " + incoming
                        + " while stubbing of " + currentInvocation
                        + " is incomplete.");
            }
        }
        return ProxyUtils.nullValue(invocation.getMethod().getReturnType());
    }

    void addAnswer(Object o) {
        resultStack.push(validAnswer(o));
    }

    void addThrow(ObjectProvider<? extends Throwable> throwableProvider) {
        resultStack.push(new Throw(currentMatcher(), throwableProvider));
    }

    private synchronized InvocationMatcher currentMatcher() {
        if (complete) {
            throw new IllegalStateException(
                    "Answers not permitted; stubbing already marked as complete.");
        }
        if (currentInvocation == null) {
            throw new IllegalStateException(
                    "No ongoing stubbing found for any method");
        }
        try {
            final RecordedInvocation recordedInvocation = currentInvocation;
            return new InvocationMatcher() {

                public boolean matches(Invocation invocation) {
                    return invocation.getMethod().getName().equals(
                            recordedInvocation.getInvokedMethod().getName())
                            && Arrays.equals(invocation.getArguments(),
                                    recordedInvocation.getArguments());
                }

            };
        } finally {
            currentInvocation = null;
        }
    }

    /**
     * Validate and return the requested answer to the current invocation.
     * @param o
     * @return Answer
     */
    synchronized Answer validAnswer(Object o) {
        if (currentInvocation == null) {
            //fall through and let currentMatcher() throw the exception
        } else if (o instanceof ObjectProvider<?>) {
            // give ObjectProviders the benefit of the doubt?
        } else {
            Method m = currentInvocation.getInvokedMethod();
            if (!TypeUtils.isInstance(o, m.getReturnType())) {
                throw new IllegalArgumentException(String.format("%s does not specify a valid return value for %s", o,
                    m));
            }
        }
        return new Answer(currentMatcher(), o);
    }

    void complete() {
        this.complete = true;
    }

    /**
     * Fallback behavior
     * @param invocation
     * @return result
     * @throws Throwable
     */
    protected abstract Object interceptFallback(Invocation invocation)
            throws Throwable;
}<commit_msg>unused import<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.proxy2.stub;

import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;

import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.proxy2.Interceptor;
import org.apache.commons.proxy2.Invocation;
import org.apache.commons.proxy2.ObjectProvider;
import org.apache.commons.proxy2.ProxyUtils;
import org.apache.commons.proxy2.invoker.RecordedInvocation;

/**
 * StubInterceptor collects, then replays on demand, the stubbing information.
 *
 * @author <NAME>
 */
/*
 * Handling with an interceptor means we get the parent ProxyFactory's implementation of an Invocation
 */
abstract class StubInterceptor implements Interceptor {
    /** Serialization version */
    private static final long serialVersionUID = 1L;

    private interface InvocationMatcher {
        boolean matches(Invocation invocation);
    }

    private static abstract class Result {
        InvocationMatcher invocationMatcher;

        Result(InvocationMatcher invocationMatcher) {
            super();
            this.invocationMatcher = invocationMatcher;
        }

        abstract Object getResult() throws Throwable;
    }

    private static class Answer extends Result {
        private Object answer;

        Answer(InvocationMatcher invocationMatcher, Object answer) {
            super(invocationMatcher);
            this.answer = answer;
        }

        /**
         * Get the answer.
         * @return Object
         */
        public Object getResult() throws Throwable {
            return answer instanceof ObjectProvider<?> ? ((ObjectProvider<?>) answer)
                    .getObject()
                    : answer;
        }
    }

    private static class Throw extends Result {
        private ObjectProvider<? extends Throwable> throwableProvider;

        /**
         * Create a new Throw instance.
         * @param invocationMatcher
         */
        Throw(InvocationMatcher invocationMatcher,
                ObjectProvider<? extends Throwable> throwableProvider) {
            super(invocationMatcher);
            this.throwableProvider = throwableProvider;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        Object getResult() throws Throwable {
            throw throwableProvider.getObject();
        }
    }

    private boolean complete;
    private RecordedInvocation currentInvocation;
    private Deque<Result> resultStack = new ArrayDeque<Result>();

    /**
     * Create a new StubInterceptor instance.
     */
    StubInterceptor() {
        super();
    }

    /**
     * {@inheritDoc}
     */
    public Object intercept(Invocation invocation) throws Throwable {
        if (complete) {
            for (Result result : resultStack) {
                if (result.invocationMatcher.matches(invocation)) {
                    return result.getResult();
                }
            }
            return interceptFallback(invocation);
        }
        RecordedInvocation incoming = new RecordedInvocation(invocation
                .getMethod(), invocation.getArguments());
        synchronized (this) {
            if (currentInvocation == null) {
                currentInvocation = incoming;
            } else {
                throw new IllegalStateException("Called " + incoming
                        + " while stubbing of " + currentInvocation
                        + " is incomplete.");
            }
        }
        return ProxyUtils.nullValue(invocation.getMethod().getReturnType());
    }

    void addAnswer(Object o) {
        resultStack.push(validAnswer(o));
    }

    void addThrow(ObjectProvider<? extends Throwable> throwableProvider) {
        resultStack.push(new Throw(currentMatcher(), throwableProvider));
    }

    private synchronized InvocationMatcher currentMatcher() {
        if (complete) {
            throw new IllegalStateException(
                    "Answers not permitted; stubbing already marked as complete.");
        }
        if (currentInvocation == null) {
            throw new IllegalStateException(
                    "No ongoing stubbing found for any method");
        }
        try {
            final RecordedInvocation recordedInvocation = currentInvocation;
            return new InvocationMatcher() {

                public boolean matches(Invocation invocation) {
                    return invocation.getMethod().getName().equals(
                            recordedInvocation.getInvokedMethod().getName())
                            && Arrays.equals(invocation.getArguments(),
                                    recordedInvocation.getArguments());
                }

            };
        } finally {
            currentInvocation = null;
        }
    }

    /**
     * Validate and return the requested answer to the current invocation.
     * @param o
     * @return Answer
     */
    synchronized Answer validAnswer(Object o) {
        if (currentInvocation == null) {
            //fall through and let currentMatcher() throw the exception
        } else if (o instanceof ObjectProvider<?>) {
            // give ObjectProviders the benefit of the doubt?
        } else {
            Method m = currentInvocation.getInvokedMethod();
            if (!TypeUtils.isInstance(o, m.getReturnType())) {
                throw new IllegalArgumentException(String.format("%s does not specify a valid return value for %s", o,
                    m));
            }
        }
        return new Answer(currentMatcher(), o);
    }

    void complete() {
        this.complete = true;
    }

    /**
     * Fallback behavior
     * @param invocation
     * @return result
     * @throws Throwable
     */
    protected abstract Object interceptFallback(Invocation invocation)
            throws Throwable;
}
{'fraction_non_alphanumeric': 0.08120041909893728, 'fraction_numerical': 0.001870977398593025, 'mean_word_length': 2.1516509433962265, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4155302', 'n_tokens_mistral': 3210, 'n_tokens_neox': 3087, 'n_words': 953}