Thanks to everyone for replies,
For the benefit of others stuck in this hole, using info in
http://njbartlett.name/2010/08/30/osgi-readiness-loading-classes.html and clues provided by Timothy
and others, I have been able to get a working solution.
As suggested by Neil in his blog, it is as simple as picking any class in a bundle, in this case the
com.vaadin.shared bundle and getting the class loader as shown below.
This then covers all components in that bundle.
Amazing how simple things are when you know how :-P.
Paul
public class QNEComponentFactory implements ComponentFactory {
private ClassLoader vaadinClassLoader;
public QNEComponentFactory() {
vaadinClassLoader = Label.class.getClassLoader(); <<<<<<<<<<<<<<<<could be any component in
the bundle<<<<
}
@Override
public Component createComponent(String fullyQualifiedClassName,
DesignContext context) {
Class<? extends Component> componentClass;
try {
componentClass = resolveComponentClass(fullyQualifiedClassName,
context);
} catch (DesignException e) {
// Try with an inner class.
int lastDot = fullyQualifiedClassName.lastIndexOf('.');
if (lastDot != -1) {
String qualifiedInnerClassName = fullyQualifiedClassName.substring(0,
lastDot) + "$"
+ fullyQualifiedClassName.substring(lastDot + 1);
return createComponent(qualifiedInnerClassName, context);
} else {
throw e;
}
}
assert Component.class.isAssignableFrom(componentClass) : "resolveComponentClass returned "
+ componentClass
+ " which is not a Vaadin Component class";
try {
return ReflectTools.createInstance(componentClass);
} catch (Exception e) {
throw new DesignException("Could not create component " +
fullyQualifiedClassName, e);
}
}
/**
* Resolves a component class based on the fully qualified name of the
class.
*
* @param qualifiedClassName
* the fully qualified name of the resolved class
* @param context
* the design context for which the class is resolved
* @return a component class object representing the provided class name
*/
protected Class<? extends Component> resolveComponentClass(String qualifiedClassName,
DesignContext context) {
try {
// Class<?> componentClass = Class.forName(qualifiedClassName,
true,VaadinServiceClassLoaderUtil.findDefaultClassLoader());
Class<?> componentClass = Class.forName(qualifiedClassName, true, vaadinClassLoader);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
return componentClass.asSubclass(Component.class);
} catch (ClassNotFoundException e) {
throw new DesignException("Unable to load component for design", e);
}
}
}
On 19/09/2017 1:16 AM, Timothy Ward wrote:
I would not recommend any solution which involves the use of DynamicImport-Package: *. This is
roughly equivalent to saying “I give up and want to switch off OSGi”. You lose any ability to
validate a that a set of bundles is complete, and you have no guarantee that things will work at
runtime. You also introduce ordering issues into
As BJ says the correct thing to do is to pass sufficient context for the runtime to actually use
the plugin. This means that you could:
* Provide your own ComponentFactory which returns a fully configured instance
- this is possible
with the existing API
* Pass a Class object rather than a String. This would need a minor change to
the existing user
interface
* Have OSGi clients obtain an OSGi service from the Vaadin runtime. This
service can be
specialised to each client bundle, at which point the service has
sufficient context to load
the plugin class from a String class name.
There are probably other ways to skin this particular cat, but resorting to TCCL and/or
DynamicImport-Package: * should be a very long way down the list.
Regards,
Tim Ward
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev