...
Code Block | ||
---|---|---|
| ||
public class ClassLoaderOptimisticCodec implements ClassLoaderCodec { public ClassLoaderOptimisticCodec() {} @Nullable public Object encodeClassLoader(Class<?> cls, ClassLoader clsLdr) throws IgniteException { return null; } public ClassLoader decodeClassLoader(String fqn, @Nullable Object encodedClsLdr) throws IgniteException { // TODO: // Iterate through all the bundles and pick the first one // that can load the class. Once found, cache the class loader // for faster lookups going forward. ... } } |
First of all the both approaches imply that your cluster is consistent and contains the same version of the bundles on all the nodes. This can be see a a valid assumption in order to ensure the consistency of your computation tasks. If you want to be able to work it in a more non deterministic approach then we have to introduce yet another strategy. But first let focus assume that the bundles are equals on the entire cluster.
TBD
On the write side this approach require you to capture the bundle symbolic name and its version. This is something easy to do as in OSGi all classloader except the system classloader implements the BundleReference. The pessimis codec can look like that:
Code Block | ||
---|---|---|
| ||
public class ClassLoaderPessimisticCodec implements ClassLoaderCodec {
private static final byte FRAMEWORK_CLASS_LOADER_ID = 0;
private static final byte IGNITE_CLASS_LOADER_ID = 1;
private static final byte BOOT_CLASS_LOADER_ID = 2;
private static final byte BUNDLE_CLASS_LOADER_ID = 4;
private static final ClassLoader FRAMEWOR_CLASS_LOADER = Bundle.class.getClassLoader();
private final PackageAdmin packageAdmin;
public ClassLoaderPessimisticCodec(PackageAdmin packageAdmin) {
this.packageAdmin = packageAdmin;
}
@Nullable
@Override
public Object encodeClassLoader(Class<?> cls) throws IgniteException {
ClassLoader classLoader = cls.getClassLoader();
if (isIgniteClass(classLoader)) {
return ClassLoaderDesc.newIgniteClassLoaderDesc();
}
if (isFrameworkClassLoader(cls.getClassLoader())) {
return ClassLoaderDesc.newFrameworkClassLoader();
}
Bundle bundle = FrameworkUtil.getBundle(cls);
if (bundle != null) {
return ClassLoaderDesc.newBundleClassLoaderDesc(bundle);
}
return ClassLoaderDesc.newBootClassLoader();
}
@Nullable
private Bundle getBundleExt(Class<?> cls) {
// maybe handle SecurityManager
Bundle bundle = FrameworkUtil.getBundle(cls);
if (bundle == null && isFrameworkClassLoader(cls.getClassLoader())) {
bundle = FrameworkUtil.getBundle(Bundle.class);
}
return bundle;
}
@Override
public ClassLoader decodeClassLoader(String fqn, ClassLoader clsLdr, @Nullable Object encodedClsLdr)
throws IgniteException {
ClassLoaderDesc classLoaderDesc = (ClassLoaderDesc) encodedClsLdr;
switch (classLoaderDesc.classLoaderId) {
case BOOT_CLASS_LOADER_ID:
return clsLdr;
case FRAMEWORK_CLASS_LOADER_ID:
return FRAMEWOR_CLASS_LOADER;
case IGNITE_CLASS_LOADER_ID:
return ClassLoaderCodec.class.getClassLoader();
case BUNDLE_CLASS_LOADER_ID:
//strict version but we can think about an different strategy here like minor or micro version range
packageAdmin.getBundles(classLoaderDesc.bsn, classLoaderDesc.version);
}
return null;
}
static final class ClassLoaderDesc implements Externalizable {
private String version;
private String bsn;
private byte classLoaderId;
public ClassLoaderDesc(byte classLoaderId) {
this.classLoaderId = classLoaderId;
}
public ClassLoaderDesc(Bundle bundle) {
this.classLoaderId = BUNDLE_CLASS_LOADER_ID;
this.bsn = bundle.getSymbolicName();
this.version = bundle.getVersion().toString();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.write(classLoaderId);
if (classLoaderId == BUNDLE_CLASS_LOADER_ID) {
out.writeUTF(bsn);
//can be optimized
out.writeUTF(version);
}
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
classLoaderId = in.readByte();
if (classLoaderId == BUNDLE_CLASS_LOADER_ID) {
}
}
static ClassLoaderDesc newIgniteClassLoaderDesc() {
return new ClassLoaderDesc(IGNITE_CLASS_LOADER_ID);
}
public static ClassLoaderDesc newBundleClassLoaderDesc(Bundle bundle) {
return new ClassLoaderDesc(bundle);
}
public static ClassLoaderDesc newFrameworkClassLoader() {
return new ClassLoaderDesc(FRAMEWORK_CLASS_LOADER_ID);
}
public static ClassLoaderDesc newBootClassLoader() {
return new ClassLoaderDesc(BOOT_CLASS_LOADER_ID);
}
}
} |