Musson Industrial's Embr-Periscope Module

I'm guessing it's a classloader thing; only the gateway enforces classloader separation for modules. We probably never thought about/tested third party modules trying to use our schemas.

You might be able to, in some semi-hacky way, set the thread context classloader to Perspective's, but I'm not actually sure where you would do that and where you might want to undo it.

1 Like

:man_mage:

More testing required, but this seems to make the gateway happy (no more errors in the logs).

    override fun startup(activationState: LicenseState) {
        ...

        logger.debug("Registering components...")
        val originalClassLoader = Thread.currentThread().contextClassLoader
        Thread.currentThread().contextClassLoader = context.perspectiveContext.javaClass.classLoader

        ...
        componentRegistry.registerComponent(...)
        modelDelegateRegistry.register(...)
        ...

        Thread.currentThread().contextClassLoader = originalClassLoader
    }

Edit: The current hack. This has the benefit of also resolving my own reusable schemas.

class DelegatedClassLoader(parent: ClassLoader, private vararg val delegates: ClassLoader) :
    ClassLoader(parent) {

    override fun findClass(name: String): Class<*> {
        for (delegate in delegates) {
            try {
                return delegate.loadClass(name)
            } catch (_: ClassNotFoundException) {}
        }
        throw ClassNotFoundException(name)
    }

    override fun findResource(name: String): URL? =
        delegates.firstNotNullOfOrNull { it.getResource(name) }

    override fun findResources(name: String): Enumeration<URL> =
        Collections.enumeration(delegates.flatMap { it.getResources(name).toList() })
}

fun withContextClassLoaders(vararg delegates: ClassLoader, block: () -> Unit) {
    val originalContextClassLoader = Thread.currentThread().contextClassLoader
    Thread.currentThread().contextClassLoader =
        DelegatedClassLoader(originalContextClassLoader, *delegates)

    block()

    Thread.currentThread().contextClassLoader = originalContextClassLoader
}
    // GatewayHook
    override fun startup(activationState: LicenseState) {
        ...

        logger.debug("Registering components...")
        withContextClassLoaders(
            this.javaClass.classLoader,
            context.perspectiveContext.javaClass.classLoader,
        ) {
            componentRegistry.registerComponent(...)
            modelDelegateRegistry.register(...)
        }

        ...
    }

This fix is now included in 0.7.2.

2 Likes

Hey @bmusson, annoying js question again :grimacing:

Toastify: how would I be able to put words on new lines in the content? Usually I have to set the css white-space to pre*, but I have no idea where to start with this one..

Option 1: You can add classes to the toast.

system.perspective.runJavaScriptAsync('''() => {
	periscope.toast('My\\nContent\\nOn\\nDifferent\\nLines', {
		className: 'psc-MultiLineToast'
	})
}''')

Option 2: You can use inline styles.

system.perspective.runJavaScriptAsync('''() => {
	periscope.toast('My\\nContent\\nOn\\nDifferent\\nLines', {
		style: {
			whiteSpace: 'pre',
			pointerEvents: 'all'
		}
	})
}''')

Edit: If using inline styles, you have to add pointerEvents: 'all' for any interaction to work. This is because I'm using inline styles on the ToastContainer for the positioning and disabling interaction. This could be improved in a future version.

1 Like

Question regarding Portal:

Patch Changes

  • 3ea4d36: (FlexRepeaterPlus) Add instance key as an implicit parameter to the instance view.
  • 1bd2a1a: (FlexRepeaterPlus) Improve ViewModel caching.
    • Move ViewModel caching from the instance level to the component level, allowing the ViewModel reference to be retained for the lifetime of the component.
    • Previously, a ViewModel instance was only cached for the lifetime of its associated InstancePropsHandler, and not much care was taken to remember InstancePropsHandlers.This resolves a bug that would occur when simultaneously (in a single update to props.instances):
    1. Moving existing instances.
    2. Adding new instances.
    3. Changing the final size of the instances array.
  • 3b53009: (Toasts) Move pointerEvents setting from inline styles to CSS.
    • This makes it easier for users to use the style property of the toast function.
    • Users no longer need to add pointerEvents: 'all' to every inline style definition.
  • Updated dependencies [3ea4d36]
  • Updated dependencies [3b53009]
    • @embr-modules/periscope-web@0.7.3
4 Likes