[
https://issues.apache.org/jira/browse/BROOKLYN-351?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15522913#comment-15522913
]
Aled Sage commented on BROOKLYN-351:
------------------------------------
I see two possible solutions:
1. Remove the store from {{JcloudsLocationResolver}}, to always query jclouds.
2. Make the store more sophisticated: just store the
{{org.jclouds.providers.Providers.fromServiceLoader}}, and delegate each time
to {{ProviderRegistry.fromRegistry()}} (because that is dynamically updated
when bundles are added/removed).
For (1), the potential downside is a performance hit:
{{Providers.withId(String)}} will call
{{ServiceLoader.load(ProviderMetadata.class)}} each time, which will scan the
current thread's context class loader.
Doing a quick test in {{brooklyn-server/locations/jclouds}} (so loading 19
providers and 19 APIs from jclouds-allcompute and jclouds-allblobstore),
calling it sequentially and repeatedly (from threads in a thread pool) it took
306ms the first time, 23ms the second time, and then decreased to about 6ms
after approx 100 calls.
Unfortunately, {{isProvider()}} and {{isApi()}} are called by
{{JcloudsLocationResolver.accepts()}} so is called a fair amount. I'm not sure
exactly, but I presume it's called when parsing catalog items at startup,
adding new catalog items, and when parsing any locations defined in
brooklyn.properties. Hopefully that's mostly just a hit at startup.
Given that (2) may not be worth the effort, I suggest we go with the simpler
code in (1). If it does impact performance (particularly if it's called when
polling the REST api for the list of catalog locations etc), then we'd need to
revisit.
If we ever did want to retrieve and store the {{ServiceLoader}} results, we
could add code like that below (untested):
{noformat}
public class JcloudsProviderAndApiLoader {
private enum LazyServiceLoader {
INSTANCE;
public final Map<String,ProviderMetadata> providers;
public final Map<String,ApiMetadata> apis;
LazyServiceLoader() {
Map<String,ProviderMetadata> providersTmp = Maps.newLinkedHashMap();
for (ProviderMetadata p: Providers.fromServiceLoader()) {
providersTmp.put(p.getId(), p);
}
providers = ImmutableMap.copyOf(providersTmp);
// Unfortunately Apis.fromServiceLoader() is private
Map<String,ApiMetadata> apisTmp = Maps.newLinkedHashMap();
ServiceLoader.load(ApiMetadata.class);
for (ApiMetadata p: ServiceLoader.load(ApiMetadata.class)) {
apisTmp.put(p.getId(), p);
}
apis = ImmutableMap.copyOf(apisTmp);
}
}
public boolean isProvider(String id) {
return getProvider(id).isPresent();
}
public boolean isApi(String id) {
return getApi(id).isPresent();
}
public Optional<ProviderMetadata> getProvider(String id) {
if (LazyServiceLoader.INSTANCE.providers.containsKey(id)) {
return Optional.of(LazyServiceLoader.INSTANCE.providers.get(id));
}
return Iterables.tryFind(ProviderRegistry.fromRegistry(),
ProviderPredicates.id(id));
}
public Optional<ApiMetadata> getApi(String id) {
if (LazyServiceLoader.INSTANCE.apis.containsKey(id)) {
return Optional.of(LazyServiceLoader.INSTANCE.apis.get(id));
}
return Iterables.tryFind(ApiRegistry.fromRegistry(),
ApiPredicates.id(id));
}
}
{noformat}
> extra jclouds providers not found (in karaf)
> --------------------------------------------
>
> Key: BROOKLYN-351
> URL: https://issues.apache.org/jira/browse/BROOKLYN-351
> Project: Brooklyn
> Issue Type: Bug
> Reporter: Aled Sage
>
> When using a downstream build of Brooklyn 0.10.0-SNAPSHOT (with karaf), I
> added a couple of extra jclouds labs providers/apis via the feature.xml.
> However, when I tried to use it with the blueprint below, I got the error
> shown:
> {noformat}
> location: jclouds:azurecompute
> services:
> - type: org.apache.brooklyn.entity.stock.BasicApplication
> 2016-09-26 12:10:12,346 DEBUG 115 o.a.b.c.t.AbstractTypePlanTransformer
> [p1212877220-1463] Could not instantiate BasicRegisteredType[null;null]
> (rethrowing): Illegal parameter for 'location' (jclouds:azurecompute); not
> resolvable: NoSuchElementException: Cloud provider/
> API type azurecompute is not supported by jclouds
> {noformat}
> Looking in {{org.jclouds.providers.Providers.withId("azurecompute")}},
> jclouds does know about azurecompute.
> The problem is that the providers/apis list are retrieved and stored in
> {{JcloudsLocationResolver.PROVIDERS}} and {{JcloudsLocationResolver.APIS}}
> (during static init). At that point, the azurecompute bundle has not been
> activated, so {{org.jclouds.osgi.ProviderRegistry}} had not yet had it added
> by {{org.jclouds.osgi.MetadataBundleListener}}.
> Below is a stacktrace of where this happens:
> {noformat}
> Daemon Thread [FelixStartLevel] (Suspended (breakpoint at line 82 in
> Providers))
> owns: AtomicBoolean (id=1573)
> Providers.all() line: 82
> JcloudsLocationResolver.getProvidersMap() line: 61
> JcloudsLocationResolver.<clinit>() line: 56
> NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line:
> not available [native method]
> NativeConstructorAccessorImpl.newInstance(Object[]) line: 57
> DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45
> Constructor<T>.newInstance(Object...) line: 526
> ReflectionUtils.newInstance(AccessControlContext, Constructor,
> Object...) line: 331
> BeanRecipe.newInstance(Constructor, Object...) line: 984
> BeanRecipe.getInstanceFromType(List<Object>, List<ReifiedType>) line:
> 349
> BeanRecipe.getInstance() line: 282
> BeanRecipe.internalCreate2() line: 830
> BeanRecipe.internalCreate() line: 811
> BeanRecipe(AbstractRecipe).create() line: 106
> RefRecipe.internalCreate() line: 62
> RefRecipe(AbstractRecipe).create() line: 106
> ServiceRecipe.createService() line: 285
> ServiceRecipe.internalGetService(Bundle, ServiceRegistration) line: 252
> ServiceRecipe.internalCreate() line: 149
> AbstractRecipe$1.call() line: 79
> FutureTask<V>.run() line: 262
> ServiceRecipe(AbstractRecipe).create() line: 88
> BlueprintRepository.createInstances(Collection<String>) line: 255
> BlueprintRepository.createAll(Collection<String>) line: 186
> BlueprintContainerImpl.instantiateEagerComponents() line: 712
> BlueprintContainerImpl.doRun() line: 399
> BlueprintContainerImpl.run() line: 273
> BlueprintExtender.createContainer(Bundle, List<Object>) line: 294
> BlueprintExtender.createContainer(Bundle) line: 263
> BlueprintExtender.modifiedBundle(Bundle, BundleEvent, Object) line: 253
> BundleHookBundleTracker$Tracked.customizerModified(Bundle, BundleEvent,
> T) line: 500
> BundleHookBundleTracker$Tracked.customizerModified(Object, Object,
> Object) line: 433
>
> BundleHookBundleTracker$Tracked(BundleHookBundleTracker$AbstractTracked<S,T,R>).track(S,
> R) line: 725
> BundleHookBundleTracker$Tracked.bundleChanged(BundleEvent) line: 463
> BundleHookBundleTracker$BundleEventHook.event(BundleEvent, Collection)
> line: 422
> SecureAction.invokeBundleEventHook(EventHook, BundleEvent,
> Collection<BundleContext>) line: 1179
> EventDispatcher.createWhitelistFromHooks(EventObject, Framework,
> Map<BundleContext,List<ListenerInfo>>, Map<BundleContext,List<ListenerInfo>>,
> Class<T>) line: 731
> EventDispatcher.fireBundleEvent(BundleEvent, Framework) line: 486
> Felix.fireBundleEvent(int, Bundle) line: 4541
> Felix.startBundle(BundleImpl, int) line: 2172
> Felix.setActiveStartLevel(int, FrameworkListener[]) line: 1371
> FrameworkStartLevelImpl.run() line: 308
> Thread.run() line: 745
> {noformat}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)