/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.locks.*;
import java.util.jar.*;
import javax.annotation.*;
import mockit.internal.expectations.mocking.*;
import mockit.internal.mockups.*;
import mockit.internal.startup.*;
import mockit.internal.util.*;
public abstract class MockingBridge implements InvocationHandler
{
private static final Object[] EMPTY_ARGS = {};
private static final ReentrantLock LOCK = new ReentrantLock();
private static boolean fieldsSet;
public final String id;
/**
* The instance is stored in a place directly accessible through the Java SE API, so that it can
* be recovered from any class loader.
*/
protected MockingBridge(@Nonnull String id) { this.id = id; }
protected static boolean notToBeMocked(@Nullable Object mocked, @Nonnull String mockedClassDesc)
{
return
(mocked == null && "java/lang/System".equals(mockedClassDesc) ||
mocked != null && instanceOfClassThatParticipatesInClassLoading(mocked.getClass())
) && wasCalledDuringClassLoading();
}
public static boolean instanceOfClassThatParticipatesInClassLoading(@Nonnull Class<?> mockedClass)
{
return
mockedClass == System.class || mockedClass == File.class || mockedClass == URL.class ||
mockedClass == FileInputStream.class || mockedClass == Manifest.class ||
JarFile.class.isAssignableFrom(mockedClass) || JarEntry.class.isAssignableFrom(mockedClass) ||
Vector.class.isAssignableFrom(mockedClass) || Hashtable.class.isAssignableFrom(mockedClass);
}
private static boolean wasCalledDuringClassLoading()
{
if (LOCK.isHeldByCurrentThread()) {
return true;
}
LOCK.lock();
try {
StackTrace st = new StackTrace(new Throwable());
int n = st.getDepth();
for (int i = 3; i < n; i++) {
StackTraceElement ste = st.getElement(i);
if (
"ClassLoader.java".equals(ste.getFileName()) &&
"loadClass getResource loadLibrary".contains(ste.getMethodName())
) {
return true;
}
}
return false;
}
finally {
LOCK.unlock();
}
}
@Nonnull
protected static Object[] extractMockArguments(int startingIndex, @Nonnull Object[] args)
{
if (args.length > startingIndex) {
Object[] mockArgs = new Object[args.length - startingIndex];
System.arraycopy(args, startingIndex, mockArgs, 0, mockArgs.length);
return mockArgs;
}
return EMPTY_ARGS;
}
public static void setMockingBridgeFields()
{
Class<?> hostClass = ClassLoad.loadByInternalName(InstrumentationHolder.hostJREClassName);
setMockingBridgeField(hostClass, MockedBridge.MB);
setMockingBridgeField(hostClass, MockupBridge.MB);
setMockingBridgeField(hostClass, MockMethodBridge.MB);
}
private static void setMockingBridgeField(@Nonnull Class<?> hostClass, @Nonnull MockingBridge mockingBridge)
{
try {
hostClass.getDeclaredField(mockingBridge.id).set(null, mockingBridge);
}
catch (NoSuchFieldException ignore) {}
catch (IllegalAccessException e) { throw new RuntimeException(e); }
}
@Nonnull
public static String getHostClassName()
{
if (!fieldsSet) {
setMockingBridgeFields();
fieldsSet = true;
}
return InstrumentationHolder.hostJREClassName;
}
}