in tapestry-core/src/main/java/org/apache/tapestry5/services/pageload/PageClassLoaderContextManagerImpl.java [342:453]
private PageClassLoaderContext merge(
Set<PageClassLoaderContext> contextDependencies,
Function<ClassLoader, PlasticProxyFactory> plasticProxyFactoryProvider,
PageClassLoaderContext root, Set<String> classesToInvalidate)
{
NESTED_MERGE_COUNT.set(NESTED_MERGE_COUNT.get() + 1);
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Nested merge count going up to {}", NESTED_MERGE_COUNT.get());
String classes;
StringBuilder builder = new StringBuilder();
builder.append("Merging the following page classloader contexts into one:\n");
for (PageClassLoaderContext context : contextDependencies)
{
classes = context.getClassNames().stream()
.map(this::getContextName)
.sorted()
.collect(Collectors.joining(", "));
builder.append(String.format("\t%s (parent %s) (%s)\n", context.getName(), context.getParent().getName(), classes));
}
LOGGER.debug(builder.toString().trim());
}
Set<PageClassLoaderContext> allContextsIncludingDescendents = new HashSet<>();
for (PageClassLoaderContext context : contextDependencies)
{
allContextsIncludingDescendents.add(context);
allContextsIncludingDescendents.addAll(context.getDescendents());
}
PageClassLoaderContext merged;
// Collect the classes in these dependencies, then invalidate the contexts
Set<PageClassLoaderContext> furtherDependencies = new HashSet<>();
Set<String> classNames = new HashSet<>();
for (PageClassLoaderContext context : contextDependencies)
{
if (!context.isRoot())
{
classNames.addAll(context.getClassNames());
}
final PageClassLoaderContext parent = context.getParent();
// We don't want the merged context to have a further dependency on
// the root context (it's not mergeable) nor on itself.
if (!parent.isRoot() &&
!allContextsIncludingDescendents.contains(parent))
{
furtherDependencies.add(parent);
}
}
final List<PageClassLoaderContext> contextsToInvalidate = contextDependencies.stream()
.filter(c -> !c.isRoot())
.collect(Collectors.toList());
if (!contextsToInvalidate.isEmpty())
{
classesToInvalidate.addAll(invalidate(contextsToInvalidate.toArray(new PageClassLoaderContext[contextsToInvalidate.size()])));
}
PageClassLoaderContext parent;
// No context dependencies, so parent is going to be the root one
if (furtherDependencies.size() == 0)
{
parent = root;
}
else
{
// Single shared context dependency, so it's our parent
if (furtherDependencies.size() == 1)
{
parent = furtherDependencies.iterator().next();
}
// No single context dependency, so we'll need to recursively merge it
// so we can have a single parent.
else
{
parent = merge(furtherDependencies, plasticProxyFactoryProvider, root, classesToInvalidate);
LOGGER.debug("New context: {}", parent);
}
}
merged = new PageClassLoaderContext(
"merged " + MERGED_COUNTER.getAndIncrement(),
parent,
classNames,
plasticProxyFactoryProvider.apply(parent.getClassLoader()),
this::get);
parent.addChild(merged);
// for (String className : classNames)
// {
// loadClass(className, merged);
// }
NESTED_MERGE_COUNT.set(NESTED_MERGE_COUNT.get() - 1);
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Nested merge count going down to {}", NESTED_MERGE_COUNT.get());
}
return merged;
}