jnr.ffi.provider.jffi.NativeClosureFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnr-ffi Show documentation
Show all versions of jnr-ffi Show documentation
A library for invoking native functions from java
/*
* Copyright (C) 2011 Wayne Meissner
*
* This file is part of the JNR project.
*
* Licensed 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 jnr.ffi.provider.jffi;
import com.kenai.jffi.CallContext;
import com.kenai.jffi.Closure;
import com.kenai.jffi.ClosureMagazine;
import com.kenai.jffi.ClosureManager;
import jnr.ffi.Pointer;
import jnr.ffi.annotations.Delegate;
import jnr.ffi.mapper.SignatureTypeMapper;
import jnr.ffi.provider.FromNativeType;
import jnr.ffi.provider.ToNativeType;
import jnr.ffi.util.ref.FinalizableWeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import static jnr.ffi.provider.jffi.ClosureUtil.getParameterType;
import static jnr.ffi.provider.jffi.ClosureUtil.getResultType;
import static jnr.ffi.provider.jffi.InvokerUtil.getCallContext;
import static jnr.ffi.provider.jffi.InvokerUtil.getNativeCallingConvention;
/**
*
*/
public final class NativeClosureFactory {
private final jnr.ffi.Runtime runtime;
private final ConcurrentMap closures = new ConcurrentHashMap();
private final CallContext callContext;
private final NativeClosureProxy.Factory closureProxyFactory;
private final ConcurrentLinkedQueue freeQueue = new ConcurrentLinkedQueue();
private ClosureMagazine currentMagazine;
protected NativeClosureFactory(jnr.ffi.Runtime runtime, CallContext callContext,
NativeClosureProxy.Factory closureProxyFactory) {
this.runtime = runtime;
this.closureProxyFactory = closureProxyFactory;
this.callContext = callContext;
}
static NativeClosureFactory newClosureFactory(jnr.ffi.Runtime runtime, Class closureClass,
SignatureTypeMapper typeMapper, AsmClassLoader classLoader) {
Method callMethod = null;
for (Method m : closureClass.getMethods()) {
if (m.isAnnotationPresent(Delegate.class) && Modifier.isPublic(m.getModifiers())
&& !Modifier.isStatic(m.getModifiers())) {
callMethod = m;
break;
}
}
if (callMethod == null) {
throw new NoSuchMethodError("no public non-static delegate method defined in " + closureClass.getName());
}
Class[] parameterTypes = callMethod.getParameterTypes();
FromNativeType[] parameterSigTypes = new FromNativeType[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; ++i) {
parameterSigTypes[i] = getParameterType(runtime, callMethod, i, typeMapper);
}
ToNativeType resultType = getResultType(runtime, callMethod, typeMapper);
return new NativeClosureFactory(runtime, getCallContext(resultType, parameterSigTypes, getNativeCallingConvention(callMethod), false),
NativeClosureProxy.newProxyFactory(runtime, callMethod, resultType, parameterSigTypes, classLoader));
}
private void expunge(ClosureReference ref, Integer key) {
// Fast case - no chained elements; can just remove from the hash map
if (ref.next == null && closures.remove(key, ref)) {
return;
}
// Remove from chained list
synchronized (closures) {
for (ClosureReference clref = closures.get(key), prev = clref; clref != null; prev = clref, clref = clref.next) {
if (clref == ref) {
if (prev != clref) {
// if not first element in list, just remove this one
prev.next = clref.next;
} else {
// first element in list, replace with the next if non-null, else remove from map
if (clref.next != null) {
closures.replace(key, clref, clref.next);
} else {
closures.remove(key, clref);
}
}
break;
}
}
}
}
private void recycle(NativeClosurePointer ptr) {
freeQueue.add(ptr);
}
final class ClosureReference extends FinalizableWeakReference