
org.firebirdsql.gds.ng.jna.FbClientFeatureAccessHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird-native Show documentation
Show all versions of jaybird-native Show documentation
Native GDS Factory Plugin for Jaybird JDBC Driver
The newest version!
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.gds.ng.jna;
import com.sun.jna.Library;
import com.sun.jna.NativeLibrary;
import org.firebirdsql.gds.JaybirdSystemProperties;
import org.firebirdsql.jna.fbclient.FbClientLibrary;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.EnumSet;
import java.util.Set;
/**
* Invocation handler to check for feature existence as part of the client library initialization.
*
* @since 4.0
*/
class FbClientFeatureAccessHandler implements InvocationHandler {
private static final Method HAS_FEATURE;
private static final Method GET_FEATURES;
static {
try {
HAS_FEATURE = FbClientFeatureAccess.class.getMethod("hasFeature", FbClientFeature.class);
GET_FEATURES = FbClientFeatureAccess.class.getMethod("getFeatures");
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private final FbClientLibrary clientLibrary;
private final NativeLibrary nativeLibrary;
private final Set clientFeatures;
private final InvocationHandler delegatedHandler;
private FbClientFeatureAccessHandler(FbClientLibrary clientLibrary, NativeLibrary nativeLibrary,
Set clientFeatures, InvocationHandler delegatedHandler) {
this.clientLibrary = clientLibrary;
this.nativeLibrary = nativeLibrary;
this.clientFeatures = clientFeatures;
this.delegatedHandler = delegatedHandler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] inArgs) throws Throwable {
// Handle implementation of FbClientFeatureAccess
if (HAS_FEATURE.equals(method)) {
//noinspection SuspiciousMethodCalls
return clientFeatures.contains(inArgs[0]);
}
if (GET_FEATURES.equals(method)) {
return clientFeatures;
}
return delegatedHandler.invoke(clientLibrary, method, inArgs);
}
NativeLibrary getNativeLibrary() {
return nativeLibrary;
}
/**
* Creates a {@code FbClientLibrary} proxy implementing {@link FbClientFeatureAccess}.
*
* @param library
* The original {@code FbClientLibrary} proxy object
* @return New proxy for {@code library} that implements {@link FbClientFeatureAccess}
* @throws IllegalArgumentException
* if {@code library} is not a proxy with {@link Library.Handler} as its invocation handler
*/
static FbClientLibrary decorateWithFeatureAccess(FbClientLibrary library) {
Class> libraryClass = library.getClass();
if (!Proxy.isProxyClass(libraryClass)) {
throw new IllegalArgumentException(
"Could not decorate client library with FbClientFeatureAccess: not a proxy");
}
InvocationHandler ih = Proxy.getInvocationHandler(library);
if (!(ih instanceof Library.Handler)) {
throw new IllegalArgumentException("Could not decorate client library with FbClientFeatureAccess: "
+ "unexpected invocation handler type " + ih.getClass());
}
Library.Handler originalHandler = (Library.Handler) ih;
NativeLibrary nativeLibrary = originalHandler.getNativeLibrary();
Set clientFeatures = determineClientFeatures(nativeLibrary);
InvocationHandler delegatedHandler = syncWrapIfNecessary(library, originalHandler);
FbClientFeatureAccessHandler fbClientFeatureAccessHandler =
new FbClientFeatureAccessHandler(library, nativeLibrary, clientFeatures, delegatedHandler);
Class> interfaceClass = originalHandler.getInterfaceClass();
ClassLoader loader = interfaceClass.getClassLoader();
Object proxy = Proxy.newProxyInstance(loader, new Class[] { interfaceClass, FbClientFeatureAccess.class },
fbClientFeatureAccessHandler);
return (FbClientLibrary) proxy;
}
private static Set determineClientFeatures(NativeLibrary nativeLibrary) {
EnumSet features = EnumSet.allOf(FbClientFeature.class);
for (FbClientFeature feature : FbClientFeature.values()) {
for (String methodName : feature.methodNames()) {
if (!hasMethod(nativeLibrary, methodName)) {
features.remove(feature);
break;
}
}
}
return features;
}
private static boolean hasMethod(NativeLibrary nativeLibrary, String methodName) {
try {
return nativeLibrary.getFunction(methodName) != null;
} catch (UnsatisfiedLinkError e) {
// not found
return false;
}
}
private static InvocationHandler syncWrapIfNecessary(final FbClientLibrary clientLibrary,
final Library.Handler originalHandler) {
if (JaybirdSystemProperties.isSyncWrapNativeLibrary()) {
// Mimics com.sun.jna.Native.synchronizedLibrary(..) with creating a proxy
return (proxy, method, args) -> {
synchronized (originalHandler.getNativeLibrary()) {
return originalHandler.invoke(clientLibrary, method, args);
}
};
}
return originalHandler;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy