in tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassLoaderContextManagerImpl.java [239:353]
private PageClassLoaderContext processUsingDependencies(
String className,
PageClassLoaderContext root,
Supplier<PageClassLoaderContext> unknownContextProvider,
Function<ClassLoader, PlasticProxyFactory> plasticProxyFactoryProvider,
Set<String> classesToInvalidate,
Set<String> alreadyProcessed,
boolean processCircularDependencies)
{
PageClassLoaderContext context = root.findByClassName(className);
if (context == null)
{
LOGGER.debug("Processing class {}", className);
alreadyProcessed.add(className);
// Sorting dependencies by type/alphabetically so we have consistent
// context trees between runs of the same webapp
List<String> allNonPageDependencies = new ArrayList<>(
componentDependencyRegistry.getAllNonPageDependencies(className));
Collections.sort(allNonPageDependencies, ClassNameComparator.INSTANCE);
List<String> dependencies = new ArrayList<>(getDependenciesWithoutPages(className));
Collections.sort(dependencies, ClassNameComparator.INSTANCE);
// Process dependencies depth-first
do
{
// Very unlikely to have infinite loops, but lets
// avoid them anyway.
int passes = 0;
int contextsCreatedInThisPass = -1;
while (contextsCreatedInThisPass < CONTEXTS_CREATED.get().get() && passes < 1000)
{
contextsCreatedInThisPass = CONTEXTS_CREATED.get().get();
for (String dependency : allNonPageDependencies)
{
// Avoid infinite recursion loops
if (!alreadyProcessed.contains(dependency)
|| root.findByClassName(dependency) == null)
{
processUsingDependencies(dependency, root, unknownContextProvider,
plasticProxyFactoryProvider, classesToInvalidate, alreadyProcessed, false);
}
}
}
}
while (!allNeededContextsAvailable(allNonPageDependencies));
// Collect context dependencies
Set<PageClassLoaderContext> contextDependencies = new HashSet<>();
for (String dependency : allNonPageDependencies)
{
PageClassLoaderContext dependencyContext = root.findByClassName(dependency);
// Avoid infinite recursion loops
if (multipleClassLoaders || !alreadyProcessed.contains(dependency))
{
if (dependencyContext == null)
{
dependencyContext = processUsingDependencies(dependency, root, unknownContextProvider,
plasticProxyFactoryProvider, classesToInvalidate, alreadyProcessed);
}
if (!dependencyContext.isRoot())
{
contextDependencies.add(dependencyContext);
}
}
}
if (contextDependencies.size() == 0)
{
context = new PageClassLoaderContext(
getContextName(className),
root,
Collections.singleton(className),
plasticProxyFactoryProvider.apply(root.getClassLoader()),
this::get);
CONTEXTS_CREATED.get().incrementAndGet();
}
else
{
PageClassLoaderContext parentContext;
if (contextDependencies.size() == 1)
{
parentContext = contextDependencies.iterator().next();
}
else
{
parentContext = merge(contextDependencies, plasticProxyFactoryProvider, root, classesToInvalidate);
}
context = new PageClassLoaderContext(
getContextName(className),
parentContext,
Collections.singleton(className),
plasticProxyFactoryProvider.apply(parentContext.getClassLoader()),
this::get);
CONTEXTS_CREATED.get().incrementAndGet();
}
LOGGER.debug("New context: {}", context);
}
context.addClass(className);
context.getParent().addChild(context);
return context;
}