Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
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() {}
        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);
        }
    }
}

Disclaimer: this implementation is not functional and not optimized is purpose it to show how it can be done. Here we are using the PackageAdmin service which is deprecated but really simple to demonstrate the purpose.