View Javadoc
1   package com.atlassian.plugin.refimpl;
2   
3   import com.atlassian.beehive.ClusterLockService;
4   import com.atlassian.beehive.SimpleClusterLockService;
5   import com.atlassian.event.api.EventPublisher;
6   import com.atlassian.healthcheck.spi.HealthCheckWhitelist;
7   import com.atlassian.healthcheck.spi.impl.ClasspathFileHealthCheckWhitelist;
8   import com.atlassian.plugin.Application;
9   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
10  import com.atlassian.plugin.ModuleDescriptorFactory;
11  import com.atlassian.plugin.PluginAccessor;
12  import com.atlassian.plugin.PluginController;
13  import com.atlassian.plugin.PluginParseException;
14  import com.atlassian.plugin.SplitStartupPluginSystemLifecycle;
15  import com.atlassian.plugin.event.PluginEventManager;
16  import com.atlassian.plugin.eventlistener.descriptors.EventListenerModuleDescriptor;
17  import com.atlassian.plugin.hostcontainer.HostContainer;
18  import com.atlassian.plugin.hostcontainer.SimpleConstructorHostContainer;
19  import com.atlassian.plugin.main.AtlassianPlugins;
20  import com.atlassian.plugin.main.PluginsConfiguration;
21  import com.atlassian.plugin.main.PluginsConfigurationBuilder;
22  import com.atlassian.plugin.metadata.DefaultPluginMetadataManager;
23  import com.atlassian.plugin.metadata.PluginMetadataManager;
24  import com.atlassian.plugin.module.ClassPrefixModuleFactory;
25  import com.atlassian.plugin.module.ModuleFactory;
26  import com.atlassian.plugin.module.PrefixDelegatingModuleFactory;
27  import com.atlassian.plugin.module.PrefixModuleFactory;
28  import com.atlassian.plugin.osgi.container.OsgiContainerManager;
29  import com.atlassian.plugin.osgi.container.impl.DefaultPackageScannerConfiguration;
30  import com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory;
31  import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
32  import com.atlassian.plugin.osgi.hostcomponents.HostComponentProvider;
33  import com.atlassian.plugin.osgi.module.BeanPrefixModuleFactory;
34  import com.atlassian.plugin.refimpl.cache.VCacheFactoryBean;
35  import com.atlassian.plugin.refimpl.db.ConnectionProviderImpl;
36  import com.atlassian.plugin.refimpl.saldeps.CookieBasedScopeManager;
37  import com.atlassian.plugin.refimpl.saldeps.CoreRefimplI18nResolver;
38  import com.atlassian.plugin.refimpl.saldeps.CoreRefimplLocaleResolver;
39  import com.atlassian.plugin.refimpl.servlet.SimpleContentTypeResolver;
40  import com.atlassian.plugin.refimpl.servlet.SimpleServletContextFactory;
41  import com.atlassian.plugin.refimpl.tenant.RefappLandlordRequests;
42  import com.atlassian.plugin.refimpl.tenant.RefappTenancyManager;
43  import com.atlassian.plugin.refimpl.tenant.RefappTenantRegistry;
44  import com.atlassian.plugin.refimpl.webresource.RefAppResourceBatchingConfiguration;
45  import com.atlassian.plugin.refimpl.webresource.SimpleWebResourceIntegration;
46  import com.atlassian.plugin.schema.descriptor.DescribedModuleDescriptorFactory;
47  import com.atlassian.plugin.schema.impl.DefaultDescribedModuleDescriptorFactory;
48  import com.atlassian.plugin.servlet.DefaultServletModuleManager;
49  import com.atlassian.plugin.servlet.DownloadStrategy;
50  import com.atlassian.plugin.servlet.ServletContextFactory;
51  import com.atlassian.plugin.servlet.ServletModuleManager;
52  import com.atlassian.plugin.servlet.descriptors.ServletContextListenerModuleDescriptor;
53  import com.atlassian.plugin.servlet.descriptors.ServletContextParamModuleDescriptor;
54  import com.atlassian.plugin.servlet.descriptors.ServletFilterModuleDescriptor;
55  import com.atlassian.plugin.servlet.descriptors.ServletModuleDescriptor;
56  import com.atlassian.plugin.util.Assertions;
57  import com.atlassian.plugin.webresource.PluginResourceLocator;
58  import com.atlassian.plugin.webresource.PluginResourceLocatorImpl;
59  import com.atlassian.plugin.webresource.ResourceBatchingConfiguration;
60  import com.atlassian.plugin.webresource.WebResourceIntegration;
61  import com.atlassian.plugin.webresource.WebResourceManager;
62  import com.atlassian.plugin.webresource.WebResourceManagerImpl;
63  import com.atlassian.plugin.webresource.WebResourceModuleDescriptor;
64  import com.atlassian.plugin.webresource.WebResourceUrlProvider;
65  import com.atlassian.plugin.webresource.WebResourceUrlProviderImpl;
66  import com.atlassian.plugin.webresource.assembler.DefaultPageBuilderService;
67  import com.atlassian.plugin.webresource.assembler.DefaultWebResourceAssemblerFactory;
68  import com.atlassian.plugin.webresource.prebake.PrebakeWebResourceAssemblerFactory;
69  import com.atlassian.plugin.webresource.servlet.PluginResourceDownload;
70  import com.atlassian.plugin.webresource.transformer.StaticTransformersSupplier;
71  import com.atlassian.plugin.webresource.transformer.UrlReadingWebResourceTransformerModuleDescriptor;
72  import com.atlassian.plugin.webresource.transformer.WebResourceTransformerModuleDescriptor;
73  import com.atlassian.plugins.landlord.spi.LandlordRequests;
74  import com.atlassian.refapp.api.ConnectionProvider;
75  import com.atlassian.tenancy.api.TenantAccessor;
76  import com.atlassian.tenancy.api.TenantContext;
77  import com.atlassian.vcache.VCacheFactory;
78  import com.atlassian.webresource.api.assembler.PageBuilderService;
79  import com.atlassian.webresource.api.assembler.WebResourceAssemblerFactory;
80  import com.google.common.collect.ImmutableSet;
81  import com.google.common.collect.Maps;
82  import com.google.common.util.concurrent.FutureCallback;
83  import com.google.common.util.concurrent.Futures;
84  import com.google.common.util.concurrent.ListenableFuture;
85  import com.google.common.util.concurrent.SettableFuture;
86  import org.apache.commons.io.FileUtils;
87  import org.apache.commons.io.IOUtils;
88  import org.apache.commons.lang.StringUtils;
89  
90  import javax.servlet.ServletContext;
91  import java.io.File;
92  import java.io.IOException;
93  import java.io.InputStream;
94  import java.net.MalformedURLException;
95  import java.net.URL;
96  import java.util.ArrayList;
97  import java.util.HashMap;
98  import java.util.List;
99  import java.util.Map;
100 import java.util.Properties;
101 
102 /**
103  * A simple class that behaves like Spring's ContainerManager class.
104  */
105 public class ContainerManager {
106     /**
107      * Object accessed via the servletContext attributes
108      */
109     public static final String TENANTACCESSOR = "tenantAccessor";
110 
111     /**
112      * System property key for overriding package export versions.
113      */
114     private static final String PACKAGE_VERSION_EXPORT_OVERRIDES = "refapp.packageExport.overrides";
115 
116     /**
117      * The directory containing all bundled plugins.
118      */
119     private static final String BUNDLED_PLUGINS_DIR = "/WEB-INF/atlassian-bundled-plugins";
120 
121     private final ServletModuleManager servletModuleManager;
122     private final SimpleWebResourceIntegration webResourceIntegration;
123     private final OsgiContainerManager osgiContainerManager;
124     private final PluginAccessor pluginAccessor;
125     private final HostComponentProvider hostComponentProvider;
126     private final DefaultModuleDescriptorFactory moduleDescriptorFactory;
127     private final Map<Class<?>, Object> publicContainer;
128     private final AtlassianPlugins plugins;
129     private final SplitStartupPluginSystemLifecycle pluginLifecycle;
130     private final RefappTenantRegistry tenantAccessor;
131     private final RefappLandlordRequests landlordImpl;
132     private final RefappTenancyManager tenancyManager;
133     private final ClusterLockService clusterLockService;
134     private final ConnectionProviderImpl connectionProvider;
135 
136     private final PluginPhaseTriggers triggers = new PluginPhaseTriggers();
137 
138     private final HostContainer hostContainer;
139     private static ContainerManager instance;
140     private final List<DownloadStrategy> downloadStrategies;
141     private final DefaultPageBuilderService pageBuilderService;
142 
143     public ContainerManager(final ServletContext servletContext) {
144         instance = this;
145         try {
146             Class factoryFinder = Class.forName("javax.xml.transform.FactoryFinder");
147         } catch (ClassNotFoundException e) {
148             throw new RuntimeException(e);
149         }
150         // Delegating host container since the real one requires the created object map, which won't be available until later
151         final HostContainer delegatingHostContainer = new HostContainer() {
152             public <T> T create(final Class<T> moduleClass) throws IllegalArgumentException {
153                 return hostContainer.create(moduleClass);
154             }
155         };
156 
157         try {
158             connectionProvider = new ConnectionProviderImpl();
159         } catch (Exception e) {
160             // we don't want to start the rest of the container without a valid database available
161             throw new RuntimeException(e);
162         }
163 
164         moduleDescriptorFactory = new DefaultDescribedModuleDescriptorFactory(delegatingHostContainer);
165 
166         moduleDescriptorFactory.addModuleDescriptor("servlet", ServletModuleDescriptor.class);
167         moduleDescriptorFactory.addModuleDescriptor("servlet-filter", ServletFilterModuleDescriptor.class);
168         moduleDescriptorFactory.addModuleDescriptor("servlet-context-param", ServletContextParamModuleDescriptor.class);
169         moduleDescriptorFactory.addModuleDescriptor("servlet-context-listener", ServletContextListenerModuleDescriptor.class);
170         moduleDescriptorFactory.addModuleDescriptor("web-resource", WebResourceModuleDescriptor.class);
171         moduleDescriptorFactory.addModuleDescriptor("web-resource-transformer", WebResourceTransformerModuleDescriptor.class);
172         moduleDescriptorFactory.addModuleDescriptor("url-reading-web-resource-transformer", UrlReadingWebResourceTransformerModuleDescriptor.class);
173         moduleDescriptorFactory.addModuleDescriptor("listener", EventListenerModuleDescriptor.class);
174 
175         final DefaultPackageScannerConfiguration scannerConfig = new DefaultPackageScannerConfiguration(determineVersion());
176         scannerConfig.setServletContext(servletContext);
177 
178         final List<String> packageIncludes = new ArrayList<String>(scannerConfig.getPackageIncludes());
179         packageIncludes.add("org.bouncycastle*");
180         packageIncludes.add("org.dom4j*");
181         packageIncludes.add("javax.servlet*");
182         packageIncludes.add("com.google.common.*");
183         packageIncludes.add("com.atlassian.sal*");
184         packageIncludes.add("com.opensymphony.module.sitemesh*");
185         packageIncludes.add("org.apache.commons.logging*");
186         scannerConfig.setPackageIncludes(packageIncludes);
187 
188         final List<String> packageExcludes = new ArrayList<String>(scannerConfig.getPackageExcludes());
189         packageExcludes.add("com.atlassian.healthcheck.spi.impl");
190         scannerConfig.setPackageExcludes(packageExcludes);
191 
192         final Map<String, String> packageVersions = Maps.<String, String>newHashMap();
193         packageVersions.put("com.google.common.*", SystemExportVersionUtils.getGoogleGuavaVersion());
194         // org.w3c.dom.html comes from both xercesImpl and xml-apis. To avoid package scanner non-deterministically guessing a
195         // version, we force the version here. Following JIRA's lead, we'll version the whole package to nothing.
196         packageVersions.put("org.w3c.*", "");
197         // javax.annotation is present both in WEB-INF/lib/jsr305-1.3.9.jar and tomcat's lib/annotations-api.jar, and there's also
198         // a bit in ${JAVA_HOME}/jre/lib/rt.jar. As above, we specify a blank version. In fact this version is changed to 1.0.0 by
199         // the plugin system *after* scanning, but we still wish to avoid the warning. We do just javax.annotation, and no
200         // subpackages, because there's no clash amongst the subpackages.
201         packageVersions.put("javax.annotation", "");
202         final String packageVersionExportOverrides = System.getProperty(PACKAGE_VERSION_EXPORT_OVERRIDES);
203         if (packageVersionExportOverrides != null) {
204             packageVersions.putAll(ConfigParser.parseMap(packageVersionExportOverrides));
205         }
206         scannerConfig.setPackageVersions(packageVersions);
207 
208         hostComponentProvider = new SimpleHostComponentProvider();
209 
210         File osgiCache = findAndCreateDirectory(servletContext, "osgi.cache", "/WEB-INF/osgi-cache");
211         File frameworkBundlesDir = findAndCreateDirectory(servletContext, "framework.bundles", "/WEB-INF/framework-bundles");
212         final URL bundledPluginDir = getBundledPluginDir(servletContext);
213         // When bundledPluginUrl is a directory, bundledPluginCacheDirectory is not used at all.
214         // But we have to keep it to make the validation happy.
215         final File legacyBundledPluginCacheDirectory = FileUtils.toFile(bundledPluginDir);
216 
217         final CookieBasedScopeManager scopeManager = new CookieBasedScopeManager();
218 
219         final PluginsConfiguration config = new PluginsConfigurationBuilder()
220                 .useLegacyDynamicPluginDeployer(true)
221                 .frameworkBundleDirectory(frameworkBundlesDir)
222                 .bundledPluginUrl(bundledPluginDir)
223                 .bundledPluginCacheDirectory(legacyBundledPluginCacheDirectory)
224                 .pluginDirectory(makeSureDirectoryExists(servletContext, "/WEB-INF/plugins"))
225                 .moduleDescriptorFactory(moduleDescriptorFactory)
226                 .packageScannerConfiguration(scannerConfig)
227                 .hostComponentProvider(hostComponentProvider)
228                 .osgiPersistentCache(osgiCache)
229                 .pluginStateStore(new DefaultPluginPersistentStateStore(osgiCache))
230                 .application(refapp())
231                 .scopeManager(scopeManager)
232                 .build();
233 
234         PrefixDelegatingModuleFactory moduleFactory = new PrefixDelegatingModuleFactory(ImmutableSet.<PrefixModuleFactory>of(new BeanPrefixModuleFactory()));
235         plugins = new AtlassianPlugins(config);
236 
237         final PluginEventManager pluginEventManager = plugins.getPluginEventManager();
238         osgiContainerManager = plugins.getOsgiContainerManager();
239 
240         servletModuleManager = new DefaultServletModuleManager(servletContext, pluginEventManager, scopeManager);
241         pluginAccessor = plugins.getPluginAccessor();
242 
243         pluginLifecycle = plugins.getPluginSystemLifecycle();
244 
245         webResourceIntegration = new SimpleWebResourceIntegration(
246                 servletContext,
247                 new CoreRefimplLocaleResolver(),
248                 new CoreRefimplI18nResolver(pluginAccessor, pluginEventManager),
249                 pluginEventManager,
250                 determineVersion()
251         );
252         WebResourceUrlProvider webResourceUrlProvider = new WebResourceUrlProviderImpl(webResourceIntegration);
253 
254         //use the refapp implementation to configure super batch
255         final RefAppResourceBatchingConfiguration refappBatchconfig = new RefAppResourceBatchingConfiguration();
256 
257         final ServletContextFactory simpleServletContextFactory = new SimpleServletContextFactory(servletContext);
258         final PluginResourceLocator pluginResourceLocator = new PluginResourceLocatorImpl(webResourceIntegration, simpleServletContextFactory, webResourceUrlProvider, refappBatchconfig, pluginEventManager);
259         final PluginResourceDownload pluginDownloadStrategy = new PluginResourceDownload(pluginResourceLocator, new SimpleContentTypeResolver(), "UTF-8");
260 
261         PrebakeWebResourceAssemblerFactory prebakeWebResourceAssemblerFactory = new DefaultWebResourceAssemblerFactory(pluginResourceLocator);
262 
263         pageBuilderService = new DefaultPageBuilderService(webResourceIntegration, prebakeWebResourceAssemblerFactory);
264 
265         EventPublisher eventPublisher = plugins.getEventPublisher();
266 
267         // Instant-On: landlord and tenant components
268         WebResourceManager webResourceManager = new WebResourceManagerImpl(pluginResourceLocator, webResourceIntegration, webResourceUrlProvider, refappBatchconfig);
269         tenantAccessor = new RefappTenantRegistry();
270         landlordImpl = new RefappLandlordRequests(triggers.getTenantTrigger(), tenantAccessor);
271         tenancyManager = new RefappTenancyManager(landlordImpl);
272         servletContext.setAttribute(TENANTACCESSOR, tenantAccessor);// Tenant filter needs access :-(
273 
274         // Cluster lock service, provided by the beehive module
275         clusterLockService = new SimpleClusterLockService();
276 
277         //VCache Factory instantiation
278         VCacheFactory vCacheFactory = new VCacheFactoryBean().getObject();
279 
280         publicContainer = new HashMap<Class<?>, Object>();
281         publicContainer.put(VCacheFactory.class, vCacheFactory);
282         publicContainer.put(PluginController.class, plugins.getPluginController());
283 
284         publicContainer.put(ClusterLockService.class, clusterLockService);
285         publicContainer.put(SplitStartupPluginSystemLifecycle.class, pluginLifecycle);
286         publicContainer.put(EventPublisher.class, eventPublisher);
287         publicContainer.put(TenantAccessor.class, tenantAccessor);
288         publicContainer.put(TenantContext.class, tenantAccessor);
289         publicContainer.put(LandlordRequests.class, landlordImpl);
290         publicContainer.put(ServletModuleManager.class, servletModuleManager);
291         publicContainer.put(WebResourceManager.class, webResourceManager);
292         publicContainer.put(WebResourceUrlProvider.class, webResourceUrlProvider);
293         publicContainer.put(ResourceBatchingConfiguration.class, refappBatchconfig);
294         publicContainer.put(WebResourceIntegration.class, webResourceIntegration);
295         publicContainer.put(WebResourceAssemblerFactory.class, prebakeWebResourceAssemblerFactory);
296         publicContainer.put(PrebakeWebResourceAssemblerFactory.class, prebakeWebResourceAssemblerFactory);
297         publicContainer.put(PluginResourceLocator.class, pluginResourceLocator);
298         publicContainer.put(PageBuilderService.class, pageBuilderService);
299         publicContainer.put(WebResourceUrlProvider.class, webResourceUrlProvider);
300 
301         publicContainer.put(Map.class, publicContainer);
302         publicContainer.put(ModuleFactory.class, moduleFactory);
303         publicContainer.put(PluginMetadataManager.class, new DefaultPluginMetadataManager());
304         publicContainer.put(ServletContextFactory.class, simpleServletContextFactory);
305 
306         publicContainer.put(ModuleDescriptorFactory.class, moduleDescriptorFactory);
307         publicContainer.put(ListableModuleDescriptorFactory.class, moduleDescriptorFactory);
308         publicContainer.put(DescribedModuleDescriptorFactory.class, moduleDescriptorFactory);
309         publicContainer.put(TenantAccessor.class, tenantAccessor);
310 
311         publicContainer.put(StaticTransformersSupplier.class, webResourceUrlProvider);
312 
313         publicContainer.put(ConnectionProvider.class, connectionProvider);
314 
315         publicContainer.put(HealthCheckWhitelist.class, new ClasspathFileHealthCheckWhitelist());
316 
317         hostContainer = new SimpleConstructorHostContainer(publicContainer);
318         moduleFactory.addPrefixModuleFactory(new ClassPrefixModuleFactory(hostContainer));
319 
320         tenancyManager.enableTenancy();
321         try {
322             pluginLifecycle.earlyStartup();
323             triggers.getPhase1Trigger().set(null);
324         } catch (final PluginParseException e) {
325             throw new RuntimeException(e);
326         }
327         downloadStrategies = new ArrayList<DownloadStrategy>();
328         downloadStrategies.add(pluginDownloadStrategy);
329     }
330 
331     private URL getBundledPluginDir(final ServletContext servletContext) {
332         final File bundledPluginDir = makeSureDirectoryExists(servletContext, BUNDLED_PLUGINS_DIR);
333         final URL bundledPluginUrl;
334         try {
335             bundledPluginUrl = bundledPluginDir.toURI().toURL();
336         } catch (MalformedURLException e) {
337             // This is a non-expected one as we know exactly the path should be valid.
338             throw new IllegalStateException("Can't form url to bundled plugins directory at: " + BUNDLED_PLUGINS_DIR, e);
339         }
340         return bundledPluginUrl;
341     }
342 
343     /**
344      * The following futures allow asynchronous triggering of the plugin system. The first phase can occur immediately,
345      * but the second phase must wait for the tenant to arrive and the first phase to complete. The plugin methods
346      * involved are:
347      */
348     private class PluginPhaseTriggers {
349         private SettableFuture<Void> triggerPhase1 = SettableFuture.create();
350         private SettableFuture<Void> triggerTenant = SettableFuture.create();
351         private ListenableFuture<List<Void>> phase2ready = Futures.allAsList(triggerPhase1, triggerTenant);
352 
353         public PluginPhaseTriggers() {
354             Futures.addCallback(phase2ready, new FutureCallback<List<Void>>() {
355                 @Override
356                 public void onSuccess(List<Void> results) {
357                     pluginLifecycle.lateStartup();
358                 }
359 
360                 @Override
361                 public void onFailure(Throwable throwable) {
362                 }
363             });
364         }
365 
366         public SettableFuture<Void> getPhase1Trigger() {
367             return triggerPhase1;
368         }
369 
370         public SettableFuture<Void> getTenantTrigger() {
371             return triggerTenant;
372         }
373     }
374 
375     private Application refapp() {
376         return new Application() {
377             @Override
378             public String getKey() {
379                 return "refapp";
380             }
381 
382             @Override
383             public String getVersion() {
384                 return "1.0";
385             }
386 
387             @Override
388             public String getBuildNumber() {
389                 return "123";
390             }
391         };
392     }
393 
394     private File findAndCreateDirectory(ServletContext servletContext, String sysPropName, String defaultPath) {
395         File dir;
396         if (System.getProperty(sysPropName) != null) {
397             dir = makeSureDirectoryExists(System.getProperty(sysPropName));
398         } else {
399             dir = makeSureDirectoryExists(servletContext, defaultPath);
400         }
401         return dir;
402     }
403 
404     private String determineVersion() {
405         InputStream in = null;
406         final Properties props = new Properties();
407         try {
408             in = getClass().getClassLoader().getResourceAsStream("META-INF/maven/com.atlassian.plugins/atlassian-plugins-core/pom.properties");
409             if (in != null) {
410                 props.load(in);
411                 return props.getProperty("version");
412             }
413         } catch (final IOException e) {
414             e.printStackTrace();
415             return null;
416         } finally {
417             IOUtils.closeQuietly(in);
418         }
419         return null;
420     }
421 
422     private File makeSureDirectoryExists(final ServletContext servletContext, final String relativePath) {
423         return makeSureDirectoryExists(servletContext.getRealPath(relativePath));
424     }
425 
426     private File makeSureDirectoryExists(final String path) {
427         final File dir = new File(path);
428         if (!dir.exists() && !dir.mkdirs()) {
429             throw new RuntimeException("Could not create directory <" + dir + ">");
430         }
431         return dir;
432     }
433 
434     public static synchronized void setInstance(final ContainerManager mgr) {
435         instance = mgr;
436     }
437 
438     public static synchronized ContainerManager getInstance() {
439         return instance;
440     }
441 
442     public ServletModuleManager getServletModuleManager() {
443         return servletModuleManager;
444     }
445 
446     public OsgiContainerManager getOsgiContainerManager() {
447         return osgiContainerManager;
448     }
449 
450     public PluginAccessor getPluginAccessor() {
451         return pluginAccessor;
452     }
453 
454     public HostComponentProvider getHostComponentProvider() {
455         return hostComponentProvider;
456     }
457 
458     public ModuleDescriptorFactory getModuleDescriptorFactory() {
459         return moduleDescriptorFactory;
460     }
461 
462     public List<DownloadStrategy> getDownloadStrategies() {
463         return downloadStrategies;
464     }
465 
466     public PageBuilderService getPageBuilderService() {
467         return pageBuilderService;
468     }
469 
470     public WebResourceIntegration getWebResourceIntegration() {
471         return webResourceIntegration;
472     }
473 
474     void shutdown() {
475         plugins.stop();
476         connectionProvider.terminate();
477     }
478 
479     private class SimpleHostComponentProvider implements HostComponentProvider {
480         public void provide(final ComponentRegistrar componentRegistrar) {
481             Assertions.notNull("publicContainer", publicContainer);
482             for (final Map.Entry<Class<?>, Object> entry : publicContainer.entrySet()) {
483                 final String name = StringUtils.uncapitalize(entry.getKey().getSimpleName());
484                 componentRegistrar.register(entry.getKey()).forInstance(entry.getValue()).withName(name);
485             }
486 
487         }
488     }
489 }